From 59dc591f66c20b6417aa2baa9503a154585386f9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 2 Jul 2014 14:34:08 -0400 Subject: update to jquery mobile 1.4.3 --- .../Notifications/NotificationManager.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs') diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 416b29e86..964e2cd24 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -30,13 +31,18 @@ namespace MediaBrowser.Server.Implementations.Notifications _logger = logManager.GetLogger(GetType().Name); } + private NotificationOptions GetConfiguration() + { + return _config.GetConfiguration("notifications"); + } + public Task SendNotification(NotificationRequest request, CancellationToken cancellationToken) { var notificationType = request.NotificationType; var options = string.IsNullOrWhiteSpace(notificationType) ? null : - _config.Configuration.NotificationOptions.GetOptions(notificationType); + GetConfiguration().GetOptions(notificationType); var users = GetUserIds(request, options) .Except(request.ExcludeUserIds) @@ -223,7 +229,7 @@ namespace MediaBrowser.Server.Implementations.Notifications private bool IsEnabled(INotificationService service, string notificationType) { return string.IsNullOrEmpty(notificationType) || - _config.Configuration.NotificationOptions.IsServiceEnabled(service.Name, notificationType); + GetConfiguration().IsServiceEnabled(service.Name, notificationType); } public void AddParts(IEnumerable services, IEnumerable notificationTypeFactories) @@ -248,9 +254,11 @@ namespace MediaBrowser.Server.Implementations.Notifications }).SelectMany(i => i).ToList(); + var config = GetConfiguration(); + foreach (var i in list) { - i.Enabled = _config.Configuration.NotificationOptions.IsEnabled(i.Type); + i.Enabled = config.IsEnabled(i.Type); } return list; -- cgit v1.2.3 From 7fa9b14f56eabbb06e38726879b3cddc47b8e8fb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 3 Jul 2014 22:22:57 -0400 Subject: fixes #762 - Marking unwatched doesn't update display --- MediaBrowser.Api/BrandingService.cs | 28 +++ MediaBrowser.Api/ConfigurationService.cs | 7 + MediaBrowser.Api/Images/ImageService.cs | 7 + MediaBrowser.Api/ItemRefreshService.cs | 22 ++- MediaBrowser.Api/Library/LibraryService.cs | 2 + MediaBrowser.Api/Library/SubtitleService.cs | 184 -------------------- MediaBrowser.Api/MediaBrowser.Api.csproj | 4 +- MediaBrowser.Api/NotificationsService.cs | 2 + MediaBrowser.Api/SessionsService.cs | 12 +- MediaBrowser.Api/Subtitles/SubtitleService.cs | 189 +++++++++++++++++++++ MediaBrowser.Api/SystemService.cs | 70 +++++++- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 10 +- MediaBrowser.Api/UserService.cs | 4 + .../WebSocket/LogFileWebSocketListener.cs | 149 ---------------- MediaBrowser.Common/Net/MimeTypes.cs | 4 + MediaBrowser.Controller/Dto/IDtoService.cs | 7 - MediaBrowser.Controller/Entities/BaseItem.cs | 15 ++ MediaBrowser.Controller/Entities/Folder.cs | 80 ++++++++- MediaBrowser.Controller/Entities/IHasUserData.cs | 18 +- MediaBrowser.Controller/Entities/TV/Episode.cs | 2 +- MediaBrowser.Controller/Entities/UserRootFolder.cs | 6 + MediaBrowser.Controller/Entities/UserView.cs | 2 +- .../Library/IUserDataManager.cs | 9 + MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs | 4 +- .../Providers/MetadataRefreshOptions.cs | 39 +++-- MediaBrowser.Controller/Session/ISessionManager.cs | 8 +- .../MediaBrowser.Model.Portable.csproj | 6 + .../MediaBrowser.Model.net35.csproj | 6 + MediaBrowser.Model/Branding/BrandingOptions.cs | 12 ++ .../Configuration/ServerConfiguration.cs | 3 - .../Configuration/XbmcMetadataOptions.cs | 3 + MediaBrowser.Model/Dto/UserItemDataDto.cs | 16 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 2 + .../Notifications/NotificationRequest.cs | 3 +- MediaBrowser.Model/Session/SessionInfoDto.cs | 32 +--- MediaBrowser.Model/System/LogFile.cs | 31 ++++ MediaBrowser.Providers/Manager/ImageSaver.cs | 28 ++- .../MediaInfo/FFProbeVideoInfo.cs | 4 +- .../Branding/BrandingConfigurationFactory.cs | 21 +++ .../Dto/DtoService.cs | 52 +++--- .../EntryPoints/UserDataChangeNotifier.cs | 45 +++-- .../HttpServer/HttpListenerHost.cs | 26 +-- .../HttpServer/Security/AuthorizationContext.cs | 9 +- .../Library/UserDataManager.cs | 37 ++++ .../LiveTv/LiveTvDtoService.cs | 11 +- .../LiveTv/LiveTvManager.cs | 6 +- .../Localization/Server/server.json | 17 +- .../MediaBrowser.Server.Implementations.csproj | 1 + .../Notifications/NotificationManager.cs | 5 +- .../Session/SessionManager.cs | 27 ++- .../Sorting/AirTimeComparer.cs | 33 +++- MediaBrowser.ServerApplication/ApplicationHost.cs | 2 +- .../Native/BrowserLauncher.cs | 12 -- MediaBrowser.ServerApplication/ServerNotifyIcon.cs | 15 -- MediaBrowser.WebDashboard/Api/DashboardService.cs | 3 +- .../MediaBrowser.WebDashboard.csproj | 22 +-- 56 files changed, 821 insertions(+), 553 deletions(-) create mode 100644 MediaBrowser.Api/BrandingService.cs delete mode 100644 MediaBrowser.Api/Library/SubtitleService.cs create mode 100644 MediaBrowser.Api/Subtitles/SubtitleService.cs delete mode 100644 MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs create mode 100644 MediaBrowser.Model/Branding/BrandingOptions.cs create mode 100644 MediaBrowser.Model/System/LogFile.cs create mode 100644 MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs (limited to 'MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs') diff --git a/MediaBrowser.Api/BrandingService.cs b/MediaBrowser.Api/BrandingService.cs new file mode 100644 index 000000000..4b49b411a --- /dev/null +++ b/MediaBrowser.Api/BrandingService.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Branding; +using ServiceStack; + +namespace MediaBrowser.Api +{ + [Route("/Branding/Configuration", "GET", Summary = "Gets branding configuration")] + public class GetBrandingOptions : IReturn + { + } + + public class BrandingService : BaseApiService + { + private readonly IConfigurationManager _config; + + public BrandingService(IConfigurationManager config) + { + _config = config; + } + + public object Get(GetBrandingOptions request) + { + var result = _config.GetConfiguration("branding"); + + return ToOptimizedResult(result); + } + } +} diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 39fcc50d8..291deb3b0 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Serialization; @@ -27,6 +28,7 @@ namespace MediaBrowser.Api } [Route("/System/Configuration/{Key}", "GET", Summary = "Gets a named configuration")] + [Authenticated] public class GetNamedConfiguration { [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -37,11 +39,13 @@ namespace MediaBrowser.Api /// Class UpdateConfiguration /// [Route("/System/Configuration", "POST", Summary = "Updates application configuration")] + [Authenticated] public class UpdateConfiguration : ServerConfiguration, IReturnVoid { } [Route("/System/Configuration/{Key}", "POST", Summary = "Updates named configuration")] + [Authenticated] public class UpdateNamedConfiguration : IReturnVoid, IRequiresRequestStream { [ApiMember(Name = "Key", Description = "Key", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -51,18 +55,21 @@ namespace MediaBrowser.Api } [Route("/System/Configuration/MetadataOptions/Default", "GET", Summary = "Gets a default MetadataOptions object")] + [Authenticated] public class GetDefaultMetadataOptions : IReturn { } [Route("/System/Configuration/MetadataPlugins", "GET", Summary = "Gets all available metadata plugins")] + [Authenticated] public class GetMetadataPlugins : IReturn> { } [Route("/System/Configuration/VideoImageExtraction", "POST", Summary = "Updates image extraction for all types")] + [Authenticated] public class UpdateVideoImageExtraction : IReturnVoid { public bool Enabled { get; set; } diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 4f8c348bb..deaefe019 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; @@ -26,6 +27,7 @@ namespace MediaBrowser.Api.Images /// [Route("/Items/{Id}/Images", "GET")] [Api(Description = "Gets information about an item's images")] + [Authenticated] public class GetItemImageInfos : IReturn> { /// @@ -56,6 +58,7 @@ namespace MediaBrowser.Api.Images /// [Route("/Items/{Id}/Images/{Type}/{Index}/Index", "POST")] [Api(Description = "Updates the index for an item image")] + [Authenticated] public class UpdateItemImageIndex : IReturnVoid { /// @@ -137,6 +140,7 @@ namespace MediaBrowser.Api.Images [Route("/Items/{Id}/Images/{Type}", "DELETE")] [Route("/Items/{Id}/Images/{Type}/{Index}", "DELETE")] [Api(Description = "Deletes an item image")] + [Authenticated] public class DeleteItemImage : DeleteImageRequest, IReturnVoid { /// @@ -153,6 +157,7 @@ namespace MediaBrowser.Api.Images [Route("/Users/{Id}/Images/{Type}", "DELETE")] [Route("/Users/{Id}/Images/{Type}/{Index}", "DELETE")] [Api(Description = "Deletes a user image")] + [Authenticated] public class DeleteUserImage : DeleteImageRequest, IReturnVoid { /// @@ -169,6 +174,7 @@ namespace MediaBrowser.Api.Images [Route("/Users/{Id}/Images/{Type}", "POST")] [Route("/Users/{Id}/Images/{Type}/{Index}", "POST")] [Api(Description = "Posts a user image")] + [Authenticated] public class PostUserImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid { /// @@ -191,6 +197,7 @@ namespace MediaBrowser.Api.Images [Route("/Items/{Id}/Images/{Type}", "POST")] [Route("/Items/{Id}/Images/{Type}/{Index}", "POST")] [Api(Description = "Posts an item image")] + [Authenticated] public class PostItemImage : DeleteImageRequest, IRequiresRequestStream, IReturnVoid { /// diff --git a/MediaBrowser.Api/ItemRefreshService.cs b/MediaBrowser.Api/ItemRefreshService.cs index b95e18a0d..993b69601 100644 --- a/MediaBrowser.Api/ItemRefreshService.cs +++ b/MediaBrowser.Api/ItemRefreshService.cs @@ -13,10 +13,16 @@ namespace MediaBrowser.Api { public class BaseRefreshRequest : IReturnVoid { - [ApiMember(Name = "Forced", Description = "Indicates if a normal or forced refresh should occur.", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] - public bool Forced { get; set; } + [ApiMember(Name = "MetadataRefreshMode", Description = "Specifies the metadata refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] + public MetadataRefreshMode MetadataRefreshMode { get; set; } - [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced during the refresh.", IsRequired = true, DataType = "boolean", ParameterType = "query", Verb = "POST")] + [ApiMember(Name = "ImageRefreshMode", Description = "Specifies the image refresh mode", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] + public ImageRefreshMode ImageRefreshMode { get; set; } + + [ApiMember(Name = "ReplaceAllMetadata", Description = "Determines if metadata should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] + public bool ReplaceAllMetadata { get; set; } + + [ApiMember(Name = "ReplaceAllImages", Description = "Determines if images should be replaced. Only applicable if mode is FullRefresh", IsRequired = false, DataType = "boolean", ParameterType = "query", Verb = "POST")] public bool ReplaceAllImages { get; set; } } @@ -93,7 +99,7 @@ namespace MediaBrowser.Api private async Task RefreshItem(RefreshItem request, BaseItem item) { var options = GetRefreshOptions(request); - + try { await item.RefreshMetadata(options, CancellationToken.None).ConfigureAwait(false); @@ -148,10 +154,10 @@ namespace MediaBrowser.Api { return new MetadataRefreshOptions { - MetadataRefreshMode = MetadataRefreshMode.FullRefresh, - ImageRefreshMode = ImageRefreshMode.FullRefresh, - ReplaceAllMetadata = request.Forced, - ReplaceAllImages = request.ReplaceAllImages + MetadataRefreshMode = request.MetadataRefreshMode, + ImageRefreshMode = request.ImageRefreshMode, + ReplaceAllImages = request.ReplaceAllImages, + ReplaceAllMetadata = request.ReplaceAllMetadata }; } } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 77a714755..10aa23126 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; @@ -226,6 +227,7 @@ namespace MediaBrowser.Api.Library /// /// Class LibraryService /// + [Authenticated] public class LibraryService : BaseApiService { /// diff --git a/MediaBrowser.Api/Library/SubtitleService.cs b/MediaBrowser.Api/Library/SubtitleService.cs deleted file mode 100644 index 4fc3e00c0..000000000 --- a/MediaBrowser.Api/Library/SubtitleService.cs +++ /dev/null @@ -1,184 +0,0 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Subtitles; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Providers; -using ServiceStack; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Api.Library -{ - [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")] - public class GetSubtitle - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - - [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string MediaSourceId { get; set; } - - [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")] - public int Index { get; set; } - - [ApiMember(Name = "Format", Description = "Format", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Format { get; set; } - - [ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] - public long StartPositionTicks { get; set; } - } - - [Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")] - public class DeleteSubtitle - { - /// - /// Gets or sets the id. - /// - /// The id. - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public string Id { get; set; } - - [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "DELETE")] - public int Index { get; set; } - } - - [Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")] - public class SearchRemoteSubtitles : IReturn> - { - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - - [ApiMember(Name = "Language", Description = "Language", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Language { get; set; } - } - - [Route("/Items/{Id}/RemoteSearch/Subtitles/Providers", "GET")] - public class GetSubtitleProviders : IReturn> - { - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - } - - [Route("/Items/{Id}/RemoteSearch/Subtitles/{SubtitleId}", "POST")] - public class DownloadRemoteSubtitles : IReturnVoid - { - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string Id { get; set; } - - [ApiMember(Name = "SubtitleId", Description = "SubtitleId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string SubtitleId { get; set; } - } - - [Route("/Providers/Subtitles/Subtitles/{Id}", "GET")] - public class GetRemoteSubtitles : IReturnVoid - { - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Id { get; set; } - } - - [Authenticated] - public class SubtitleService : BaseApiService - { - private readonly ILibraryManager _libraryManager; - private readonly ISubtitleManager _subtitleManager; - private readonly ISubtitleEncoder _subtitleEncoder; - - public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder) - { - _libraryManager = libraryManager; - _subtitleManager = subtitleManager; - _subtitleEncoder = subtitleEncoder; - } - - public object Get(SearchRemoteSubtitles request) - { - var video = (Video)_libraryManager.GetItemById(request.Id); - - var response = _subtitleManager.SearchSubtitles(video, request.Language, CancellationToken.None).Result; - - return ToOptimizedResult(response); - } - public object Get(GetSubtitle request) - { - if (string.IsNullOrEmpty(request.Format)) - { - var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); - - var mediaSource = item.GetMediaSources(false) - .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id)); - - var subtitleStream = mediaSource.MediaStreams - .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index); - - return ToStaticFileResult(subtitleStream.Path); - } - - var stream = GetSubtitles(request).Result; - - return ResultFactory.GetResult(stream, Common.Net.MimeTypes.GetMimeType("file." + request.Format)); - } - - private async Task GetSubtitles(GetSubtitle request) - { - return await _subtitleEncoder.GetSubtitles(request.Id, - request.MediaSourceId, - request.Index, - request.Format, - request.StartPositionTicks, - CancellationToken.None).ConfigureAwait(false); - } - - public void Delete(DeleteSubtitle request) - { - var task = _subtitleManager.DeleteSubtitles(request.Id, request.Index); - - Task.WaitAll(task); - } - - public object Get(GetSubtitleProviders request) - { - var result = _subtitleManager.GetProviders(request.Id); - - return ToOptimizedResult(result); - } - - public object Get(GetRemoteSubtitles request) - { - var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result; - - return ResultFactory.GetResult(result.Stream, Common.Net.MimeTypes.GetMimeType("file." + result.Format)); - } - - public void Post(DownloadRemoteSubtitles request) - { - var video = (Video)_libraryManager.GetItemById(request.Id); - - Task.Run(async () => - { - try - { - await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None) - .ConfigureAwait(false); - - await video.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.ErrorException("Error downloading subtitles", ex); - } - - }); - } - } -} diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index a68966b33..ca2887d19 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -65,11 +65,12 @@ Properties\SharedVersion.cs + - + @@ -139,7 +140,6 @@ - diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs index 28edb61dd..51a080106 100644 --- a/MediaBrowser.Api/NotificationsService.cs +++ b/MediaBrowser.Api/NotificationsService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Notifications; using MediaBrowser.Model.Notifications; using ServiceStack; @@ -82,6 +83,7 @@ namespace MediaBrowser.Api public string Ids { get; set; } } + [Authenticated] public class NotificationsService : BaseApiService { private readonly INotificationsRepository _notificationsRepo; diff --git a/MediaBrowser.Api/SessionsService.cs b/MediaBrowser.Api/SessionsService.cs index 00c307a18..f4651601b 100644 --- a/MediaBrowser.Api/SessionsService.cs +++ b/MediaBrowser.Api/SessionsService.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; using ServiceStack; @@ -14,6 +15,7 @@ namespace MediaBrowser.Api /// Class GetSessions /// [Route("/Sessions", "GET", Summary = "Gets a list of sessions")] + [Authenticated] public class GetSessions : IReturn> { [ApiMember(Name = "ControllableByUserId", Description = "Optional. Filter by sessions that a given user is allowed to remote control.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] @@ -27,6 +29,7 @@ namespace MediaBrowser.Api /// Class DisplayContent /// [Route("/Sessions/{Id}/Viewing", "POST", Summary = "Instructs a session to browse to an item or view")] + [Authenticated] public class DisplayContent : IReturnVoid { /// @@ -59,6 +62,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Playing", "POST", Summary = "Instructs a session to play an item")] + [Authenticated] public class Play : IReturnVoid { /// @@ -91,6 +95,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Playing/{Command}", "POST", Summary = "Issues a playstate command to a client")] + [Authenticated] public class SendPlaystateCommand : IReturnVoid { /// @@ -115,6 +120,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/System/{Command}", "POST", Summary = "Issues a system command to a client")] + [Authenticated] public class SendSystemCommand : IReturnVoid { /// @@ -133,6 +139,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Command/{Command}", "POST", Summary = "Issues a system command to a client")] + [Authenticated] public class SendGeneralCommand : IReturnVoid { /// @@ -151,6 +158,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Command", "POST", Summary = "Issues a system command to a client")] + [Authenticated] public class SendFullGeneralCommand : GeneralCommand, IReturnVoid { /// @@ -162,6 +170,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Message", "POST", Summary = "Issues a command to a client to display a message to the user")] + [Authenticated] public class SendMessageCommand : IReturnVoid { /// @@ -182,6 +191,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Users/{UserId}", "POST", Summary = "Adds an additional user to a session")] + [Authenticated] public class AddUserToSession : IReturnVoid { [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] @@ -192,6 +202,7 @@ namespace MediaBrowser.Api } [Route("/Sessions/{Id}/Users/{UserId}", "DELETE", Summary = "Removes an additional user from a session")] + [Authenticated] public class RemoveUserFromSession : IReturnVoid { [ApiMember(Name = "Id", Description = "Session Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] @@ -202,7 +213,6 @@ namespace MediaBrowser.Api } [Route("/Sessions/Capabilities", "POST", Summary = "Updates capabilities for a device")] - [Route("/Sessions/{Id}/Capabilities", "POST", Summary = "Updates capabilities for a device")] public class PostCapabilities : IReturnVoid { /// diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs new file mode 100644 index 000000000..3e692cb22 --- /dev/null +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -0,0 +1,189 @@ +using System.IO; +using System.Linq; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Subtitles; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Providers; +using ServiceStack; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Subtitles +{ + [Route("/Videos/{Id}/Subtitles/{Index}", "DELETE", Summary = "Deletes an external subtitle file")] + [Authenticated] + public class DeleteSubtitle + { + /// + /// Gets or sets the id. + /// + /// The id. + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] + public string Id { get; set; } + + [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "DELETE")] + public int Index { get; set; } + } + + [Route("/Items/{Id}/RemoteSearch/Subtitles/{Language}", "GET")] + [Authenticated] + public class SearchRemoteSubtitles : IReturn> + { + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + + [ApiMember(Name = "Language", Description = "Language", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Language { get; set; } + } + + [Route("/Items/{Id}/RemoteSearch/Subtitles/Providers", "GET")] + [Authenticated] + public class GetSubtitleProviders : IReturn> + { + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + [Route("/Items/{Id}/RemoteSearch/Subtitles/{SubtitleId}", "POST")] + [Authenticated] + public class DownloadRemoteSubtitles : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string Id { get; set; } + + [ApiMember(Name = "SubtitleId", Description = "SubtitleId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string SubtitleId { get; set; } + } + + [Route("/Providers/Subtitles/Subtitles/{Id}", "GET")] + [Authenticated] + public class GetRemoteSubtitles : IReturnVoid + { + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } + + [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")] + public class GetSubtitle + { + /// + /// Gets or sets the id. + /// + /// The id. + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + + [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string MediaSourceId { get; set; } + + [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")] + public int Index { get; set; } + + [ApiMember(Name = "Format", Description = "Format", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Format { get; set; } + + [ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public long StartPositionTicks { get; set; } + } + + public class SubtitleService : BaseApiService + { + private readonly ILibraryManager _libraryManager; + private readonly ISubtitleManager _subtitleManager; + private readonly ISubtitleEncoder _subtitleEncoder; + + public SubtitleService(ILibraryManager libraryManager, ISubtitleManager subtitleManager, ISubtitleEncoder subtitleEncoder) + { + _libraryManager = libraryManager; + _subtitleManager = subtitleManager; + _subtitleEncoder = subtitleEncoder; + } + + public object Get(GetSubtitle request) + { + if (string.IsNullOrEmpty(request.Format)) + { + var item = (Video)_libraryManager.GetItemById(new Guid(request.Id)); + + var mediaSource = item.GetMediaSources(false) + .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id)); + + var subtitleStream = mediaSource.MediaStreams + .First(i => i.Type == MediaStreamType.Subtitle && i.Index == request.Index); + + return ToStaticFileResult(subtitleStream.Path); + } + + var stream = GetSubtitles(request).Result; + + return ResultFactory.GetResult(stream, Common.Net.MimeTypes.GetMimeType("file." + request.Format)); + } + + private async Task GetSubtitles(GetSubtitle request) + { + return await _subtitleEncoder.GetSubtitles(request.Id, + request.MediaSourceId, + request.Index, + request.Format, + request.StartPositionTicks, + CancellationToken.None).ConfigureAwait(false); + } + + public object Get(SearchRemoteSubtitles request) + { + var video = (Video)_libraryManager.GetItemById(request.Id); + + var response = _subtitleManager.SearchSubtitles(video, request.Language, CancellationToken.None).Result; + + return ToOptimizedResult(response); + } + + public void Delete(DeleteSubtitle request) + { + var task = _subtitleManager.DeleteSubtitles(request.Id, request.Index); + + Task.WaitAll(task); + } + + public object Get(GetSubtitleProviders request) + { + var result = _subtitleManager.GetProviders(request.Id); + + return ToOptimizedResult(result); + } + + public object Get(GetRemoteSubtitles request) + { + var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result; + + return ResultFactory.GetResult(result.Stream, Common.Net.MimeTypes.GetMimeType("file." + result.Format)); + } + + public void Post(DownloadRemoteSubtitles request) + { + var video = (Video)_libraryManager.GetItemById(request.Id); + + Task.Run(async () => + { + try + { + await _subtitleManager.DownloadSubtitles(video, request.SubtitleId, CancellationToken.None) + .ConfigureAwait(false); + + await video.RefreshMetadata(new MetadataRefreshOptions(), CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + Logger.ErrorException("Error downloading subtitles", ex); + } + + }); + } + } +} diff --git a/MediaBrowser.Api/SystemService.cs b/MediaBrowser.Api/SystemService.cs index 2f0741434..6f2e83a79 100644 --- a/MediaBrowser.Api/SystemService.cs +++ b/MediaBrowser.Api/SystemService.cs @@ -1,6 +1,12 @@ -using MediaBrowser.Controller; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.System; using ServiceStack; +using System.Collections.Generic; +using System.IO; +using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Api @@ -18,15 +24,30 @@ namespace MediaBrowser.Api /// Class RestartApplication /// [Route("/System/Restart", "POST", Summary = "Restarts the application, if needed")] + [Authenticated] public class RestartApplication { } [Route("/System/Shutdown", "POST", Summary = "Shuts down the application")] + [Authenticated] public class ShutdownApplication { } + [Route("/System/Logs", "GET", Summary = "Gets a list of available server log files")] + [Authenticated] + public class GetServerLogs : IReturn> + { + } + + [Route("/System/Logs/Log", "GET", Summary = "Gets a log file")] + public class GetLogFile + { + [ApiMember(Name = "Name", Description = "The log file name.", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] + public string Name { get; set; } + } + /// /// Class SystemInfoService /// @@ -36,16 +57,59 @@ namespace MediaBrowser.Api /// The _app host /// private readonly IServerApplicationHost _appHost; - + private readonly IApplicationPaths _appPaths; + private readonly IFileSystem _fileSystem; /// /// Initializes a new instance of the class. /// /// The app host. /// jsonSerializer - public SystemService(IServerApplicationHost appHost) + public SystemService(IServerApplicationHost appHost, IApplicationPaths appPaths, IFileSystem fileSystem) { _appHost = appHost; + _appPaths = appPaths; + _fileSystem = fileSystem; + } + + public object Get(GetServerLogs request) + { + List files; + + try + { + files = new DirectoryInfo(_appPaths.LogDirectoryPath) + .EnumerateFiles("*", SearchOption.AllDirectories) + .Where(i => string.Equals(i.Extension, ".txt", System.StringComparison.OrdinalIgnoreCase)) + .ToList(); + } + catch (DirectoryNotFoundException) + { + files = new List(); + } + + var result = files.Select(i => new LogFile + { + DateCreated = _fileSystem.GetCreationTimeUtc(i), + DateModified = _fileSystem.GetLastWriteTimeUtc(i), + Name = i.Name, + Size = i.Length + + }).OrderByDescending(i => i.DateModified) + .ThenByDescending(i => i.DateCreated) + .ThenBy(i => i.Name) + .ToList(); + + return ToOptimizedResult(result); + } + + public object Get(GetLogFile request) + { + var file = new DirectoryInfo(_appPaths.LogDirectoryPath) + .EnumerateFiles("*", SearchOption.AllDirectories) + .First(i => string.Equals(i.Name, request.Name, System.StringComparison.OrdinalIgnoreCase)); + + return ResultFactory.GetStaticFileResult(Request, file.FullName, FileShare.ReadWrite); } /// diff --git a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs index d1767e7fd..55cdc8681 100644 --- a/MediaBrowser.Api/UserLibrary/UserLibraryService.cs +++ b/MediaBrowser.Api/UserLibrary/UserLibraryService.cs @@ -717,9 +717,7 @@ namespace MediaBrowser.Api.UserLibrary await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false); - data = _userDataRepository.GetUserData(user.Id, key); - - return _dtoService.GetUserItemDataDto(data); + return _userDataRepository.GetUserDataDto(item, user); } /// @@ -766,9 +764,7 @@ namespace MediaBrowser.Api.UserLibrary await _userDataRepository.SaveUserData(user.Id, item, data, UserDataSaveReason.UpdateUserRating, CancellationToken.None).ConfigureAwait(false); - data = _userDataRepository.GetUserData(user.Id, key); - - return _dtoService.GetUserItemDataDto(data); + return _userDataRepository.GetUserDataDto(item, user); } /// @@ -936,7 +932,7 @@ namespace MediaBrowser.Api.UserLibrary await item.MarkUnplayed(user, _userDataRepository).ConfigureAwait(false); } - return _dtoService.GetUserItemDataDto(_userDataRepository.GetUserData(user.Id, item.GetUserDataKey())); + return _userDataRepository.GetUserDataDto(item, user); } } } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 64d1fcb34..cda489c94 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -51,6 +51,7 @@ namespace MediaBrowser.Api /// Class DeleteUser /// [Route("/Users/{Id}", "DELETE", Summary = "Deletes a user")] + [Authenticated] public class DeleteUser : IReturnVoid { /// @@ -107,6 +108,7 @@ namespace MediaBrowser.Api /// Class UpdateUserPassword /// [Route("/Users/{Id}/Password", "POST", Summary = "Updates a user's password")] + [Authenticated] public class UpdateUserPassword : IReturnVoid { /// @@ -138,6 +140,7 @@ namespace MediaBrowser.Api /// Class UpdateUser /// [Route("/Users/{Id}", "POST", Summary = "Updates a user")] + [Authenticated] public class UpdateUser : UserDto, IReturnVoid { } @@ -146,6 +149,7 @@ namespace MediaBrowser.Api /// Class CreateUser /// [Route("/Users", "POST", Summary = "Creates a user")] + [Authenticated] public class CreateUser : UserDto, IReturn { } diff --git a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs b/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs deleted file mode 100644 index 46dabb042..000000000 --- a/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs +++ /dev/null @@ -1,149 +0,0 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.IO; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; - -namespace MediaBrowser.Api.WebSocket -{ - /// - /// Class ScheduledTasksWebSocketListener - /// - public class LogFileWebSocketListener : BasePeriodicWebSocketListener, LogFileWebSocketState> - { - /// - /// Gets the name. - /// - /// The name. - protected override string Name - { - get { return "LogFile"; } - } - - /// - /// The _kernel - /// - private readonly ILogManager _logManager; - private readonly IFileSystem _fileSystem; - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// The log manager. - public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem) - : base(logger) - { - _logManager = logManager; - _fileSystem = fileSystem; - _logManager.LoggerLoaded += kernel_LoggerLoaded; - } - - /// - /// Gets the data to send. - /// - /// The state. - /// IEnumerable{System.String}. - protected override async Task> GetDataToSend(LogFileWebSocketState state) - { - if (!string.Equals(_logManager.LogFilePath, state.LastLogFilePath)) - { - state.LastLogFilePath = _logManager.LogFilePath; - state.StartLine = 0; - } - - var lines = await GetLogLines(state.LastLogFilePath, state.StartLine, _fileSystem).ConfigureAwait(false); - - state.StartLine += lines.Count; - - return lines; - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected override void Dispose(bool dispose) - { - if (dispose) - { - _logManager.LoggerLoaded -= kernel_LoggerLoaded; - } - base.Dispose(dispose); - } - - /// - /// Handles the LoggerLoaded event of the kernel control. - /// - /// The source of the event. - /// The instance containing the event data. - void kernel_LoggerLoaded(object sender, EventArgs e) - { - // Reset the startline for each connection whenever the logger reloads - lock (ActiveConnections) - { - foreach (var connection in ActiveConnections) - { - connection.Item4.StartLine = 0; - } - } - } - - /// - /// Gets the log lines. - /// - /// The log file path. - /// The start line. - /// Task{IEnumerable{System.String}}. - internal static async Task> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem) - { - var lines = new List(); - - using (var fs = fileSystem.GetFileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) - { - using (var reader = new StreamReader(fs)) - { - while (!reader.EndOfStream) - { - var line = await reader.ReadLineAsync().ConfigureAwait(false); - - if (line.IndexOf("Info -", StringComparison.OrdinalIgnoreCase) != -1 || - line.IndexOf("Warn -", StringComparison.OrdinalIgnoreCase) != -1 || - line.IndexOf("Error -", StringComparison.OrdinalIgnoreCase) != -1) - { - lines.Add(line); - } - } - } - } - - if (startLine > 0) - { - lines = lines.Skip(startLine).ToList(); - } - - return lines; - } - } - - /// - /// Class LogFileWebSocketState - /// - public class LogFileWebSocketState : WebSocketListenerState - { - /// - /// Gets or sets the last log file path. - /// - /// The last log file path. - public string LastLogFilePath { get; set; } - /// - /// Gets or sets the start line. - /// - /// The start line. - public int StartLine { get; set; } - } -} diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs index 0cc4fc6b4..dcac5e7ba 100644 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ b/MediaBrowser.Common/Net/MimeTypes.cs @@ -199,6 +199,10 @@ namespace MediaBrowser.Common.Net { return "application/x-javascript"; } + if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-javascript"; + } if (ext.Equals(".woff", StringComparison.OrdinalIgnoreCase)) { diff --git a/MediaBrowser.Controller/Dto/IDtoService.cs b/MediaBrowser.Controller/Dto/IDtoService.cs index f9d7cc21a..0d0555dc0 100644 --- a/MediaBrowser.Controller/Dto/IDtoService.cs +++ b/MediaBrowser.Controller/Dto/IDtoService.cs @@ -25,13 +25,6 @@ namespace MediaBrowser.Controller.Dto /// System.String. string GetDtoId(BaseItem item); - /// - /// Gets the user item data dto. - /// - /// The data. - /// UserItemDataDto. - UserItemDataDto GetUserItemDataDto(UserItemData data); - /// /// Attaches the primary image aspect ratio. /// diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 524d7097b..042834731 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -6,6 +6,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; using MediaBrowser.Model.Logging; @@ -1571,5 +1572,19 @@ namespace MediaBrowser.Controller.Entities return path; } + + public virtual void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) + { + if (RunTimeTicks.HasValue) + { + double pct = RunTimeTicks.Value; + + if (pct > 0) + { + pct = userData.PlaybackPositionTicks / pct; + dto.PlayedPercentage = 100 * pct; + } + } + } } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 584091b13..b886cef19 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -4,6 +4,7 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MoreLinq; using System; @@ -769,6 +770,11 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. /// public virtual IEnumerable GetChildren(User user, bool includeLinkedChildren) + { + return GetChildren(user, includeLinkedChildren, false); + } + + internal IEnumerable GetChildren(User user, bool includeLinkedChildren, bool includeHidden) { if (user == null) { @@ -780,7 +786,7 @@ namespace MediaBrowser.Controller.Entities var list = new List(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false); + var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, includeHidden, false); return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; } @@ -796,9 +802,10 @@ namespace MediaBrowser.Controller.Entities /// The user. /// if set to true [include linked children]. /// The list. + /// if set to true [include hidden]. /// if set to true [recursive]. /// true if XXXX, false otherwise - private bool AddChildrenToList(User user, bool includeLinkedChildren, List list, bool recursive) + private bool AddChildrenToList(User user, bool includeLinkedChildren, List list, bool includeHidden, bool recursive) { var hasLinkedChildren = false; @@ -806,7 +813,7 @@ namespace MediaBrowser.Controller.Entities { if (child.IsVisible(user)) { - if (!child.IsHiddenFromUser(user)) + if (includeHidden || !child.IsHiddenFromUser(user)) { list.Add(child); } @@ -815,7 +822,7 @@ namespace MediaBrowser.Controller.Entities { var folder = (Folder)child; - if (folder.AddChildrenToList(user, includeLinkedChildren, list, true)) + if (folder.AddChildrenToList(user, includeLinkedChildren, list, includeHidden, true)) { hasLinkedChildren = true; } @@ -855,7 +862,7 @@ namespace MediaBrowser.Controller.Entities var list = new List(); - var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, true); + var hasLinkedChildren = AddChildrenToList(user, includeLinkedChildren, list, false, true); return hasLinkedChildren ? list.DistinctBy(i => i.Id).ToList() : list; } @@ -1069,5 +1076,68 @@ namespace MediaBrowser.Controller.Entities return GetRecursiveChildren(user).Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual) .All(i => i.IsUnplayed(user)); } + + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) + { + var recursiveItemCount = 0; + var unplayed = 0; + + double totalPercentPlayed = 0; + + IEnumerable children; + var folder = this; + + var season = folder as Season; + + if (season != null) + { + children = season.GetEpisodes(user).Where(i => i.LocationType != LocationType.Virtual); + } + else + { + children = folder.GetRecursiveChildren(user) + .Where(i => !i.IsFolder && i.LocationType != LocationType.Virtual); + } + + // Loop through each recursive child + foreach (var child in children) + { + recursiveItemCount++; + + var isUnplayed = true; + + var itemUserData = UserDataManager.GetUserData(user.Id, child.GetUserDataKey()); + + // Incrememt totalPercentPlayed + if (itemUserData != null) + { + if (itemUserData.Played) + { + totalPercentPlayed += 100; + + isUnplayed = false; + } + else if (itemUserData.PlaybackPositionTicks > 0 && child.RunTimeTicks.HasValue && child.RunTimeTicks.Value > 0) + { + double itemPercent = itemUserData.PlaybackPositionTicks; + itemPercent /= child.RunTimeTicks.Value; + totalPercentPlayed += itemPercent; + } + } + + if (isUnplayed) + { + unplayed++; + } + } + + dto.UnplayedItemCount = unplayed; + + if (recursiveItemCount > 0) + { + dto.PlayedPercentage = totalPercentPlayed / recursiveItemCount; + dto.Played = dto.PlayedPercentage.Value >= 100; + } + } } } diff --git a/MediaBrowser.Controller/Entities/IHasUserData.cs b/MediaBrowser.Controller/Entities/IHasUserData.cs index 780181a61..d576d90c4 100644 --- a/MediaBrowser.Controller/Entities/IHasUserData.cs +++ b/MediaBrowser.Controller/Entities/IHasUserData.cs @@ -1,4 +1,6 @@ - +using MediaBrowser.Model.Dto; +using System; + namespace MediaBrowser.Controller.Entities { /// @@ -6,10 +8,24 @@ namespace MediaBrowser.Controller.Entities /// public interface IHasUserData { + /// + /// Gets or sets the identifier. + /// + /// The identifier. + Guid Id { get; set; } + /// /// Gets the user data key. /// /// System.String. string GetUserDataKey(); + + /// + /// Fills the user data dto values. + /// + /// The dto. + /// The user data. + /// The user. + void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user); } } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index b9630a66f..847183fd0 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Entities.TV { get { - return FindParent(); + return Season; } } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index e5a8135c2..6404e71ec 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; using System; using System.Collections.Generic; using System.Linq; @@ -51,5 +52,10 @@ namespace MediaBrowser.Controller.Entities LibraryManager.RegisterItem(item); } } + + public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, User user) + { + // Nothing meaninful here and will only waste resources + } } } diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 86099fdc0..619a497f5 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Entities var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList(); return user.RootFolder - .GetChildren(user, true) + .GetChildren(user, true, true) .OfType() .Where(i => !excludeFolderIds.Contains(i.Id) && !IsExcludedFromGrouping(i)); } diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 2bec9e3de..9db91e7f2 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using System; using System.Threading; @@ -34,5 +35,13 @@ namespace MediaBrowser.Controller.Library /// The key. /// Task{UserItemData}. UserItemData GetUserData(Guid userId, string key); + + /// + /// Gets the user data dto. + /// + /// The item. + /// The user. + /// UserItemDataDto. + UserItemDataDto GetUserDataDto(IHasUserData item, User user); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs index 23610351e..ba1cb3043 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvRecording.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.LiveTv { - public interface ILiveTvRecording : IHasImages, IHasMediaSources + public interface ILiveTvRecording : IHasImages, IHasMediaSources, IHasUserData { string ServiceName { get; set; } @@ -20,8 +20,6 @@ namespace MediaBrowser.Controller.LiveTv string GetClientTypeName(); - string GetUserDataKey(); - bool IsParentalAllowed(User user); Task RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken); diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 692d6db90..7f1ddbce9 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,6 +1,6 @@ -using System; +using MediaBrowser.Model.Entities; +using System; using System.Collections.Generic; -using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Providers { @@ -18,6 +18,11 @@ namespace MediaBrowser.Controller.Providers /// [Obsolete] public bool ForceSave { get; set; } + + public MetadataRefreshOptions() + { + MetadataRefreshMode = MetadataRefreshMode.Default; + } } public class ImageRefreshOptions @@ -38,48 +43,54 @@ namespace MediaBrowser.Controller.Providers public bool IsReplacingImage(ImageType type) { - return ReplaceAllImages || ReplaceImages.Contains(type); + return ImageRefreshMode == ImageRefreshMode.FullRefresh && + (ReplaceAllImages || ReplaceImages.Contains(type)); } } public enum MetadataRefreshMode { /// - /// Providers will be executed based on default rules + /// The none /// - EnsureMetadata = 0, + None = 0, /// - /// No providers will be executed + /// The validation only /// - None = 1, + ValidationOnly = 1, /// - /// All providers will be executed to search for new metadata + /// Providers will be executed based on default rules /// - FullRefresh = 2, + Default = 2, /// - /// The validation only + /// All providers will be executed to search for new metadata /// - ValidationOnly = 3 + FullRefresh = 3 } public enum ImageRefreshMode { + /// + /// The none + /// + None = 0, + /// /// The default /// - Default = 0, + Default = 1, /// /// Existing images will be validated /// - ValidationOnly = 1, + ValidationOnly = 2, /// /// All providers will be executed to search for new metadata /// - FullRefresh = 2 + FullRefresh = 3 } } diff --git a/MediaBrowser.Controller/Session/ISessionManager.cs b/MediaBrowser.Controller/Session/ISessionManager.cs index 6d3a9d20c..7b2062182 100644 --- a/MediaBrowser.Controller/Session/ISessionManager.cs +++ b/MediaBrowser.Controller/Session/ISessionManager.cs @@ -219,7 +219,13 @@ namespace MediaBrowser.Controller.Session /// Name of the device. /// The remote end point. /// Task{SessionInfo}. - Task AuthenticateNewSession(string username, string password, string clientType, string appVersion, string deviceId, string deviceName, string remoteEndPoint); + Task AuthenticateNewSession(string username, + string password, + string clientType, + string appVersion, + string deviceId, + string deviceName, + string remoteEndPoint); /// /// Reports the capabilities. diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 0ed49d5f8..91c1508fc 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -77,6 +77,9 @@ ApiClient\SessionUpdatesEventArgs.cs + + Branding\BrandingOptions.cs + Channels\ChannelFeatures.cs @@ -815,6 +818,9 @@ Session\UserDataChangeInfo.cs + + System\LogFile.cs + System\SystemInfo.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 12c87ca97..782e8524d 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -64,6 +64,9 @@ ApiClient\SessionUpdatesEventArgs.cs + + Branding\BrandingOptions.cs + Channels\ChannelFeatures.cs @@ -796,6 +799,9 @@ Session\UserDataChangeInfo.cs + + System\LogFile.cs + System\SystemInfo.cs diff --git a/MediaBrowser.Model/Branding/BrandingOptions.cs b/MediaBrowser.Model/Branding/BrandingOptions.cs new file mode 100644 index 000000000..737cb5c48 --- /dev/null +++ b/MediaBrowser.Model/Branding/BrandingOptions.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Model.Branding +{ + public class BrandingOptions + { + /// + /// Gets or sets the login disclaimer. + /// + /// The login disclaimer. + public string LoginDisclaimer { get; set; } + } +} diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 36c353479..49b731341 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -158,9 +158,6 @@ namespace MediaBrowser.Model.Configuration public bool EnableTmdbUpdates { get; set; } public bool EnableFanArtUpdates { get; set; } - public bool RequireMobileManualLogin { get; set; } - public bool RequireNonMobileManualLogin { get; set; } - /// /// Gets or sets the image saving convention. /// diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs index db8b69951..86eb40b97 100644 --- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs +++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs @@ -10,12 +10,15 @@ namespace MediaBrowser.Model.Configuration public bool SaveImagePathsInNfo { get; set; } public bool EnablePathSubstitution { get; set; } + public bool EnableExtraThumbsDuplication { get; set; } + public XbmcMetadataOptions() { ReleaseDateFormat = "yyyy-MM-dd"; SaveImagePathsInNfo = true; EnablePathSubstitution = true; + EnableExtraThumbsDuplication = true; } } } diff --git a/MediaBrowser.Model/Dto/UserItemDataDto.cs b/MediaBrowser.Model/Dto/UserItemDataDto.cs index 26b0e9d9e..6ee9f1916 100644 --- a/MediaBrowser.Model/Dto/UserItemDataDto.cs +++ b/MediaBrowser.Model/Dto/UserItemDataDto.cs @@ -1,6 +1,6 @@ -using System; +using MediaBrowser.Model.Extensions; +using System; using System.ComponentModel; -using MediaBrowser.Model.Extensions; namespace MediaBrowser.Model.Dto { @@ -15,6 +15,18 @@ namespace MediaBrowser.Model.Dto /// The rating. public double? Rating { get; set; } + /// + /// Gets or sets the played percentage. + /// + /// The played percentage. + public double? PlayedPercentage { get; set; } + + /// + /// Gets or sets the unplayed item count. + /// + /// The unplayed item count. + public int? UnplayedItemCount { get; set; } + /// /// Gets or sets the playback position ticks. /// diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index d758f2f39..4d4ca8e20 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -65,6 +65,7 @@ + @@ -294,6 +295,7 @@ + diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs index f511d41a9..6e9368f44 100644 --- a/MediaBrowser.Model/Notifications/NotificationRequest.cs +++ b/MediaBrowser.Model/Notifications/NotificationRequest.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Model.Configuration; -using System; +using System; using System.Collections.Generic; namespace MediaBrowser.Model.Notifications diff --git a/MediaBrowser.Model/Session/SessionInfoDto.cs b/MediaBrowser.Model/Session/SessionInfoDto.cs index 40723eff8..98df3efe5 100644 --- a/MediaBrowser.Model/Session/SessionInfoDto.cs +++ b/MediaBrowser.Model/Session/SessionInfoDto.cs @@ -1,32 +1,20 @@ using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Extensions; using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; -using MediaBrowser.Model.Extensions; namespace MediaBrowser.Model.Session { [DebuggerDisplay("Client = {Client}, Username = {UserName}")] public class SessionInfoDto : IHasPropertyChangedEvent { - /// - /// Gets or sets a value indicating whether this instance can seek. - /// - /// true if this instance can seek; otherwise, false. - public bool CanSeek { get; set; } - /// /// Gets or sets the supported commands. /// /// The supported commands. public List SupportedCommands { get; set; } - - /// - /// Gets or sets the remote end point. - /// - /// The remote end point. - public string RemoteEndPoint { get; set; } /// /// Gets or sets the queueable media types. @@ -99,18 +87,6 @@ namespace MediaBrowser.Model.Session /// /// The name of the device. public string DeviceName { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is paused. - /// - /// true if this instance is paused; otherwise, false. - public bool IsPaused { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is muted. - /// - /// true if this instance is muted; otherwise, false. - public bool IsMuted { get; set; } /// /// Gets or sets the now playing item. @@ -118,12 +94,6 @@ namespace MediaBrowser.Model.Session /// The now playing item. public BaseItemInfo NowPlayingItem { get; set; } - /// - /// Gets or sets the now playing position ticks. - /// - /// The now playing position ticks. - public long? NowPlayingPositionTicks { get; set; } - /// /// Gets or sets the device id. /// diff --git a/MediaBrowser.Model/System/LogFile.cs b/MediaBrowser.Model/System/LogFile.cs new file mode 100644 index 000000000..ba409c542 --- /dev/null +++ b/MediaBrowser.Model/System/LogFile.cs @@ -0,0 +1,31 @@ +using System; + +namespace MediaBrowser.Model.System +{ + public class LogFile + { + /// + /// Gets or sets the date created. + /// + /// The date created. + public DateTime DateCreated { get; set; } + + /// + /// Gets or sets the date modified. + /// + /// The date modified. + public DateTime DateModified { get; set; } + + /// + /// Gets or sets the size. + /// + /// The size. + public long Size { get; set; } + + /// + /// Gets or sets the name. + /// + /// The name. + public string Name { get; set; } + } +} diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 12af93dbd..1b2e9fa6d 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -441,11 +442,16 @@ namespace MediaBrowser.Providers.Manager var extraFanartFilename = GetBackdropSaveFilename(item.GetImages(ImageType.Backdrop), "fanart", "fanart", outputIndex); - return new[] - { - Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension), - Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension) - }; + var list = new List + { + Path.Combine(item.ContainingFolderPath, "extrafanart", extraFanartFilename + extension) + }; + + if (EnableExtraThumbsDuplication) + { + list.Add(Path.Combine(item.ContainingFolderPath, "extrathumbs", "thumb" + outputIndex.ToString(UsCulture) + extension)); + } + return list.ToArray(); } if (type == ImageType.Primary) @@ -528,6 +534,16 @@ namespace MediaBrowser.Providers.Manager return new[] { GetStandardSavePath(item, type, imageIndex, mimeType, true) }; } + private bool EnableExtraThumbsDuplication + { + get + { + var config = _config.GetConfiguration("xbmcmetadata"); + + return config.EnableExtraThumbsDuplication; + } + } + /// /// Gets the save path for item in mixed folder. /// diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 92b4616e7..57a40741f 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -234,7 +234,7 @@ namespace MediaBrowser.Providers.MediaInfo await _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken).ConfigureAwait(false); if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || - options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata) + options.MetadataRefreshMode == MetadataRefreshMode.Default) { try { @@ -460,7 +460,7 @@ namespace MediaBrowser.Providers.MediaInfo var externalSubtitleStreams = subtitleResolver.GetExternalSubtitleStreams(video, currentStreams.Count, options.DirectoryService, false).ToList(); - var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.EnsureMetadata || + var enableSubtitleDownloading = options.MetadataRefreshMode == MetadataRefreshMode.Default || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh; if (enableSubtitleDownloading && (_config.Configuration.SubtitleOptions.DownloadEpisodeSubtitles && diff --git a/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs b/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs new file mode 100644 index 000000000..d6cd3424b --- /dev/null +++ b/MediaBrowser.Server.Implementations/Branding/BrandingConfigurationFactory.cs @@ -0,0 +1,21 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Branding; +using System.Collections.Generic; + +namespace MediaBrowser.Server.Implementations.Branding +{ + public class BrandingConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new[] + { + new ConfigurationStore + { + ConfigurationType = typeof(BrandingOptions), + Key = "branding" + } + }; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 73216ca33..62ff9f687 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -212,6 +212,12 @@ namespace MediaBrowser.Server.Implementations.Dto { if (item.IsFolder) { + var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey()); + + // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice + // TODO: Improve in future + dto.UserData = GetUserItemDataDto(userData); + var folder = (Folder)item; dto.ChildCount = GetChildCount(folder, user); @@ -220,15 +226,15 @@ namespace MediaBrowser.Server.Implementations.Dto { SetSpecialCounts(folder, user, dto, fields); } - } - var userData = _userDataRepository.GetUserData(user.Id, item.GetUserDataKey()); - - dto.UserData = GetUserItemDataDto(userData); + dto.UserData.Played = dto.PlayedPercentage.HasValue && dto.PlayedPercentage.Value >= 100; + dto.UserData.PlayedPercentage = dto.PlayedPercentage; + dto.UserData.UnplayedItemCount = dto.RecursiveUnplayedItemCount; + } - if (item.IsFolder) + else { - dto.UserData.Played = dto.PlayedPercentage.HasValue && dto.PlayedPercentage.Value >= 100; + dto.UserData = _userDataRepository.GetUserDataDto(item, user); } dto.PlayAccess = item.GetPlayAccess(user); @@ -1110,16 +1116,17 @@ namespace MediaBrowser.Server.Implementations.Dto if (episode != null) { - series = item.FindParent(); + series = episode.Series; - dto.SeriesId = GetDtoId(series); - dto.SeriesName = series.Name; - dto.AirTime = series.AirTime; - dto.SeriesStudio = series.Studios.FirstOrDefault(); - - dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb); - - dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); + if (series != null) + { + dto.SeriesId = GetDtoId(series); + dto.SeriesName = series.Name; + dto.AirTime = series.AirTime; + dto.SeriesStudio = series.Studios.FirstOrDefault(); + dto.SeriesThumbImageTag = GetImageCacheTag(series, ImageType.Thumb); + dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); + } } // Add SeasonInfo @@ -1127,14 +1134,17 @@ namespace MediaBrowser.Server.Implementations.Dto if (season != null) { - series = item.FindParent(); + series = season.Series; - dto.SeriesId = GetDtoId(series); - dto.SeriesName = series.Name; - dto.AirTime = series.AirTime; - dto.SeriesStudio = series.Studios.FirstOrDefault(); + if (series != null) + { + dto.SeriesId = GetDtoId(series); + dto.SeriesName = series.Name; + dto.AirTime = series.AirTime; + dto.SeriesStudio = series.Studios.FirstOrDefault(); - dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); + dto.SeriesPrimaryImageTag = GetImageCacheTag(series, ImageType.Primary); + } } var game = item as Game; diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs index d7186aa21..c31f46215 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UserDataChangeNotifier.cs @@ -1,10 +1,11 @@ -using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; +using MoreLinq; using System; using System.Collections.Generic; using System.Linq; @@ -17,21 +18,21 @@ namespace MediaBrowser.Server.Implementations.EntryPoints { private readonly ISessionManager _sessionManager; private readonly ILogger _logger; - private readonly IDtoService _dtoService; private readonly IUserDataManager _userDataManager; + private readonly IUserManager _userManager; private readonly object _syncLock = new object(); private Timer UpdateTimer { get; set; } private const int UpdateDuration = 500; - private readonly Dictionary> _changedKeys = new Dictionary>(); + private readonly Dictionary> _changedItems = new Dictionary>(); - public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, IDtoService dtoService, ILogger logger) + public UserDataChangeNotifier(IUserDataManager userDataManager, ISessionManager sessionManager, ILogger logger, IUserManager userManager) { _userDataManager = userDataManager; _sessionManager = sessionManager; - _dtoService = dtoService; _logger = logger; + _userManager = userManager; } public void Run() @@ -58,15 +59,28 @@ namespace MediaBrowser.Server.Implementations.EntryPoints UpdateTimer.Change(UpdateDuration, Timeout.Infinite); } - List keys; + List keys; - if (!_changedKeys.TryGetValue(e.UserId, out keys)) + if (!_changedItems.TryGetValue(e.UserId, out keys)) { - keys = new List(); - _changedKeys[e.UserId] = keys; + keys = new List(); + _changedItems[e.UserId] = keys; } - keys.Add(e.Key); + keys.Add(e.Item); + + var baseItem = e.Item as BaseItem; + + // Go up one level for indicators + if (baseItem != null) + { + var parent = baseItem.Parent; + + if (parent != null) + { + keys.Add(parent); + } + } } } @@ -75,8 +89,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints lock (_syncLock) { // Remove dupes in case some were saved multiple times - var changes = _changedKeys.ToList(); - _changedKeys.Clear(); + var changes = _changedItems.ToList(); + _changedItems.Clear(); SendNotifications(changes, CancellationToken.None); @@ -88,7 +102,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints } } - private async Task SendNotifications(IEnumerable>> changes, CancellationToken cancellationToken) + private async Task SendNotifications(IEnumerable>> changes, CancellationToken cancellationToken) { foreach (var pair in changes) { @@ -99,8 +113,11 @@ namespace MediaBrowser.Server.Implementations.EntryPoints if (userSessions.Count > 0) { + var user = _userManager.GetUserById(userId); + var dtoList = pair.Value - .Select(i => _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(userId, i))) + .DistinctBy(i => i.Id) + .Select(i => _userDataManager.GetUserDataDto(i, user)) .ToList(); var info = new UserDataChangeInfo diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 833dfc5e4..cfcbb077e 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -363,19 +363,15 @@ namespace MediaBrowser.Server.Implementations.HttpServer { try { - var errorResponse = new ErrorResponse - { - ResponseStatus = new ResponseStatus - { - ErrorCode = ex.GetType().GetOperationName(), - Message = ex.Message, - StackTrace = ex.StackTrace, - } - }; - var operationName = context.Request.GetOperationName(); var httpReq = GetRequest(context, operationName); var httpRes = httpReq.Response; + + if (httpRes.IsClosed) + { + return; + } + var contentType = httpReq.ResponseContentType; var serializer = HostContext.ContentTypes.GetResponseSerializer(contentType); @@ -398,6 +394,16 @@ namespace MediaBrowser.Server.Implementations.HttpServer httpRes.ContentType = contentType; + var errorResponse = new ErrorResponse + { + ResponseStatus = new ResponseStatus + { + ErrorCode = ex.GetType().GetOperationName(), + Message = ex.Message, + StackTrace = ex.StackTrace, + } + }; + serializer(httpReq, errorResponse, httpRes); httpRes.Close(); diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs index 77343ab4e..94be37e95 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthorizationContext.cs @@ -36,6 +36,13 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security auth.TryGetValue("Version", out version); } + var token = httpReq.Headers["X-MediaBrowser-Token"]; + + if (string.IsNullOrWhiteSpace(token)) + { + token = httpReq.QueryString["api_key"]; + } + return new AuthorizationInfo { Client = client, @@ -43,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security DeviceId = deviceId, UserId = userId, Version = version, - Token = httpReq.Headers["X-AUTH-TOKEN"] + Token = token }; } diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index 79f126511..d3030f31f 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; @@ -125,5 +126,41 @@ namespace MediaBrowser.Server.Implementations.Library { return userId + key; } + + public UserItemDataDto GetUserDataDto(IHasUserData item, User user) + { + var userData = GetUserData(user.Id, item.GetUserDataKey()); + var dto = GetUserItemDataDto(userData); + + item.FillUserDataDtoValues(dto, userData, user); + + return dto; + } + + /// + /// Converts a UserItemData to a DTOUserItemData + /// + /// The data. + /// DtoUserItemData. + /// + private UserItemDataDto GetUserItemDataDto(UserItemData data) + { + if (data == null) + { + throw new ArgumentNullException("data"); + } + + return new UserItemDataDto + { + IsFavorite = data.IsFavorite, + Likes = data.Likes, + PlaybackPositionTicks = data.PlaybackPositionTicks, + PlayCount = data.PlayCount, + Rating = data.Rating, + Played = data.Played, + LastPlayedDate = data.LastPlayedDate, + Key = data.Key + }; + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 412b2e7bd..9c69e656d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Entities; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Logging; @@ -23,15 +22,13 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly IUserDataManager _userDataManager; private readonly IDtoService _dtoService; - private readonly IItemRepository _itemRepo; - public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger, IItemRepository itemRepo) + public LiveTvDtoService(IDtoService dtoService, IUserDataManager userDataManager, IImageProcessor imageProcessor, ILogger logger) { _dtoService = dtoService; _userDataManager = userDataManager; _imageProcessor = imageProcessor; _logger = logger; - _itemRepo = itemRepo; } public TimerInfoDto GetTimerInfoDto(TimerInfo info, ILiveTvService service, LiveTvProgram program, LiveTvChannel channel) @@ -249,7 +246,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (user != null) { - dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, recording.GetUserDataKey())); + dto.UserData = _userDataManager.GetUserDataDto(recording, user); dto.PlayAccess = recording.GetPlayAccess(user); } @@ -322,7 +319,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (user != null) { - dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, info.GetUserDataKey())); + dto.UserData = _userDataManager.GetUserDataDto(info, user); dto.PlayAccess = info.GetPlayAccess(user); } @@ -401,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (user != null) { - dto.UserData = _dtoService.GetUserItemDataDto(_userDataManager.GetUserData(user.Id, item.GetUserDataKey())); + dto.UserData = _userDataManager.GetUserDataDto(item, user); dto.PlayAccess = item.GetPlayAccess(user); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index ad1ddba88..09793f4fc 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -40,7 +40,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly IUserDataManager _userDataManager; private readonly ILibraryManager _libraryManager; private readonly ITaskManager _taskManager; - private readonly IJsonSerializer _json; private readonly IDtoService _dtoService; private readonly ILocalizationManager _localization; @@ -58,7 +57,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private readonly SemaphoreSlim _refreshSemaphore = new SemaphoreSlim(1, 1); - public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, IJsonSerializer json, ILocalizationManager localization) + public LiveTvManager(IServerConfigurationManager config, IFileSystem fileSystem, ILogger logger, IItemRepository itemRepo, IImageProcessor imageProcessor, IUserDataManager userDataManager, IDtoService dtoService, IUserManager userManager, ILibraryManager libraryManager, ITaskManager taskManager, ILocalizationManager localization) { _config = config; _fileSystem = fileSystem; @@ -67,12 +66,11 @@ namespace MediaBrowser.Server.Implementations.LiveTv _userManager = userManager; _libraryManager = libraryManager; _taskManager = taskManager; - _json = json; _localization = localization; _dtoService = dtoService; _userDataManager = userDataManager; - _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger, _itemRepo); + _tvDtoService = new LiveTvDtoService(dtoService, userDataManager, imageProcessor, logger); } /// diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 3bd0df0eb..d6d4bbc51 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -258,11 +258,11 @@ "LabelCachePath": "Cache path:", "LabelCachePathHelp": "This folder contains server cache files, such as images.", "LabelImagesByNamePath": "Images by name path:", - "LabelImagesByNamePathHelp": "This folder contains actor, artist, genre and studio images.", + "LabelImagesByNamePathHelp": "This folder contains downloaded actor, artist, genre and studio images.", "LabelMetadataPath": "Metadata path:", "LabelMetadataPathHelp": "This location contains downloaded artwork and metadata that is not configured to be stored in media folders.", "LabelTranscodingTempPath": "Transcoding temporary path:", - "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder.", + "LabelTranscodingTempPathHelp": "This folder contains working files used by the transcoder. Specify a custom path, or leave empty to use the default within the server's data folder.", "TabBasics": "Basics", "TabTV": "TV", "TabGames": "Games", @@ -284,7 +284,7 @@ "ButtonAutoScroll": "Auto-scroll", "LabelImageSavingConvention": "Image saving convention:", "LabelImageSavingConventionHelp": "Media Browser recognizes images from most major media applications. Choosing your downloading convention is useful if you also use other products.", - "OptionImageSavingCompatible": "Compatible - Media Browser/Plex/Xbmc", + "OptionImageSavingCompatible": "Compatible - Media Browser/Xbmc/Plex", "OptionImageSavingStandard": "Standard - MB2", "ButtonSignIn": "Sign In", "TitleSignIn": "Sign In", @@ -849,5 +849,14 @@ "LabelXbmcMetadataEnablePathSubstitutionHelp2": "See path substitution.", "LabelGroupChannelsIntoViews": "Display the following channels directly within my views:", "LabelGroupChannelsIntoViewsHelp": "If enabled, these channels will be displayed directly alongside other views. If disabled, they'll be displayed within a separate Channels view.", - "LabelDisplayCollectionsView": "Display a Collections view to show movie collections" + "LabelDisplayCollectionsView": "Display a Collections view to show movie collections", + "LabelXbmcMetadataEnableExtraThumbs": "Copy extrafanart into extrathumbs", + "LabelXbmcMetadataEnableExtraThumbsHelp": "When downloading images they can be saved into both extrafanart and extrathumbs for maximum Xbmc skin compatibility.", + "TabServices": "Services", + "TabLogs": "Logs", + "HeaderServerLogFiles": "Server log files:", + "TabBranding": "Branding", + "HeaderBrandingHelp": "Customize the appearance of Media Browser to fit the needs of your group or organization.", + "LabelLoginDisclaimer": "Login disclaimer:", + "LabelLoginDisclaimerHelp": "This will be displayed at the bottom of the login page." } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index a909929ae..1d201e069 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -101,6 +101,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 964e2cd24..b832f3a06 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Notifications; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Notifications; using System; @@ -93,7 +92,9 @@ namespace MediaBrowser.Server.Implementations.Notifications if (options != null && !string.IsNullOrWhiteSpace(request.NotificationType)) { - return _userManager.Users.Where(i => _config.Configuration.NotificationOptions.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) + var config = GetConfiguration(); + + return _userManager.Users.Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) .Select(i => i.Id.ToString("N")); } diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 2f6790a3e..2d85a3aa7 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.Events; +using System.Security.Cryptography; +using System.Text; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -1185,6 +1187,24 @@ namespace MediaBrowser.Server.Implementations.Session }; } + private bool IsLocal(string remoteEndpoint) + { + if (string.IsNullOrWhiteSpace(remoteEndpoint)) + { + throw new ArgumentNullException("remoteEndpoint"); + } + + // Private address space: + // http://en.wikipedia.org/wiki/Private_network + + return remoteEndpoint.IndexOf("localhost", StringComparison.OrdinalIgnoreCase) != -1 || + remoteEndpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase) || + remoteEndpoint.StartsWith("192.", StringComparison.OrdinalIgnoreCase) || + remoteEndpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase) || + remoteEndpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) || + remoteEndpoint.StartsWith("::", StringComparison.OrdinalIgnoreCase); + } + /// /// Reports the capabilities. /// @@ -1283,15 +1303,10 @@ namespace MediaBrowser.Server.Implementations.Session DeviceName = session.DeviceName, Id = session.Id, LastActivityDate = session.LastActivityDate, - NowPlayingPositionTicks = session.PlayState.PositionTicks, - IsPaused = session.PlayState.IsPaused, - IsMuted = session.PlayState.IsMuted, NowViewingItem = session.NowViewingItem, ApplicationVersion = session.ApplicationVersion, - CanSeek = session.PlayState.CanSeek, QueueableMediaTypes = session.QueueableMediaTypes, PlayableMediaTypes = session.PlayableMediaTypes, - RemoteEndPoint = session.RemoteEndPoint, AdditionalUsers = session.AdditionalUsers, SupportedCommands = session.SupportedCommands, UserName = session.UserName, diff --git a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs b/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs index 46c3df07b..7e6a252cd 100644 --- a/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs +++ b/MediaBrowser.Server.Implementations/Sorting/AirTimeComparer.cs @@ -26,13 +26,36 @@ namespace MediaBrowser.Server.Implementations.Sorting /// System.String. private DateTime GetValue(BaseItem x) { - var series = (x as Series) ?? x.FindParent(); + var series = x as Series; - DateTime result; - if (series != null && DateTime.TryParse(series.AirTime, out result)) + if (series == null) { - return result; - } + var season = x as Season; + + if (season != null) + { + series = season.Series; + } + else + { + var episode = x as Episode; + + if (episode != null) + { + series = episode.Series; + } + } + } + + if (series != null) + { + DateTime result; + if (DateTime.TryParse(series.AirTime, out result)) + { + return result; + } + } + return DateTime.MinValue; } diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 673a9f151..91e92e21c 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -654,7 +654,7 @@ namespace MediaBrowser.ServerApplication var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor); RegisterSingleInstance(collectionManager); - LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, JsonSerializer, LocalizationManager); + LiveTvManager = new LiveTvManager(ServerConfigurationManager, FileSystemManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager); RegisterSingleInstance(LiveTvManager); UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, FileSystemManager, UserManager, ChannelManager, LiveTvManager); diff --git a/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs index 4ba98e9b6..c2c64ea4d 100644 --- a/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs +++ b/MediaBrowser.ServerApplication/Native/BrowserLauncher.cs @@ -86,18 +86,6 @@ namespace MediaBrowser.ServerApplication.Native appHost.WebApplicationName + "/swagger-ui/index.html", logger); } - /// - /// Opens the standard API documentation. - /// - /// The configuration manager. - /// The app host. - /// The logger. - public static void OpenStandardApiDocumentation(IServerConfigurationManager configurationManager, IServerApplicationHost appHost, ILogger logger) - { - OpenUrl("http://localhost:" + configurationManager.Configuration.HttpServerPortNumber + "/" + - appHost.WebApplicationName + "/metadata", logger); - } - /// /// Opens the URL. /// diff --git a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs index f5f9434e7..47a4be8e3 100644 --- a/MediaBrowser.ServerApplication/ServerNotifyIcon.cs +++ b/MediaBrowser.ServerApplication/ServerNotifyIcon.cs @@ -29,7 +29,6 @@ namespace MediaBrowser.ServerApplication private System.Windows.Forms.ToolStripMenuItem cmdLogWindow; private System.Windows.Forms.ToolStripMenuItem cmdCommunity; private System.Windows.Forms.ToolStripMenuItem cmdApiDocs; - private System.Windows.Forms.ToolStripMenuItem cmdStandardDocs; private System.Windows.Forms.ToolStripMenuItem cmdSwagger; private System.Windows.Forms.ToolStripMenuItem cmdGtihub; @@ -90,7 +89,6 @@ namespace MediaBrowser.ServerApplication cmdConfigure = new System.Windows.Forms.ToolStripMenuItem(); cmdBrowse = new System.Windows.Forms.ToolStripMenuItem(); cmdApiDocs = new System.Windows.Forms.ToolStripMenuItem(); - cmdStandardDocs = new System.Windows.Forms.ToolStripMenuItem(); cmdSwagger = new System.Windows.Forms.ToolStripMenuItem(); cmdGtihub = new System.Windows.Forms.ToolStripMenuItem(); @@ -169,17 +167,11 @@ namespace MediaBrowser.ServerApplication // cmdApiDocs // cmdApiDocs.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - cmdStandardDocs, cmdSwagger, cmdGtihub}); cmdApiDocs.Name = "cmdApiDocs"; cmdApiDocs.Size = new System.Drawing.Size(208, 22); // - // cmdStandardDocs - // - cmdStandardDocs.Name = "cmdStandardDocs"; - cmdStandardDocs.Size = new System.Drawing.Size(136, 22); - // // cmdSwagger // cmdSwagger.Name = "cmdSwagger"; @@ -199,7 +191,6 @@ namespace MediaBrowser.ServerApplication cmdLibraryExplorer.Click += cmdLibraryExplorer_Click; cmdSwagger.Click += cmdSwagger_Click; - cmdStandardDocs.Click += cmdStandardDocs_Click; cmdGtihub.Click += cmdGtihub_Click; LoadLogWindow(null, EventArgs.Empty); @@ -224,7 +215,6 @@ namespace MediaBrowser.ServerApplication cmdCommunity.Text = _localization.GetLocalizedString("LabelVisitCommunity"); cmdGtihub.Text = _localization.GetLocalizedString("LabelGithubWiki"); cmdSwagger.Text = _localization.GetLocalizedString("LabelSwagger"); - cmdStandardDocs.Text = _localization.GetLocalizedString("LabelStandard"); cmdApiDocs.Text = _localization.GetLocalizedString("LabelViewApiDocumentation"); cmdBrowse.Text = _localization.GetLocalizedString("LabelBrowseLibrary"); cmdConfigure.Text = _localization.GetLocalizedString("LabelConfigureMediaBrowser"); @@ -346,11 +336,6 @@ namespace MediaBrowser.ServerApplication BrowserLauncher.OpenGithub(_logger); } - void cmdStandardDocs_Click(object sender, EventArgs e) - { - BrowserLauncher.OpenStandardApiDocumentation(_configurationManager, _appHost, _logger); - } - void cmdSwagger_Click(object sender, EventArgs e) { BrowserLauncher.OpenSwagger(_configurationManager, _appHost, _logger); diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 3ccf26c37..36adae71c 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -521,6 +521,7 @@ namespace MediaBrowser.WebDashboard.Api "mediacontroller.js", "chromecast.js", "backdrops.js", + "branding.js", "mediaplayer.js", "mediaplayer-video.js", @@ -529,7 +530,6 @@ namespace MediaBrowser.WebDashboard.Api "ratingdialog.js", "aboutpage.js", - "allusersettings.js", "alphapicker.js", "addpluginpage.js", "advancedconfigurationpage.js", @@ -537,7 +537,6 @@ namespace MediaBrowser.WebDashboard.Api "advancedserversettings.js", "metadataadvanced.js", "appsplayback.js", - "appsweather.js", "autoorganizetv.js", "autoorganizelog.js", "channels.js", diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index 8f85fcb51..0099daaf1 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -98,6 +98,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -392,9 +395,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -617,6 +617,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest @@ -1499,9 +1502,6 @@ PreserveNewest - - PreserveNewest - PreserveNewest @@ -1748,11 +1748,6 @@ PreserveNewest - - - PreserveNewest - - PreserveNewest @@ -1814,11 +1809,6 @@ PreserveNewest - - - PreserveNewest - - PreserveNewest -- cgit v1.2.3 From 97c5b468a0a731b38c83c6b2e6d8231bda02be2a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 17 Jul 2014 20:39:07 -0400 Subject: add dlna channel factory --- MediaBrowser.Api/Images/ImageService.cs | 3 - .../Channels/ChannelFolderItem.cs | 6 -- .../Entities/Audio/MusicAlbum.cs | 9 +-- .../Entities/Audio/MusicArtist.cs | 10 +-- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 4 +- MediaBrowser.Controller/Entities/TV/Series.cs | 9 +-- MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs | 88 ++++++++++++++++++++++ MediaBrowser.Dlna/MediaBrowser.Dlna.csproj | 1 + .../Channels/ChannelManager.cs | 4 +- .../Notifications/NotificationManager.cs | 5 +- 10 files changed, 98 insertions(+), 41 deletions(-) create mode 100644 MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs (limited to 'MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs') diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 10bc53b74..30db91da8 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -535,9 +535,6 @@ namespace MediaBrowser.Api.Images throw new ResourceNotFoundException(string.Format("{0} does not have an image of type {1}", item.Name, request.Type)); } - // See if we can avoid a file system lookup by looking for the file in ResolveArgs - var originalFileImageDateModified = imageInfo.DateModified; - var supportedImageEnhancers = request.EnableImageEnhancers ? _imageProcessor.ImageEnhancers.Where(i => { try diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs index afc6493e4..d6e315fd1 100644 --- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -15,7 +15,6 @@ namespace MediaBrowser.Controller.Channels public ChannelFolderType ChannelFolderType { get; set; } public string OriginalImageUrl { get; set; } - public List Tags { get; set; } protected override bool GetBlockUnratedValue(UserConfiguration config) { @@ -31,11 +30,6 @@ namespace MediaBrowser.Controller.Channels } } - public ChannelFolderItem() - { - Tags = new List(); - } - public override string GetUserDataKey() { return ExternalId; diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 9ddd10f4a..695b1fd57 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class MusicAlbum /// - public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasTags, IHasLookupInfo + public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo { public List SoundtrackIds { get; set; } @@ -19,7 +19,6 @@ namespace MediaBrowser.Controller.Entities.Audio { Artists = new List(); SoundtrackIds = new List(); - Tags = new List(); } [IgnoreDataMember] @@ -65,12 +64,6 @@ namespace MediaBrowser.Controller.Entities.Audio } } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets the tracks. /// diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 0a5d8eec0..1544da7bc 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -13,16 +13,9 @@ namespace MediaBrowser.Controller.Entities.Audio /// /// Class MusicArtist /// - public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasTags, IHasProductionLocations, IHasLookupInfo + public class MusicArtist : Folder, IMetadataContainer, IItemByName, IHasMusicGenres, IHasDualAccess, IHasProductionLocations, IHasLookupInfo { public bool IsAccessedByName { get; set; } - - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - public List ProductionLocations { get; set; } public override bool IsFolder @@ -60,7 +53,6 @@ namespace MediaBrowser.Controller.Entities.Audio public MusicArtist() { - Tags = new List(); ProductionLocations = new List(); } diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index b0cb549f4..0d2be9f74 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -14,13 +14,12 @@ namespace MediaBrowser.Controller.Entities.Movies /// /// Class BoxSet /// - public class BoxSet : Folder, IHasTrailers, IHasTags, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo, IMetadataContainer + public class BoxSet : Folder, IHasTrailers, IHasKeywords, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo, IMetadataContainer { public BoxSet() { RemoteTrailers = new List(); LocalTrailerIds = new List(); - Tags = new List(); DisplayOrder = ItemSortBy.PremiereDate; Keywords = new List(); @@ -38,7 +37,6 @@ namespace MediaBrowser.Controller.Entities.Movies /// Gets or sets the tags. /// /// The tags. - public List Tags { get; set; } public List Keywords { get; set; } public string PreferredMetadataLanguage { get; set; } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index a9a2b024f..9c2ed27bb 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Entities.TV /// /// Class Series /// - public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasTags, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo + public class Series : Folder, IHasSoundtracks, IHasTrailers, IHasPreferredMetadataLanguage, IHasDisplayOrder, IHasLookupInfo { public List SpecialFeatureIds { get; set; } public List SoundtrackIds { get; set; } @@ -36,7 +36,6 @@ namespace MediaBrowser.Controller.Entities.TV SoundtrackIds = new List(); RemoteTrailers = new List(); LocalTrailerIds = new List(); - Tags = new List(); DisplaySpecialsWithSeasons = true; } @@ -51,12 +50,6 @@ namespace MediaBrowser.Controller.Entities.TV /// public string DisplayOrder { get; set; } - /// - /// Gets or sets the tags. - /// - /// The tags. - public List Tags { get; set; } - /// /// Gets or sets the status. /// diff --git a/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs b/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs new file mode 100644 index 000000000..24e864c27 --- /dev/null +++ b/MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs @@ -0,0 +1,88 @@ +using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Dlna.Channels +{ + public class DlnaChannelFactory : IChannelFactory + { + public IEnumerable GetChannels() + { + // Check config here + // If user wants all channels separate, return them all + // If user wants one parent channel, return just that one + + return new List() + { + //new DummyChannel("test 1"), + //new DummyChannel("test 2") + }; + } + } + + public class DummyChannel : IChannel + { + private readonly string _name; + + public DummyChannel(string name) + { + _name = name; + } + + public string Name + { + get { return _name; } + } + + public string Description + { + get { return "Dummy Channel"; } + } + + public string DataVersion + { + get { return "1"; } + } + + public string HomePageUrl + { + get { return "http://www.google.com"; } + } + + public ChannelParentalRating ParentalRating + { + get { return ChannelParentalRating.GeneralAudience; } + } + + public InternalChannelFeatures GetChannelFeatures() + { + return new InternalChannelFeatures + { + + }; + } + + public bool IsEnabledFor(string userId) + { + return true; + } + + public Task GetChannelItems(InternalChannelItemQuery query, CancellationToken cancellationToken) + { + return Task.FromResult(new ChannelItemResult()); + } + + public Task GetChannelImage(ImageType type, CancellationToken cancellationToken) + { + return Task.FromResult(new DynamicImageResponse()); + } + + public IEnumerable GetSupportedChannelImages() + { + return new List(); + } + } +} diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index e3a5289f5..effa9f755 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -51,6 +51,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 79a251d1b..bf48af4fb 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -542,7 +542,7 @@ namespace MediaBrowser.Server.Implementations.Channels throw new ArgumentException("User not found."); } - var channels = _channels; + var channels = GetAllChannels(); if (query.ChannelIds.Length > 0) { @@ -696,7 +696,7 @@ namespace MediaBrowser.Server.Implementations.Channels ? null : _userManager.GetUserById(new Guid(query.UserId)); - var channels = _channels; + var channels = GetAllChannels(); if (query.ChannelIds.Length > 0) { diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index b832f3a06..7286846db 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -94,8 +94,9 @@ namespace MediaBrowser.Server.Implementations.Notifications { var config = GetConfiguration(); - return _userManager.Users.Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) - .Select(i => i.Id.ToString("N")); + return _userManager.Users + .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) + .Select(i => i.Id.ToString("N")); } return request.UserIds; -- cgit v1.2.3 From 6780e146a0bbea7065f478f957642a8ce50a6643 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 25 Aug 2014 22:30:52 -0400 Subject: remember display mirroring --- MediaBrowser.Controller/Entities/Audio/Audio.cs | 5 ++- MediaBrowser.Controller/Entities/BaseItem.cs | 26 ++++++++++- MediaBrowser.Controller/Entities/IThemeMedia.cs | 8 ++++ MediaBrowser.Controller/Entities/Video.cs | 5 ++- .../MediaBrowser.Controller.csproj | 1 + .../Providers/MetadataRefreshOptions.cs | 13 ++++++ MediaBrowser.Dlna/Ssdp/Datagram.cs | 2 +- MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs | 51 +++++----------------- MediaBrowser.Dlna/Ssdp/SsdpHandler.cs | 17 +------- MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs | 28 +----------- .../Notifications/NotificationRequest.cs | 4 -- .../EntryPoints/ActivityLogEntryPoint.cs | 14 ++++++ .../EntryPoints/Notifications/Notifications.cs | 8 ++-- .../LiveTv/LiveTvManager.cs | 23 ++++++++-- .../Localization/Server/server.json | 19 +++++--- .../Notifications/NotificationManager.cs | 1 - Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 20 files changed, 123 insertions(+), 114 deletions(-) create mode 100644 MediaBrowser.Controller/Entities/IThemeMedia.cs (limited to 'MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs') diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index d3085cb68..7d54e012c 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -20,7 +20,8 @@ namespace MediaBrowser.Controller.Entities.Audio IHasMusicGenres, IHasLookupInfo, IHasTags, - IHasMediaSources + IHasMediaSources, + IThemeMedia { public string FormatName { get; set; } public long? Size { get; set; } @@ -28,6 +29,8 @@ namespace MediaBrowser.Controller.Entities.Audio public int? TotalBitrate { get; set; } public List Tags { get; set; } + public bool IsThemeMedia { get; set; } + public Audio() { Artists = new List(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e718a53ff..fd7a33ddf 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -749,7 +749,18 @@ namespace MediaBrowser.Controller.Entities var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds); - var tasks = newThemeVideos.Select(i => i.RefreshMetadata(options, cancellationToken)); + var tasks = newThemeVideos.Select(i => + { + var subOptions = new MetadataRefreshOptions(options); + + if (!i.IsThemeMedia) + { + i.IsThemeMedia = true; + subOptions.ForceSave = true; + } + + return i.RefreshMetadata(subOptions, cancellationToken); + }); await Task.WhenAll(tasks).ConfigureAwait(false); @@ -768,7 +779,18 @@ namespace MediaBrowser.Controller.Entities var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds); - var tasks = newThemeSongs.Select(i => i.RefreshMetadata(options, cancellationToken)); + var tasks = newThemeSongs.Select(i => + { + var subOptions = new MetadataRefreshOptions(options); + + if (!i.IsThemeMedia) + { + i.IsThemeMedia = true; + subOptions.ForceSave = true; + } + + return i.RefreshMetadata(subOptions, cancellationToken); + }); await Task.WhenAll(tasks).ConfigureAwait(false); diff --git a/MediaBrowser.Controller/Entities/IThemeMedia.cs b/MediaBrowser.Controller/Entities/IThemeMedia.cs new file mode 100644 index 000000000..b2eff230f --- /dev/null +++ b/MediaBrowser.Controller/Entities/IThemeMedia.cs @@ -0,0 +1,8 @@ + +namespace MediaBrowser.Controller.Entities +{ + public interface IThemeMedia + { + bool IsThemeMedia { get; } + } +} diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index ff4c5dd90..ea530272d 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -24,7 +24,8 @@ namespace MediaBrowser.Controller.Entities IHasTags, ISupportsPlaceHolders, IHasMediaSources, - IHasShortOverview + IHasShortOverview, + IThemeMedia { public bool IsMultiPart { get; set; } public bool HasLocalAlternateVersions { get; set; } @@ -33,6 +34,8 @@ namespace MediaBrowser.Controller.Entities public List AdditionalPartIds { get; set; } public List LocalAlternateVersionIds { get; set; } + public bool IsThemeMedia { get; set; } + public string FormatName { get; set; } public long? Size { get; set; } public string Container { get; set; } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index cbf99d9a8..561ae9326 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -151,6 +151,7 @@ + diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index 7f1ddbce9..dd07979d3 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -1,6 +1,7 @@ using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; +using System.Linq; namespace MediaBrowser.Controller.Providers { @@ -23,6 +24,18 @@ namespace MediaBrowser.Controller.Providers { MetadataRefreshMode = MetadataRefreshMode.Default; } + + public MetadataRefreshOptions(MetadataRefreshOptions copy) + { + MetadataRefreshMode = copy.MetadataRefreshMode; + ForceSave = copy.ForceSave; + ReplaceAllMetadata = copy.ReplaceAllMetadata; + + ImageRefreshMode = copy.ImageRefreshMode; + DirectoryService = copy.DirectoryService; + ReplaceAllImages = copy.ReplaceAllImages; + ReplaceImages = copy.ReplaceImages.ToList(); + } } public class ImageRefreshOptions diff --git a/MediaBrowser.Dlna/Ssdp/Datagram.cs b/MediaBrowser.Dlna/Ssdp/Datagram.cs index 9df7502e7..2554d33c6 100644 --- a/MediaBrowser.Dlna/Ssdp/Datagram.cs +++ b/MediaBrowser.Dlna/Ssdp/Datagram.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Dlna.Ssdp } catch (Exception ex) { - _logger.ErrorException("Error sending Datagram: " + Message, ex); + _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString()); } ++SendCount; } diff --git a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs index 8cda73082..cc9b80d75 100644 --- a/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs +++ b/MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs @@ -1,8 +1,6 @@ using MediaBrowser.Common.Events; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Dlna.PlayTo; -using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; @@ -10,7 +8,6 @@ using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -75,7 +72,7 @@ namespace MediaBrowser.Dlna.Ssdp } } - void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e) + void _ssdpHandler_MessageReceived(object sender, SsdpMessageEventArgs e) { string nts; e.Headers.TryGetValue("NTS", out nts); @@ -87,10 +84,16 @@ namespace MediaBrowser.Dlna.Ssdp EventHelper.FireEventIfNotNull(DeviceLeft, this, e, _logger); return; } - - try + + try { - //TryCreateDevice(e, IPAddress.Parse(_networkManager.GetLocalIpAddresses().First())); + //var ip = _networkManager.GetLocalIpAddresses().FirstOrDefault(); + + //if (ip != null) + //{ + // e.LocalIp = IPAddress.Parse(ip); + // TryCreateDevice(e); + //} } catch (OperationCanceledException) { @@ -184,36 +187,6 @@ namespace MediaBrowser.Dlna.Ssdp } - private void CreateNotifier(Socket socket) - { - Task.Factory.StartNew(async (o) => - { - try - { - var msg = new SsdpMessageBuilder().BuildRendererDiscoveryMessage(); - var request = Encoding.UTF8.GetBytes(msg); - - while (true) - { - socket.SendTo(request, new IPEndPoint(IPAddress.Parse("239.255.255.250"), 1900)); - - var delay = _config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds * 1000; - - await Task.Delay(delay).ConfigureAwait(false); - } - } - catch (OperationCanceledException) - { - } - catch (Exception ex) - { - _logger.ErrorException("Error in notifier", ex); - } - - }, _tokenSource.Token, TaskCreationOptions.LongRunning); - - } - private Socket GetMulticastSocket(int networkInterfaceIndex) { var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); @@ -223,7 +196,7 @@ namespace MediaBrowser.Dlna.Ssdp return socket; } - private void TryCreateDevice(SsdpMessageEventArgs args) + private void TryCreateDevice(SsdpMessageEventArgs args) { string nts; args.Headers.TryGetValue("NTS", out nts); @@ -262,7 +235,7 @@ namespace MediaBrowser.Dlna.Ssdp public void Dispose() { _ssdpHandler.MessageReceived -= _ssdpHandler_MessageReceived; - + if (!_disposed) { _disposed = true; diff --git a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs index 10a234fb1..b8c64a787 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpHandler.cs @@ -146,21 +146,6 @@ namespace MediaBrowser.Dlna.Ssdp StartQueueTimer(); } - public void SendDatagramFromDevices(string header, - Dictionary values, - IPEndPoint endpoint, - string deviceType) - { - foreach (var d in RegisteredDevices) - { - if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) || - string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase)) - { - SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0)); - } - } - } - private void RespondToSearch(IPEndPoint endpoint, string deviceType) { if (_config.GetDlnaConfiguration().EnableDebugLogging) @@ -185,7 +170,7 @@ namespace MediaBrowser.Dlna.Ssdp values["ST"] = d.Type; values["USN"] = d.USN; - SendDatagram(header, values, endpoint, null); + SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0)); if (_config.GetDlnaConfiguration().EnableDebugLogging) { diff --git a/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs b/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs index 0eff6ad6f..e479ca19a 100644 --- a/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs +++ b/MediaBrowser.Dlna/Ssdp/SsdpMessageBuilder.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; namespace MediaBrowser.Dlna.Ssdp @@ -23,30 +22,5 @@ namespace MediaBrowser.Dlna.Ssdp return builder.ToString(); } - - public string BuildDiscoveryMessage(string deviceSearchType, string mx) - { - const string header = "M-SEARCH * HTTP/1.1"; - - var values = new Dictionary(StringComparer.OrdinalIgnoreCase); - - values["HOST"] = "239.255.255.250:1900"; - values["USER-AGENT"] = "UPnP/1.0 DLNADOC/1.50 Platinum/1.0.4.2"; - values["ST"] = "ssdp:all"; - values["MAN"] = "ssdp:discover"; - values["MX"] = "10"; - - return BuildMessage(header, values); - } - - public string BuildRendererDiscoveryMessage() - { - return BuildDiscoveryMessage("urn:schemas-upnp-org:device:MediaRenderer:1", "3"); - } - - public string BuildMediaServerDiscoveryMessage() - { - return BuildDiscoveryMessage("urn:schemas-upnp-org:device:MediaRenderer:1", "3"); - } } } diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs index 6e9368f44..3cd463422 100644 --- a/MediaBrowser.Model/Notifications/NotificationRequest.cs +++ b/MediaBrowser.Model/Notifications/NotificationRequest.cs @@ -26,16 +26,12 @@ namespace MediaBrowser.Model.Notifications public SendToUserType? SendToUserMode { get; set; } - public List ExcludeUserIds { get; set; } - public NotificationRequest() { UserIds = new List(); Date = DateTime.UtcNow; Variables = new Dictionary(); - - ExcludeUserIds = new List(); } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs index 0bd772a56..fb1010f1b 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ActivityLogEntryPoint.cs @@ -117,6 +117,13 @@ namespace MediaBrowser.Server.Implementations.EntryPoints return; } + var themeMedia = item as IThemeMedia; + if (themeMedia != null && themeMedia.IsThemeMedia) + { + // Don't report theme song or local trailer playback + return; + } + if (e.Users.Count == 0) { return; @@ -142,6 +149,13 @@ namespace MediaBrowser.Server.Implementations.EntryPoints return; } + var themeMedia = item as IThemeMedia; + if (themeMedia != null && themeMedia.IsThemeMedia) + { + // Don't report theme song or local trailer playback + return; + } + if (e.Users.Count == 0) { return; diff --git a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs index 6a0bb780c..065b5e95d 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/Notifications/Notifications.cs @@ -195,19 +195,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints.Notifications var user = e.Users.FirstOrDefault(); var item = e.MediaInfo; + var themeMedia = item as IThemeMedia; - if (e.Item != null && e.Item.Parent == null) + if (themeMedia != null && themeMedia.IsThemeMedia) { // Don't report theme song or local trailer playback - // TODO: This will also cause movie specials to not be reported return; } var notification = new NotificationRequest { - NotificationType = type, - - ExcludeUserIds = e.Users.Select(i => i.Id.ToString("N")).ToList() + NotificationType = type }; notification.Variables["ItemName"] = item.Name; diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index cc06c6c50..d072217af 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -475,13 +475,27 @@ namespace MediaBrowser.Server.Implementations.LiveTv } item.ChannelType = channelInfo.ChannelType; - item.ProviderImageUrl = channelInfo.ImageUrl; - item.HasProviderImage = channelInfo.HasImage; - item.ProviderImagePath = channelInfo.ImagePath; item.ExternalId = channelInfo.Id; item.ServiceName = serviceName; item.Number = channelInfo.Number; + var replaceImages = new List(); + + if (!string.Equals(item.ProviderImageUrl, channelInfo.ImageUrl, StringComparison.OrdinalIgnoreCase)) + { + isNew = true; + replaceImages.Add(ImageType.Primary); + } + if (!string.Equals(item.ProviderImagePath, channelInfo.ImagePath, StringComparison.OrdinalIgnoreCase)) + { + isNew = true; + replaceImages.Add(ImageType.Primary); + } + + item.ProviderImageUrl = channelInfo.ImageUrl; + item.HasProviderImage = channelInfo.HasImage; + item.ProviderImagePath = channelInfo.ImagePath; + if (string.IsNullOrEmpty(item.Name)) { item.Name = channelInfo.Name; @@ -489,7 +503,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv await item.RefreshMetadata(new MetadataRefreshOptions { - ForceSave = isNew + ForceSave = isNew, + ReplaceImages = replaceImages.Distinct().ToList() }, cancellationToken); diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index df9e28b90..6b1f3d91a 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -602,7 +602,6 @@ "LabelNotificationEnabled": "Enable this notification", "LabelMonitorUsers": "Monitor activity from:", "LabelSendNotificationToUsers": "Send the notification to:", - "UsersNotNotifiedAboutSelfActivity": "Users will not be notified about their own activities.", "LabelUseNotificationServices": "Use the following services:", "CategoryUser": "User", "CategorySystem": "System", @@ -769,15 +768,15 @@ "LabelDisplayPluginsFor": "Display plugins for:", "PluginTabMediaBrowserClassic": "MB Classic", "PluginTabMediaBrowserTheater": "MB Theater", - "LabelEpisodeName": "Episode name", - "LabelSeriesName": "Series name", + "LabelEpisodeNamePlain": "Episode name", + "LabelSeriesNamePlain": "Series name", "ValueSeriesNamePeriod": "Series.name", "ValueSeriesNameUnderscore": "Series_name", "ValueEpisodeNamePeriod": "Episode.name", "ValueEpisodeNameUnderscore": "Episode_name", - "LabelSeasonNumber": "Season number", - "LabelEpisodeNumber": "Episode number", - "LabelEndingEpisodeNumber": "Ending episode number", + "LabelSeasonNumberPlain": "Season number", + "LabelEpisodeNumberPlain": "Episode number", + "LabelEndingEpisodeNumberPlain": "Ending episode number", "HeaderTypeText": "Enter Text", "LabelTypeText": "Text", "HeaderSearchForSubtitles": "Search for Subtitles", @@ -1100,5 +1099,11 @@ "OptionNoTrailer": "No Trailer", "OptionNoThemeSong": "No Theme Song", "OptionNoThemeVideo": "No Theme Video", - "LabelOneTimeDonationAmount": "Donation amount:" + "LabelOneTimeDonationAmount": "Donation amount:", + "OptionActor": "Actor", + "OptionComposer": "Composer", + "OptionDirector": "Director", + "OptionGuestStar": "Guest star", + "OptionProducer": "Producer", + "OptionWriter": "Writer" } diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 7286846db..3558922d8 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -44,7 +44,6 @@ namespace MediaBrowser.Server.Implementations.Notifications GetConfiguration().GetOptions(notificationType); var users = GetUserIds(request, options) - .Except(request.ExcludeUserIds) .Select(i => _userManager.GetUserById(new Guid(i))); var title = GetTitle(request, options); diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 3f023c5ef..e843c6298 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.426 + 3.0.427 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 908d06954..90a66b3c7 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.426 + 3.0.427 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 6a9c203ce..a444d4c33 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.426 + 3.0.427 MediaBrowser.Model - Signed Edition Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 3cbad00b7..dadc51dff 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.426 + 3.0.427 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + -- cgit v1.2.3