From e55ab989d2077d70568965198139793ca7c116b4 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 18 Dec 2014 23:20:07 -0500 Subject: add more sync buttons --- MediaBrowser.Controller/Entities/BaseItem.cs | 2 + MediaBrowser.Controller/Entities/Movies/Movie.cs | 9 +++- MediaBrowser.Controller/Entities/TV/Episode.cs | 49 ++-------------------- MediaBrowser.Controller/Library/ILibraryManager.cs | 24 +++-------- 4 files changed, 18 insertions(+), 66 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ed950b1c5..1d57c46e6 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -45,6 +45,8 @@ namespace MediaBrowser.Controller.Entities /// public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" }; + public static readonly List SupportedImageExtensionsList = SupportedImageExtensions.ToList(); + /// /// The trailer folder name /// diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index e749d89e4..30bf0fefc 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -153,7 +153,14 @@ namespace MediaBrowser.Controller.Entities.Movies public MovieInfo GetLookupInfo() { - return GetItemLookupInfo(); + var info = GetItemLookupInfo(); + + if (!IsInMixedFolder) + { + info.Name = System.IO.Path.GetFileName(ContainingFolderPath); + } + + return info; } public override bool BeforeMetadataRefresh() diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index cc0fc6812..e270bbdf3 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System; @@ -301,51 +300,9 @@ namespace MediaBrowser.Controller.Entities.TV { var hasChanges = base.BeforeMetadataRefresh(); - var locationType = LocationType; - if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) + if (LibraryManager.FillMissingEpisodeNumbersFromPath(this)) { - if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) - { - IndexNumber = LibraryManager.GetEpisodeNumberFromFile(Path, true); - - // If a change was made record it - if (IndexNumber.HasValue) - { - hasChanges = true; - } - } - - if (!IndexNumberEnd.HasValue && !string.IsNullOrEmpty(Path)) - { - IndexNumberEnd = LibraryManager.GetEndingEpisodeNumberFromFile(Path); - - // If a change was made record it - if (IndexNumberEnd.HasValue) - { - hasChanges = true; - } - } - } - - if (!ParentIndexNumber.HasValue) - { - var season = Season; - - if (season != null) - { - ParentIndexNumber = season.IndexNumber; - } - - if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path)) - { - ParentIndexNumber = LibraryManager.GetSeasonNumberFromEpisodeFile(Path); - } - - // If a change was made record it - if (ParentIndexNumber.HasValue) - { - hasChanges = true; - } + hasChanges = true; } return hasChanges; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 33dea4dca..6d8f89226 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Sorting; @@ -340,26 +341,11 @@ namespace MediaBrowser.Controller.Library int? GetSeasonNumberFromPath(string path); /// - /// Gets the season number from episode file. + /// Fills the missing episode numbers from path. /// - /// The path. - /// System.Nullable<System.Int32>. - int? GetSeasonNumberFromEpisodeFile(string path); - - /// - /// Gets the ending episode number from file. - /// - /// The path. - /// System.Nullable<System.Int32>. - int? GetEndingEpisodeNumberFromFile(string path); - - /// - /// Gets the episode number from file. - /// - /// The path. - /// if set to true [consider seasonless]. - /// System.Nullable<System.Int32>. - int? GetEpisodeNumberFromFile(string path, bool considerSeasonless); + /// The episode. + /// true if XXXX, false otherwise. + bool FillMissingEpisodeNumbersFromPath(Episode episode); /// /// Parses the name. -- cgit v1.2.3 From 8807e80d0a04cf0c13a2113fab9917065cb0fdd9 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 20 Dec 2014 01:06:27 -0500 Subject: start using user policy --- MediaBrowser.Api/Library/LibraryService.cs | 4 +- MediaBrowser.Api/LiveTv/LiveTvService.cs | 2 +- MediaBrowser.Api/NotificationsService.cs | 2 +- MediaBrowser.Api/Playback/BaseStreamingService.cs | 48 ++++-- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 2 +- MediaBrowser.Api/Playback/Hls/MpegDashService.cs | 2 +- .../Playback/Progressive/AudioService.cs | 2 +- .../Playback/Progressive/VideoService.cs | 2 +- MediaBrowser.Api/Session/SessionsService.cs | 4 +- MediaBrowser.Api/UserService.cs | 72 +++++---- MediaBrowser.Controller/Channels/Channel.cs | 2 +- .../Channels/ChannelAudioItem.cs | 5 +- .../Channels/ChannelFolderItem.cs | 3 +- .../Channels/ChannelVideoItem.cs | 3 +- MediaBrowser.Controller/Entities/Audio/Audio.cs | 3 +- .../Entities/Audio/MusicAlbum.cs | 3 +- .../Entities/Audio/MusicArtist.cs | 3 +- MediaBrowser.Controller/Entities/BaseItem.cs | 11 +- MediaBrowser.Controller/Entities/Book.cs | 3 +- MediaBrowser.Controller/Entities/Folder.cs | 4 +- MediaBrowser.Controller/Entities/Game.cs | 3 +- MediaBrowser.Controller/Entities/GameSystem.cs | 3 +- MediaBrowser.Controller/Entities/Movies/BoxSet.cs | 3 +- MediaBrowser.Controller/Entities/Movies/Movie.cs | 3 +- MediaBrowser.Controller/Entities/MusicVideo.cs | 3 +- MediaBrowser.Controller/Entities/Photo.cs | 5 +- MediaBrowser.Controller/Entities/PhotoAlbum.cs | 5 +- MediaBrowser.Controller/Entities/TV/Episode.cs | 3 +- MediaBrowser.Controller/Entities/TV/Season.cs | 3 +- MediaBrowser.Controller/Entities/TV/Series.cs | 3 +- MediaBrowser.Controller/Entities/Trailer.cs | 3 +- MediaBrowser.Controller/Entities/User.cs | 72 ++------- MediaBrowser.Controller/Entities/UserView.cs | 3 +- MediaBrowser.Controller/Library/IUserManager.cs | 22 ++- .../LiveTv/LiveTvAudioRecording.cs | 3 +- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 3 +- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 3 +- .../LiveTv/LiveTvVideoRecording.cs | 3 +- MediaBrowser.Controller/LiveTv/RecordingGroup.cs | 3 +- .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + .../Configuration/UserConfiguration.cs | 13 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + MediaBrowser.Model/Users/UserPolicy.cs | 63 +++++++- .../Channels/ChannelDownloadScheduledTask.cs | 2 +- .../Connect/ConnectManager.cs | 35 +++-- .../HttpServer/HttpListenerHost.cs | 4 +- .../HttpServer/Security/AuthService.cs | 8 +- .../Library/Resolvers/Audio/MusicAlbumResolver.cs | 18 +-- .../Library/Resolvers/Audio/MusicArtistResolver.cs | 18 +-- .../Library/Resolvers/FolderResolver.cs | 50 +------ .../Library/Resolvers/Movies/MovieResolver.cs | 6 - .../Library/Resolvers/PhotoAlbumResolver.cs | 12 +- .../Library/Resolvers/SpecialFolderResolver.cs | 79 ++++++++++ .../Library/Resolvers/TV/SeriesResolver.cs | 16 +- .../Library/UserManager.cs | 163 +++++++++++++++++---- .../LiveTv/LiveTvManager.cs | 4 +- .../Localization/JavaScript/javascript.json | 9 +- .../Localization/Server/server.json | 1 - .../MediaBrowser.Server.Implementations.csproj | 1 + .../Notifications/NotificationManager.cs | 2 +- .../Sync/SyncManager.cs | 3 +- .../Sync/SyncRepository.cs | 13 +- .../ApplicationHost.cs | 2 +- .../MediaBrowser.WebDashboard.csproj | 9 -- 66 files changed, 546 insertions(+), 323 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 5cb007f8f..e85f2cbf9 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -479,14 +479,14 @@ namespace MediaBrowser.Api.Library } else if (item is ILiveTvRecording) { - if (!user.Configuration.EnableLiveTvManagement) + if (!user.Policy.EnableLiveTvManagement) { throw new UnauthorizedAccessException(); } } else { - if (!user.Configuration.EnableContentDeletion) + if (!user.Policy.EnableContentDeletion) { throw new UnauthorizedAccessException(); } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 3afe72866..f3dcf57e0 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -319,7 +319,7 @@ namespace MediaBrowser.Api.LiveTv throw new UnauthorizedAccessException("Anonymous live tv management is not allowed."); } - if (!user.Configuration.EnableLiveTvManagement) + if (!user.Policy.EnableLiveTvManagement) { throw new UnauthorizedAccessException("The current user does not have permission to manage live tv."); } diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs index 69f1f3489..5103d1b5c 100644 --- a/MediaBrowser.Api/NotificationsService.cs +++ b/MediaBrowser.Api/NotificationsService.cs @@ -135,7 +135,7 @@ namespace MediaBrowser.Api Level = request.Level, Name = request.Name, Url = request.Url, - UserIds = _userManager.Users.Where(i => i.Configuration.IsAdministrator).Select(i => i.Id.ToString("N")).ToList() + UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id.ToString("N")).ToList() }; await _notificationManager.SendNotification(notification, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 1a8c1d849..203a62dfc 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -202,6 +202,10 @@ namespace MediaBrowser.Api.Playback { args += " -map -0:s"; } + else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) + { + args += " -map 1:0 -sn"; + } return args; } @@ -273,7 +277,7 @@ namespace MediaBrowser.Api.Playback // Recommended per docs return Math.Max(Environment.ProcessorCount - 1, 2); } - + // Use more when this is true. -re will keep cpu usage under control if (state.ReadInputAtNativeFramerate) { @@ -666,9 +670,18 @@ namespace MediaBrowser.Api.Playback videoSizeParam = string.Format(",scale={0}:{1}", state.VideoStream.Width.Value.ToString(UsCulture), state.VideoStream.Height.Value.ToString(UsCulture)); } - return string.Format(" -filter_complex \"[0:{0}]format=yuva444p{3},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{1}] [sub] overlay{2}\"", - state.SubtitleStream.Index, - state.VideoStream.Index, + var mapPrefix = state.SubtitleStream.IsExternal ? + 1 : + 0; + + var subtitleStreamIndex = state.SubtitleStream.IsExternal + ? 0 + : state.SubtitleStream.Index; + + return string.Format(" -filter_complex \"[{0}:{1}]format=yuva444p{4},lut=u=128:v=128:y=gammaval(.3)[sub] ; [0:{2}] [sub] overlay{3}\"", + mapPrefix.ToString(UsCulture), + subtitleStreamIndex.ToString(UsCulture), + state.VideoStream.Index.ToString(UsCulture), outputSizeParam, videoSizeParam); } @@ -812,6 +825,21 @@ namespace MediaBrowser.Api.Playback /// The state. /// System.String. protected string GetInputArgument(string transcodingJobId, StreamState state) + { + var arg = "-i " + GetInputPathArgument(transcodingJobId, state); + + if (state.SubtitleStream != null) + { + if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) + { + arg += " -i " + state.SubtitleStream.Path; + } + } + + return arg; + } + + private string GetInputPathArgument(string transcodingJobId, StreamState state) { if (state.InputProtocol == MediaProtocol.File && state.RunTimeTicks.HasValue && @@ -883,7 +911,7 @@ namespace MediaBrowser.Api.Playback state.InputProtocol = streamInfo.Protocol; await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false); - + AttachMediaStreamInfo(state, streamInfo, state.VideoRequest, state.RequestedUrl); checkCodecs = true; } @@ -913,8 +941,8 @@ namespace MediaBrowser.Api.Playback /// The cancellation token source. /// The working directory. /// Task. - protected async Task StartFfMpeg(StreamState state, - string outputPath, + protected async Task StartFfMpeg(StreamState state, + string outputPath, CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { @@ -1103,7 +1131,7 @@ namespace MediaBrowser.Api.Playback if (scale.HasValue) { long val; - + if (long.TryParse(size, NumberStyles.Any, UsCulture, out val)) { bytesTranscoded = val * scale.Value; @@ -1642,7 +1670,7 @@ namespace MediaBrowser.Api.Playback if (string.IsNullOrEmpty(container)) { - container = request.Static ? + container = request.Static ? state.InputContainer : (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); } @@ -1717,7 +1745,7 @@ namespace MediaBrowser.Api.Playback AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest, requestedUrl); } - + private void AttachMediaStreamInfo(StreamState state, List mediaStreams, VideoStreamRequest videoRequest, diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index c2a9b963c..94198d974 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -239,7 +239,7 @@ namespace MediaBrowser.Api.Playback.Hls "hls/" + Path.GetFileNameWithoutExtension(outputPath)); } - var args = string.Format("{0} {1} -i {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"", + var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"", itsOffset, inputModifier, GetInputArgument(transcodingJobId, state), diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 7903724e8..489259334 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -677,7 +677,7 @@ namespace MediaBrowser.Api.Playback.Hls // If isEncoding is true we're actually starting ffmpeg var startNumberParam = isEncoding ? GetStartNumber(state).ToString(UsCulture) : "0"; - var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"", + var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"", inputModifier, GetInputArgument(transcodingJobId, state), threads, diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs index ca46df05d..e91ed98d1 100644 --- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs @@ -627,7 +627,7 @@ namespace MediaBrowser.Api.Playback.Hls var segmentFilename = Path.GetFileNameWithoutExtension(outputPath) + "%03d" + GetSegmentFileExtension(state); - var args = string.Format("{0} -i {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}", + var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f ssegment -segment_time {6} -segment_list_size {8} -segment_list \"{9}\" {10}", inputModifier, GetInputArgument(transcodingJobId, state), threads, diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index ae592c428..725526ecd 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"", + return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"", inputModifier, GetInputArgument(transcodingJobId, state), threads, diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index a64866d68..fb2d30732 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"", + return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"", inputModifier, GetInputArgument(transcodingJobId, state), keyFrame, diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs index d2881893b..4f47b9f54 100644 --- a/MediaBrowser.Api/Session/SessionsService.cs +++ b/MediaBrowser.Api/Session/SessionsService.cs @@ -373,12 +373,12 @@ namespace MediaBrowser.Api.Session var user = _userManager.GetUserById(request.ControllableByUserId.Value); - if (!user.Configuration.EnableRemoteControlOfOtherUsers) + if (!user.Policy.EnableRemoteControlOfOtherUsers) { result = result.Where(i => i.ContainsUser(request.ControllableByUserId.Value)); } - if (!user.Configuration.EnableSharedDeviceControl) + if (!user.Policy.EnableSharedDeviceControl) { result = result.Where(i => !i.UserId.HasValue); } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 9c8216a03..760cb07fd 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -264,12 +264,12 @@ namespace MediaBrowser.Api if (request.IsDisabled.HasValue) { - users = users.Where(i => i.Configuration.IsDisabled == request.IsDisabled.Value); + users = users.Where(i => i.Policy.IsDisabled == request.IsDisabled.Value); } if (request.IsHidden.HasValue) { - users = users.Where(i => i.Configuration.IsHidden == request.IsHidden.Value); + users = users.Where(i => i.Policy.IsHidden == request.IsHidden.Value); } if (request.IsGuest.HasValue) @@ -445,39 +445,13 @@ namespace MediaBrowser.Api var user = _userManager.GetUserById(id); - // If removing admin access - if (!dtoUser.Configuration.IsAdministrator && user.Configuration.IsAdministrator) - { - if (_userManager.Users.Count(i => i.Configuration.IsAdministrator) == 1) - { - throw new ArgumentException("There must be at least one user in the system with administrative access."); - } - } - - // If disabling - if (dtoUser.Configuration.IsDisabled && user.Configuration.IsAdministrator) - { - throw new ArgumentException("Administrators cannot be disabled."); - } - - // If disabling - if (dtoUser.Configuration.IsDisabled && !user.Configuration.IsDisabled) - { - if (_userManager.Users.Count(i => !i.Configuration.IsDisabled) == 1) - { - throw new ArgumentException("There must be at least one enabled user in the system."); - } - - await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false); - } - var task = user.Name.Equals(dtoUser.Name, StringComparison.Ordinal) ? _userManager.UpdateUser(user) : _userManager.RenameUser(user, dtoUser.Name); await task.ConfigureAwait(false); - user.UpdateConfiguration(dtoUser.Configuration); + await _userManager.UpdateConfiguration(dtoUser.Id, dtoUser.Configuration); } /// @@ -515,14 +489,48 @@ namespace MediaBrowser.Api public void Post(UpdateUserConfiguration request) { - var user = _userManager.GetUserById(request.Id); - user.UpdateConfiguration(request); + var task = _userManager.UpdateConfiguration(request.Id, request); + + Task.WaitAll(task); } public void Post(UpdateUserPolicy request) { - var task = _userManager.UpdateUserPolicy(request.Id, request); + var task = UpdateUserPolicy(request); Task.WaitAll(task); } + + private async Task UpdateUserPolicy(UpdateUserPolicy request) + { + var user = _userManager.GetUserById(request.Id); + + // If removing admin access + if (!request.IsAdministrator && user.Policy.IsAdministrator) + { + if (_userManager.Users.Count(i => i.Policy.IsAdministrator) == 1) + { + throw new ArgumentException("There must be at least one user in the system with administrative access."); + } + } + + // If disabling + if (request.IsDisabled && user.Policy.IsAdministrator) + { + throw new ArgumentException("Administrators cannot be disabled."); + } + + // If disabling + if (request.IsDisabled && !user.Policy.IsDisabled) + { + if (_userManager.Users.Count(i => !i.Policy.IsDisabled) == 1) + { + throw new ArgumentException("There must be at least one enabled user in the system."); + } + + await _sessionMananger.RevokeUserTokens(user.Id.ToString("N")).ConfigureAwait(false); + } + + await _userManager.UpdateUserPolicy(request.Id, request).ConfigureAwait(false); + } } } diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index f618c8a25..5a9fc3322 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Channels public override bool IsVisible(User user) { - if (user.Configuration.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { return false; } diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs index ede366dab..896d598bb 100644 --- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Linq; using System.Threading; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -25,8 +26,8 @@ namespace MediaBrowser.Controller.Channels public string OriginalImageUrl { get; set; } public List ChannelMediaSources { get; set; } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); } diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs index 5362cc195..8482e38df 100644 --- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -5,6 +5,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Querying; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -20,7 +21,7 @@ namespace MediaBrowser.Controller.Channels public string OriginalImageUrl { get; set; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. return false; diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs index 72e2b110a..f0eafcbdf 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.Channels return ExternalId; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 447328ea1..623ae8968 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -173,7 +174,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 1f7c62de0..90edfcce7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -154,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 2d9e052b1..e9cc13c66 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -114,7 +115,7 @@ namespace MediaBrowser.Controller.Entities.Audio return "Artist-" + item.Name; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1d57c46e6..aea04187d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -595,7 +596,7 @@ namespace MediaBrowser.Controller.Entities /// PlayAccess. public PlayAccess GetPlayAccess(User user) { - if (!user.Configuration.EnableMediaPlayback) + if (!user.Policy.EnableMediaPlayback) { return PlayAccess.None; } @@ -987,7 +988,7 @@ namespace MediaBrowser.Controller.Entities return false; } - var maxAllowedRating = user.Configuration.MaxParentalRating; + var maxAllowedRating = user.Policy.MaxParentalRating; if (maxAllowedRating == null) { @@ -1003,7 +1004,7 @@ namespace MediaBrowser.Controller.Entities if (string.IsNullOrWhiteSpace(rating)) { - return !GetBlockUnratedValue(user.Configuration); + return !GetBlockUnratedValue(user.Policy); } var value = LocalizationManager.GetRatingLevel(rating); @@ -1023,7 +1024,7 @@ namespace MediaBrowser.Controller.Entities if (hasTags != null) { - if (user.Configuration.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) + if (user.Policy.BlockedTags.Any(i => hasTags.Tags.Contains(i, StringComparer.OrdinalIgnoreCase))) { return false; } @@ -1037,7 +1038,7 @@ namespace MediaBrowser.Controller.Entities /// /// The configuration. /// true if XXXX, false otherwise. - protected virtual bool GetBlockUnratedValue(UserConfiguration config) + protected virtual bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index ea7ecfb4a..381b2101d 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -36,7 +37,7 @@ namespace MediaBrowser.Controller.Entities Tags = new List(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Book); } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 87ad9c380..fba5d082d 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -303,10 +303,10 @@ namespace MediaBrowser.Controller.Entities { if (this is ICollectionFolder) { - if (user.Configuration.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || + if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || // Backwards compatibility - user.Configuration.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) + user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) { return false; } diff --git a/MediaBrowser.Controller/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index e4d032359..bf32d3e63 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -108,7 +109,7 @@ namespace MediaBrowser.Controller.Entities return base.GetDeletePaths(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Game); } diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index f2fec4397..758498977 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using System; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -43,7 +44,7 @@ namespace MediaBrowser.Controller.Entities return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. Determine by game return false; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 9dc600675..6563da8de 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { @@ -67,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// The display order. public string DisplayOrder { get; set; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Movie); } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 30bf0fefc..4c1aac700 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { @@ -146,7 +147,7 @@ namespace MediaBrowser.Controller.Entities.Movies return itemsChanged; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Movie); } diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index d7cd62aa6..4ca8cf1c5 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -80,7 +81,7 @@ namespace MediaBrowser.Controller.Entities return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 367db5dcb..a3d892181 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Drawing; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -69,8 +70,8 @@ namespace MediaBrowser.Controller.Entities public double? Longitude { get; set; } public double? Altitude { get; set; } public int? IsoSpeedRating { get; set; } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index 982b1ef17..24ebf8815 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -1,6 +1,7 @@ using MediaBrowser.Model.Configuration; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -22,8 +23,8 @@ namespace MediaBrowser.Controller.Entities return true; } } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index e270bbdf3..6b6f07d4c 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -274,7 +275,7 @@ namespace MediaBrowser.Controller.Entities.TV return new[] { Path }; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Series); } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2df90244c..ceddbbc3b 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -7,6 +7,7 @@ using MediaBrowser.Model.Querying; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -249,7 +250,7 @@ namespace MediaBrowser.Controller.Entities.TV return GetEpisodes(user); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. Let either the entire series rating or episode rating determine it return false; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 4c0d1fdfb..8e43c45e0 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -246,7 +247,7 @@ namespace MediaBrowser.Controller.Entities.TV }); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Series); } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index bb165d790..7a1eef8db 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -98,7 +99,7 @@ namespace MediaBrowser.Controller.Entities return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Trailer); } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 3dfc8cc7d..626afcfdf 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; @@ -107,37 +106,27 @@ namespace MediaBrowser.Controller.Entities /// The last activity date. public DateTime? LastActivityDate { get; set; } - /// - /// The _configuration - /// - private UserConfiguration _configuration; - /// - /// The _configuration initialized - /// - private bool _configurationInitialized; - /// - /// The _configuration sync lock - /// - private object _configurationSyncLock = new object(); - /// - /// Gets the user's configuration - /// - /// The configuration. + private UserConfiguration _config; + private readonly object _configSyncLock = new object(); [IgnoreDataMember] public UserConfiguration Configuration { get { - // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => (UserConfiguration)ConfigurationHelper.GetXmlConfiguration(typeof(UserConfiguration), ConfigurationFilePath, XmlSerializer)); - return _configuration; - } - private set - { - _configuration = value; + if (_config == null) + { + lock (_configSyncLock) + { + if (_config == null) + { + _config = UserManager.GetUserConfiguration(this); + } + } + } - _configurationInitialized = value != null; + return _config; } + set { _config = value; } } private UserPolicy _policy; @@ -256,35 +245,6 @@ namespace MediaBrowser.Controller.Entities return System.IO.Path.Combine(parentPath, Id.ToString("N")); } - /// - /// Gets the path to the user's configuration file - /// - /// The configuration file path. - [IgnoreDataMember] - public string ConfigurationFilePath - { - get - { - return System.IO.Path.Combine(ConfigurationDirectoryPath, "config.xml"); - } - } - - /// - /// Updates the configuration. - /// - /// The config. - /// config - public void UpdateConfiguration(UserConfiguration config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - - Configuration = config; - UserManager.UpdateConfiguration(this, Configuration); - } - public bool IsParentalScheduleAllowed() { return IsParentalScheduleAllowed(DateTime.UtcNow); @@ -292,7 +252,7 @@ namespace MediaBrowser.Controller.Entities public bool IsParentalScheduleAllowed(DateTime date) { - var schedules = Configuration.AccessSchedules; + var schedules = Policy.AccessSchedules; if (schedules.Length == 0) { diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 926ffa19c..0364ff678 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -63,7 +63,8 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos + CollectionType.Photos, + string.Empty }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 9dc16ba4d..f7fbc9c20 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -35,13 +35,6 @@ namespace MediaBrowser.Controller.Library event EventHandler> UserConfigurationUpdated; event EventHandler> UserPasswordChanged; - /// - /// Updates the configuration. - /// - /// The user. - /// The new configuration. - void UpdateConfiguration(User user, UserConfiguration newConfiguration); - /// /// Gets a User by Id /// @@ -172,6 +165,21 @@ namespace MediaBrowser.Controller.Library /// UserPolicy. UserPolicy GetUserPolicy(User user); + /// + /// Gets the user configuration. + /// + /// The user. + /// UserConfiguration. + UserConfiguration GetUserConfiguration(User user); + + /// + /// Updates the configuration. + /// + /// The user identifier. + /// The new configuration. + /// Task. + Task UpdateConfiguration(string userId, UserConfiguration newConfiguration); + /// /// Updates the user policy. /// diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index 9f8d67a48..b95d67ad8 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index df118b25f..de72accff 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvChannel); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 266eaabee..29b23a551 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -6,6 +6,7 @@ using System; using System.Threading; using System.Threading.Tasks; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -199,7 +200,7 @@ namespace MediaBrowser.Controller.LiveTv return ItemRepository.SaveItem(this, cancellationToken); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index 66de81213..6fc985643 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs index 7bd810b8d..d7250d9d2 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs @@ -1,11 +1,12 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { public class RecordingGroup : Folder { - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. return false; diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 2629dac8b..8994b16c3 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1034,6 +1034,9 @@ Sync\SyncDialogOptions.cs + + Sync\SyncItem.cs + Sync\SyncJob.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 4840777a5..fbde4c92d 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -993,6 +993,9 @@ Sync\SyncDialogOptions.cs + + Sync\SyncItem.cs + Sync\SyncJob.cs diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index f0a27a2b9..01f90a0ba 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -42,6 +42,10 @@ namespace MediaBrowser.Model.Configuration /// true if this instance is hidden; otherwise, false. public bool IsHidden { get; set; } + /// + /// Gets or sets a value indicating whether this instance is disabled. + /// + /// true if this instance is disabled; otherwise, false. public bool IsDisabled { get; set; } public bool DisplayMissingEpisodes { get; set; } @@ -74,9 +78,6 @@ namespace MediaBrowser.Model.Configuration public string[] OrderedViews { get; set; } - public bool SyncConnectName { get; set; } - public bool SyncConnectImage { get; set; } - public bool IncludeTrailersInSuggestions { get; set; } public bool EnableCinemaMode { get; set; } @@ -87,7 +88,9 @@ namespace MediaBrowser.Model.Configuration public string[] LatestItemsExcludes { get; set; } public string[] BlockedTags { get; set; } - + + public bool ValuesMigratedToPolicy { get; set; } + /// /// Initializes a new instance of the class. /// @@ -110,8 +113,6 @@ namespace MediaBrowser.Model.Configuration ExcludeFoldersFromGrouping = new string[] { }; DisplayCollectionsView = true; - SyncConnectName = true; - SyncConnectImage = true; IncludeTrailersInSuggestions = true; EnableCinemaMode = true; EnableUserPreferenceAccess = true; diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b81b4c1fd..47bb62a32 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -366,6 +366,7 @@ + diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index b458e2854..4d09ae8e8 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -1,8 +1,69 @@ - +using MediaBrowser.Model.Configuration; + namespace MediaBrowser.Model.Users { public class UserPolicy { + /// + /// Gets or sets a value indicating whether this instance is administrator. + /// + /// true if this instance is administrator; otherwise, false. + public bool IsAdministrator { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is hidden. + /// + /// true if this instance is hidden; otherwise, false. + public bool IsHidden { get; set; } + + /// + /// Gets or sets a value indicating whether this instance is disabled. + /// + /// true if this instance is disabled; otherwise, false. + public bool IsDisabled { get; set; } + + /// + /// Gets or sets the max parental rating. + /// + /// The max parental rating. + public int? MaxParentalRating { get; set; } + + public string[] BlockedTags { get; set; } + public bool EnableUserPreferenceAccess { get; set; } + public AccessSchedule[] AccessSchedules { get; set; } + public UnratedItem[] BlockUnratedItems { get; set; } + public string[] BlockedMediaFolders { get; set; } + public string[] BlockedChannels { get; set; } + public bool EnableRemoteControlOfOtherUsers { get; set; } + public bool EnableSharedDeviceControl { get; set; } + + public bool EnableLiveTvManagement { get; set; } + public bool EnableLiveTvAccess { get; set; } + + public bool EnableMediaPlayback { get; set; } + public bool EnableContentDeletion { get; set; } + + /// + /// Gets or sets a value indicating whether [enable synchronize]. + /// + /// true if [enable synchronize]; otherwise, false. public bool EnableSync { get; set; } + + public UserPolicy() + { + EnableLiveTvManagement = true; + EnableMediaPlayback = true; + EnableLiveTvAccess = true; + EnableSharedDeviceControl = true; + + BlockedMediaFolders = new string[] { }; + BlockedTags = new string[] { }; + BlockedChannels = new string[] { }; + BlockUnratedItems = new UnratedItem[] { }; + + EnableUserPreferenceAccess = true; + + AccessSchedules = new AccessSchedule[] { }; + } } } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index bfdbb8ccf..ce939aeb4 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Channels public static string GetUserDistinctValue(User user) { - var channels = user.Configuration.BlockedChannels + var channels = user.Policy.BlockedChannels .OrderBy(i => i) .ToList(); diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index cbd75cdeb..376dc3548 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -432,9 +432,7 @@ namespace MediaBrowser.Server.Implementations.Connect await user.UpdateToRepository(ItemUpdateType.MetadataEdit, CancellationToken.None).ConfigureAwait(false); - user.Configuration.SyncConnectImage = false; - user.Configuration.SyncConnectName = false; - _userManager.UpdateConfiguration(user, user.Configuration); + await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration); await RefreshAuthorizationsInternal(false, CancellationToken.None).ConfigureAwait(false); @@ -800,23 +798,21 @@ namespace MediaBrowser.Server.Implementations.Connect await _userManager.UpdateUser(user).ConfigureAwait(false); - user.Configuration.SyncConnectImage = true; - user.Configuration.SyncConnectName = true; - user.Configuration.IsHidden = true; - user.Configuration.EnableLiveTvManagement = false; - user.Configuration.EnableContentDeletion = false; - user.Configuration.EnableRemoteControlOfOtherUsers = false; - user.Configuration.EnableSharedDeviceControl = false; - user.Configuration.IsAdministrator = false; + user.Policy.IsHidden = true; + user.Policy.EnableLiveTvManagement = false; + user.Policy.EnableContentDeletion = false; + user.Policy.EnableRemoteControlOfOtherUsers = false; + user.Policy.EnableSharedDeviceControl = false; + user.Policy.IsAdministrator = false; if (currentPendingEntry != null) { - user.Configuration.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv; - user.Configuration.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries; - user.Configuration.BlockedChannels = currentPendingEntry.ExcludedChannels; + user.Policy.EnableLiveTvAccess = currentPendingEntry.EnableLiveTv; + user.Policy.BlockedMediaFolders = currentPendingEntry.ExcludedLibraries; + user.Policy.BlockedChannels = currentPendingEntry.ExcludedChannels; } - _userManager.UpdateConfiguration(user, user.Configuration); + await _userManager.UpdateConfiguration(user.Id.ToString("N"), user.Configuration); } } else if (string.Equals(connectEntry.AcceptStatus, "waiting", StringComparison.OrdinalIgnoreCase)) @@ -844,7 +840,7 @@ namespace MediaBrowser.Server.Implementations.Connect { var users = _userManager.Users .Where(i => !string.IsNullOrEmpty(i.ConnectUserId) && - (i.Configuration.SyncConnectImage || i.Configuration.SyncConnectName)) + (i.ConnectLinkType.HasValue && i.ConnectLinkType.Value == UserLinkType.Guest)) .ToList(); foreach (var user in users) @@ -857,7 +853,10 @@ namespace MediaBrowser.Server.Implementations.Connect continue; } - if (user.Configuration.SyncConnectName) + var syncConnectName = true; + var syncConnectImage = true; + + if (syncConnectName) { var changed = !string.Equals(authorization.UserName, user.Name, StringComparison.OrdinalIgnoreCase); @@ -867,7 +866,7 @@ namespace MediaBrowser.Server.Implementations.Connect } } - if (user.Configuration.SyncConnectImage) + if (syncConnectImage) { var imageUrl = authorization.UserImageUrl; diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 56e2e5247..b754a943a 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -206,8 +206,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First()); _listener = _supportsNativeWebSocket && NativeWebSocket.IsSupported - ? _listener = new HttpListenerServer(_logger, OnRequestReceived) - //? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) + //? _listener = new HttpListenerServer(_logger, OnRequestReceived) + ? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) : _listener = new WebSocketSharpListener(_logger, OnRequestReceived); _listener.WebSocketHandler = WebSocketHandler; diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index 57d87749c..13563ce19 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (user != null) { - if (user.Configuration.IsDisabled) + if (user.Policy.IsDisabled) { throw new SecurityException("User account has been disabled.") { @@ -76,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security }; } - if (!user.Configuration.IsAdministrator && + if (!user.Policy.IsAdministrator && !authAttribtues.EscapeParentalControl && !user.IsParentalScheduleAllowed()) { @@ -135,7 +135,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Configuration.IsAdministrator) + if (user == null || !user.Policy.IsAdministrator) { throw new SecurityException("User does not have admin access.") { @@ -145,7 +145,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security } if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Configuration.EnableContentDeletion) + if (user == null || !user.Policy.EnableContentDeletion) { throw new SecurityException("User does not have delete access.") { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index f32ed2b20..05ff270fc 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -37,7 +37,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio /// The priority. public override ResolverPriority Priority { - get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one + get + { + // Behind special folder resolver + return ResolverPriority.Second; + } } /// @@ -49,21 +53,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio { if (!args.IsDirectory) return null; - //Avoid mis-identifying top folders - if (args.Parent == null) return null; + // Avoid mis-identifying top folders if (args.Parent.IsRoot) return null; if (args.HasParent()) return null; - // Optimization - if (args.HasParent() || args.HasParent() || args.HasParent()) - { - return null; - } - var collectionType = args.GetCollectionType(); - var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, - StringComparison.OrdinalIgnoreCase); + var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not music, don't allow it. if (!isMusicMediaFolder) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 71b6c0843..edbc87415 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -34,7 +34,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio /// The priority. public override ResolverPriority Priority { - get { return ResolverPriority.Third; } // we need to be ahead of the generic folder resolver but behind the movie one + get + { + // Behind special folder resolver + return ResolverPriority.Second; + } } /// @@ -46,8 +50,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio { if (!args.IsDirectory) return null; - //Avoid mis-identifying top folders - if (args.Parent == null) return null; + // Avoid mis-identifying top folders if (args.Parent.IsRoot) return null; // Don't allow nested artists @@ -56,16 +59,9 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio return null; } - // Optimization - if (args.HasParent() || args.HasParent() || args.HasParent()) - { - return null; - } - var collectionType = args.GetCollectionType(); - var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, - StringComparison.OrdinalIgnoreCase); + var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not music, it can't be a series if (!isMusicMediaFolder) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs index 166465f72..34237622d 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -1,10 +1,6 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; -using System; -using System.IO; -using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers { @@ -13,13 +9,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers /// public class FolderResolver : FolderResolver { - private readonly IFileSystem _fileSystem; - - public FolderResolver(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - /// /// Gets the priority. /// @@ -38,48 +27,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { if (args.IsDirectory) { - if (args.IsPhysicalRoot) - { - return new AggregateFolder(); - } - if (args.IsRoot) - { - return new UserRootFolder(); //if we got here and still a root - must be user root - } - if (args.IsVf) - { - return new CollectionFolder - { - CollectionType = GetCollectionType(args) - }; - } - return new Folder(); } return null; } - - private string GetCollectionType(ItemResolveArgs args) - { - return args.FileSystemChildren - .Where(i => - { - - try - { - return (i.Attributes & FileAttributes.Directory) != FileAttributes.Directory && - string.Equals(".collection", i.Extension, StringComparison.OrdinalIgnoreCase); - } - catch (IOException) - { - return false; - } - - }) - .Select(i => _fileSystem.GetFileNameWithoutExtension(i)) - .FirstOrDefault(); - } } /// diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 0e5ed1825..58b5dbc6a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -183,12 +183,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return FindMovie public class XmlSerializer : IXmlSerializer { + // Need to cache these + // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html + private readonly ConcurrentDictionary _serializers = + new ConcurrentDictionary(); + + private System.Xml.Serialization.XmlSerializer GetSerializer(Type type) + { + var key = type.FullName; + return _serializers.GetOrAdd(key, k => new System.Xml.Serialization.XmlSerializer(type)); + } + /// /// Serializes to writer. /// @@ -18,7 +30,7 @@ namespace MediaBrowser.Common.Implementations.Serialization private void SerializeToWriter(object obj, XmlTextWriter writer) { writer.Formatting = Formatting.Indented; - var netSerializer = new System.Xml.Serialization.XmlSerializer(obj.GetType()); + var netSerializer = GetSerializer(obj.GetType()); netSerializer.Serialize(writer, obj); } @@ -32,8 +44,7 @@ namespace MediaBrowser.Common.Implementations.Serialization { using (var reader = new XmlTextReader(stream)) { - var netSerializer = new System.Xml.Serialization.XmlSerializer(type); - + var netSerializer = GetSerializer(type); return netSerializer.Deserialize(reader); } } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index e8582a52a..2761aa5d7 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -708,7 +708,7 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected virtual IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { - var collectionType = LibraryManager.FindCollectionType(this); + var collectionType = LibraryManager.GetContentType(this); return LibraryManager.ResolvePaths(GetFileSystemChildren(directoryService), directoryService, this, collectionType); } diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 6d8f89226..7cdfb7788 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -259,8 +259,15 @@ namespace MediaBrowser.Controller.Library /// /// The item. /// System.String. - string FindCollectionType(BaseItem item); + string GetContentType(BaseItem item); + /// + /// Gets the type of the inherited content. + /// + /// The item. + /// System.String. + string GetInheritedContentType(BaseItem item); + /// /// Normalizes the root path list. /// diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index ec41ffe0b..f18c53cd3 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -464,6 +464,9 @@ Dto\MetadataEditorInfo.cs + + Dto\NameValuePair.cs + Dto\RatingType.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 01aaad2ac..f17215988 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -429,6 +429,9 @@ Dto\MetadataEditorInfo.cs + + Dto\NameValuePair.cs + Dto\RatingType.cs diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs index 66bdb8ce3..9bd15fc8f 100644 --- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs +++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs @@ -12,12 +12,16 @@ namespace MediaBrowser.Model.Dto public List Cultures { get; set; } public List ExternalIdInfos { get; set; } + public string ContentType { get; set; } + public List ContentTypeOptions { get; set; } + public MetadataEditorInfo() { ParentalRatingOptions = new List(); Countries = new List(); Cultures = new List(); ExternalIdInfos = new List(); + ContentTypeOptions = new List(); } } } diff --git a/MediaBrowser.Model/Dto/NameValuePair.cs b/MediaBrowser.Model/Dto/NameValuePair.cs new file mode 100644 index 000000000..2d55e8f2a --- /dev/null +++ b/MediaBrowser.Model/Dto/NameValuePair.cs @@ -0,0 +1,17 @@ + +namespace MediaBrowser.Model.Dto +{ + public class NameValuePair + { + /// + /// Gets or sets the name. + /// + /// The name. + public string Name { get; set; } + /// + /// Gets or sets the value. + /// + /// The value. + public string Value { get; set; } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 0dd5442ed..759c671e9 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -129,6 +129,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 9647461bf..ab50c30fb 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1546,12 +1546,17 @@ namespace MediaBrowser.Server.Implementations.Library return ItemRepository.RetrieveItem(id); } - /// - /// Finds the type of the collection. - /// - /// The item. - /// System.String. - public string FindCollectionType(BaseItem item) + public string GetContentType(BaseItem item) + { + return GetInheritedContentType(item); + } + + public string GetInheritedContentType(BaseItem item) + { + return GetTopFolderContentType(item); + } + + private string GetTopFolderContentType(BaseItem item) { while (!(item.Parent is AggregateFolder) && item.Parent != null) { diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 9bf06c50b..9a515d492 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -37,6 +37,18 @@ "ButtonOk": "Ok", "ButtonCancel": "Cancel", "ButtonNew": "New", + "FolderTypeMixed": "Mixed videos", + "FolderTypeMovies": "Movies", + "FolderTypeMusic": "Music", + "FolderTypeAdultVideos": "Adult videos", + "FolderTypePhotos": "Photos", + "FolderTypeMusicVideos": "Music videos", + "FolderTypeHomeVideos": "Home videos", + "FolderTypeGames": "Games", + "FolderTypeBooks": "Books", + "FolderTypeTvShows": "TV", + "FolderTypeInherit": "Inherit", + "LabelContentType": "Content type:", "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", -- cgit v1.2.3 From 97ae93fe5eb0f010db9835efd72954f31ccdd2cd Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 21 Dec 2014 14:40:37 -0500 Subject: add standalone EncodingOptions --- MediaBrowser.Api/ApiEntryPoint.cs | 19 +++-- MediaBrowser.Api/Playback/BaseStreamingService.cs | 11 +-- .../Configuration/BaseConfigurationManager.cs | 20 +++++- .../Configuration/IConfigurationFactory.cs | 5 ++ .../MediaBrowser.Controller.csproj | 3 - .../MediaEncoding/EncodingOptions.cs | 80 ---------------------- .../MediaEncoding/EncodingResult.cs | 13 ---- .../MediaEncoding/VideoEncodingOptions.cs | 26 ------- .../Configuration/EncodingConfigurationFactory.cs | 45 ++++++++++++ .../MediaBrowser.MediaEncoding.csproj | 1 + .../MediaBrowser.Model.Portable.csproj | 3 + .../MediaBrowser.Model.net35.csproj | 3 + .../Configuration/EncodingOptions.cs | 19 +++++ .../Configuration/ServerConfiguration.cs | 13 ---- MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + .../Configuration/ServerConfigurationManager.cs | 33 --------- 16 files changed, 113 insertions(+), 182 deletions(-) delete mode 100644 MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs delete mode 100644 MediaBrowser.Controller/MediaEncoding/EncodingResult.cs delete mode 100644 MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs create mode 100644 MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs create mode 100644 MediaBrowser.Model/Configuration/EncodingOptions.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 95f7ef694..a05d7d1b2 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -1,7 +1,9 @@ using MediaBrowser.Api.Playback; -using MediaBrowser.Controller; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; using System; @@ -33,7 +35,7 @@ namespace MediaBrowser.Api /// /// The application paths /// - private readonly IServerApplicationPaths _appPaths; + private readonly IServerConfigurationManager _config; private readonly ISessionManager _sessionManager; @@ -43,13 +45,13 @@ namespace MediaBrowser.Api /// Initializes a new instance of the class. /// /// The logger. - /// The application paths. /// The session manager. - public ApiEntryPoint(ILogger logger, IServerApplicationPaths appPaths, ISessionManager sessionManager) + /// The configuration. + public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config) { Logger = logger; - _appPaths = appPaths; _sessionManager = sessionManager; + _config = config; Instance = this; } @@ -73,12 +75,17 @@ namespace MediaBrowser.Api } } + public EncodingOptions GetEncodingOptions() + { + return _config.GetConfiguration("encoding"); + } + /// /// Deletes the encoded media cache. /// private void DeleteEncodedMediaCache() { - foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories) + foreach (var file in Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*", SearchOption.AllDirectories) .ToList()) { File.Delete(file); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 203a62dfc..683a1f962 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -249,7 +250,7 @@ namespace MediaBrowser.Api.Playback protected EncodingQuality GetQualitySetting() { - var quality = ServerConfigurationManager.Configuration.MediaEncodingQuality; + var quality = ApiEntryPoint.Instance.GetEncodingOptions().MediaEncodingQuality; if (quality == EncodingQuality.Auto) { @@ -310,7 +311,7 @@ namespace MediaBrowser.Api.Playback { get { - var lib = ServerConfigurationManager.Configuration.H264Encoder; + var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder; if (!string.IsNullOrWhiteSpace(lib)) { @@ -461,7 +462,7 @@ namespace MediaBrowser.Api.Playback { if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5) { - volParam = ",volume=" + ServerConfigurationManager.Configuration.DownMixAudioBoost.ToString(UsCulture); + volParam = ",volume=" + ApiEntryPoint.Instance.GetEncodingOptions().DownMixAudioBoost.ToString(UsCulture); } } @@ -953,7 +954,7 @@ namespace MediaBrowser.Api.Playback var transcodingId = Guid.NewGuid().ToString("N"); var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true); - if (ServerConfigurationManager.Configuration.EnableDebugEncodingLogging) + if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging) { commandLineArgs = "-loglevel debug " + commandLineArgs; } diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs index a061420d7..093010124 100644 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs @@ -233,13 +233,22 @@ namespace MediaBrowser.Common.Implementations.Configuration public void SaveConfiguration(string key, object configuration) { - var configurationType = GetConfigurationType(key); + var configurationStore = GetConfigurationStore(key); + var configurationType = configurationStore.ConfigurationType; if (configuration.GetType() != configurationType) { throw new ArgumentException("Expected configuration type is " + configurationType.Name); } + var validatingStore = configurationStore as IValidatingConfiguration; + if (validatingStore != null) + { + var currentConfiguration = GetConfiguration(key); + + validatingStore.Validate(currentConfiguration, configuration); + } + EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs { Key = key, @@ -267,9 +276,14 @@ namespace MediaBrowser.Common.Implementations.Configuration public Type GetConfigurationType(string key) { - return _configurationStores - .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)) + return GetConfigurationStore(key) .ConfigurationType; } + + private ConfigurationStore GetConfigurationStore(string key) + { + return _configurationStores + .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs index d418d0a42..6ed638536 100644 --- a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs +++ b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs @@ -14,4 +14,9 @@ namespace MediaBrowser.Common.Configuration public Type ConfigurationType { get; set; } } + + public interface IValidatingConfiguration + { + void Validate(object oldConfig, object newConfig); + } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index c198a58d4..3b9f3a5b2 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -198,16 +198,13 @@ - - - diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs deleted file mode 100644 index 26182ebc4..000000000 --- a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using MediaBrowser.Controller.Dlna; -using MediaBrowser.Model.Dlna; - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class EncodingOptions - { - /// - /// Gets or sets the item identifier. - /// - /// The item identifier. - public string ItemId { get; set; } - - /// - /// Gets or sets the media source identifier. - /// - /// The media source identifier. - public string MediaSourceId { get; set; } - - /// - /// Gets or sets the device profile. - /// - /// The device profile. - public DeviceProfile DeviceProfile { get; set; } - - /// - /// Gets or sets the output path. - /// - /// The output path. - public string OutputPath { get; set; } - - /// - /// Gets or sets the container. - /// - /// The container. - public string Container { get; set; } - - /// - /// Gets or sets the audio codec. - /// - /// The audio codec. - public string AudioCodec { get; set; } - - /// - /// Gets or sets the start time ticks. - /// - /// The start time ticks. - public long? StartTimeTicks { get; set; } - - /// - /// Gets or sets the maximum channels. - /// - /// The maximum channels. - public int? MaxAudioChannels { get; set; } - - /// - /// Gets or sets the channels. - /// - /// The channels. - public int? AudioChannels { get; set; } - - /// - /// Gets or sets the sample rate. - /// - /// The sample rate. - public int? AudioSampleRate { get; set; } - - /// - /// Gets or sets the bit rate. - /// - /// The bit rate. - public int? AudioBitRate { get; set; } - - /// - /// Gets or sets the maximum audio bit rate. - /// - /// The maximum audio bit rate. - public int? MaxAudioBitRate { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs b/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs deleted file mode 100644 index 75ee90e42..000000000 --- a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class EncodingResult - { - public string OutputPath { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs deleted file mode 100644 index 773f0ea46..000000000 --- a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class VideoEncodingOptions : EncodingOptions - { - public string VideoCodec { get; set; } - - public string VideoProfile { get; set; } - - public double? VideoLevel { get; set; } - - public int? VideoStreamIndex { get; set; } - - public int? AudioStreamIndex { get; set; } - - public int? SubtitleStreamIndex { get; set; } - - public int? MaxWidth { get; set; } - - public int? MaxHeight { get; set; } - - public int? Height { get; set; } - - public int? Width { get; set; } - } -} diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs new file mode 100644 index 000000000..17470d206 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs @@ -0,0 +1,45 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; +using System.Collections.Generic; +using System.IO; + +namespace MediaBrowser.MediaEncoding.Configuration +{ + public class EncodingConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new[] + { + new EncodingConfigurationStore() + }; + } + } + + public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration + { + public EncodingConfigurationStore() + { + ConfigurationType = typeof(EncodingOptions); + Key = "encoding"; + } + + public void Validate(object oldConfig, object newConfig) + { + var oldEncodingConfig = (EncodingOptions)oldConfig; + var newEncodingConfig = (EncodingOptions)newConfig; + + var newPath = newEncodingConfig.TranscodingTempPath; + + if (!string.IsNullOrWhiteSpace(newPath) + && !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath)) + { + // Validate + if (!Directory.Exists(newPath)) + { + throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath)); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 6f59b7bec..5c472ebc8 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -56,6 +56,7 @@ Properties\SharedVersion.cs + diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index f18c53cd3..9900484cd 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -188,6 +188,9 @@ Configuration\DynamicDayOfWeek.cs + + Configuration\EncodingOptions.cs + Configuration\EncodingQuality.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index f17215988..bd98b5b86 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -153,6 +153,9 @@ Configuration\DynamicDayOfWeek.cs + + Configuration\EncodingOptions.cs + Configuration\EncodingQuality.cs diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs new file mode 100644 index 000000000..f24367298 --- /dev/null +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -0,0 +1,19 @@ + +namespace MediaBrowser.Model.Configuration +{ + public class EncodingOptions + { + public EncodingQuality EncodingQuality { get; set; } + public string TranscodingTempPath { get; set; } + public double DownMixAudioBoost { get; set; } + public string H264Encoder { get; set; } + public bool EnableDebugLogging { get; set; } + + public EncodingOptions() + { + H264Encoder = "libx264"; + DownMixAudioBoost = 2; + EncodingQuality = EncodingQuality.Auto; + } + } +} diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 59dd04f33..0852e0a5c 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -144,15 +144,8 @@ namespace MediaBrowser.Model.Configuration /// The image saving convention. public ImageSavingConvention ImageSavingConvention { get; set; } - /// - /// Gets or sets the encoding quality. - /// - /// The encoding quality. - public EncodingQuality MediaEncodingQuality { get; set; } - public MetadataOptions[] MetadataOptions { get; set; } - public bool EnableDebugEncodingLogging { get; set; } public string TranscodingTempPath { get; set; } public bool EnableAutomaticRestart { get; set; } @@ -165,15 +158,12 @@ namespace MediaBrowser.Model.Configuration public string UICulture { get; set; } - public double DownMixAudioBoost { get; set; } - public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } public string[] InsecureApps7 { get; set; } public bool SaveMetadataHidden { get; set; } - public string H264Encoder { get; set; } /// /// Initializes a new instance of the class. @@ -181,7 +171,6 @@ namespace MediaBrowser.Model.Configuration public ServerConfiguration() : base() { - MediaEncodingQuality = EncodingQuality.Auto; ImageSavingConvention = ImageSavingConvention.Compatible; PublicPort = 8096; HttpServerPortNumber = 8096; @@ -190,7 +179,6 @@ namespace MediaBrowser.Model.Configuration EnableAutomaticRestart = true; EnableUPnP = true; - DownMixAudioBoost = 2; MinResumePct = 5; MaxResumePct = 90; @@ -217,7 +205,6 @@ namespace MediaBrowser.Model.Configuration EnableRealtimeMonitor = true; UICulture = "en-us"; - H264Encoder = "libx264"; PeopleMetadataOptions = new PeopleMetadataOptions(); diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 759c671e9..e1f0e78f4 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -96,6 +96,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs index b9896e9ce..704bdea29 100644 --- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -32,7 +32,6 @@ namespace MediaBrowser.Server.Implementations.Configuration : base(applicationPaths, logManager, xmlSerializer) { UpdateItemsByNamePath(); - UpdateTranscodingTempPath(); UpdateMetadataPath(); } @@ -71,7 +70,6 @@ namespace MediaBrowser.Server.Implementations.Configuration protected override void OnConfigurationUpdated() { UpdateItemsByNamePath(); - UpdateTranscodingTempPath(); UpdateMetadataPath(); base.OnConfigurationUpdated(); @@ -97,16 +95,6 @@ namespace MediaBrowser.Server.Implementations.Configuration Configuration.MetadataPath; } - /// - /// Updates the transcoding temporary path. - /// - private void UpdateTranscodingTempPath() - { - ((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(Configuration.TranscodingTempPath) ? - null : - Configuration.TranscodingTempPath; - } - /// /// Replaces the configuration. /// @@ -117,7 +105,6 @@ namespace MediaBrowser.Server.Implementations.Configuration var newConfig = (ServerConfiguration)newConfiguration; ValidateItemByNamePath(newConfig); - ValidateTranscodingTempPath(newConfig); ValidatePathSubstitutions(newConfig); ValidateMetadataPath(newConfig); @@ -157,26 +144,6 @@ namespace MediaBrowser.Server.Implementations.Configuration } } - /// - /// Validates the transcoding temporary path. - /// - /// The new configuration. - /// - private void ValidateTranscodingTempPath(ServerConfiguration newConfig) - { - var newPath = newConfig.TranscodingTempPath; - - if (!string.IsNullOrWhiteSpace(newPath) - && !string.Equals(Configuration.TranscodingTempPath ?? string.Empty, newPath)) - { - // Validate - if (!Directory.Exists(newPath)) - { - throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath)); - } - } - } - /// /// Validates the metadata path. /// -- cgit v1.2.3 From 498b58aad0b2df17b3caf34b04dbf3f1438742c5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 22 Dec 2014 01:50:29 -0500 Subject: added content type selection --- MediaBrowser.Api/ItemUpdateService.cs | 37 ++++++++++++---- MediaBrowser.Controller/Library/ILibraryManager.cs | 4 +- .../Configuration/CinemaModeConfiguration.cs | 1 + .../Configuration/ServerConfiguration.cs | 6 ++- .../Library/LibraryManager.cs | 49 +++++++++++++++++++--- .../Library/Resolvers/Movies/MovieResolver.cs | 4 +- 6 files changed, 82 insertions(+), 19 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 953f7b3bb..020908ddd 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -46,12 +47,14 @@ namespace MediaBrowser.Api private readonly ILibraryManager _libraryManager; private readonly IProviderManager _providerManager; private readonly ILocalizationManager _localizationManager; + private readonly IServerConfigurationManager _config; - public ItemUpdateService(ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager) + public ItemUpdateService(ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager, IServerConfigurationManager config) { _libraryManager = libraryManager; _providerManager = providerManager; _localizationManager = localizationManager; + _config = config; } public object Get(GetMetadataEditorInfo request) @@ -70,11 +73,14 @@ namespace MediaBrowser.Api if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) { - var collectionType = _libraryManager.GetInheritedContentType(item); - if (string.IsNullOrWhiteSpace(collectionType)) + if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder)) { - info.ContentTypeOptions = GetContentTypeOptions(true); - info.ContentType = _libraryManager.GetContentType(item); + var collectionType = _libraryManager.GetInheritedContentType(item); + if (string.IsNullOrWhiteSpace(collectionType)) + { + info.ContentTypeOptions = GetContentTypeOptions(true); + info.ContentType = _libraryManager.GetContentType(item); + } } } @@ -83,7 +89,24 @@ namespace MediaBrowser.Api public void Post(UpdateItemContentType request) { - + var item = _libraryManager.GetItemById(request.ItemId); + var path = item.ContainingFolderPath; + + var types = _config.Configuration.ContentTypes + .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (!string.IsNullOrWhiteSpace(request.ContentType)) + { + types.Add(new NameValuePair + { + Name = path, + Value = request.ContentType + }); + } + + _config.Configuration.ContentTypes = types.ToArray(); + _config.SaveConfiguration(); } private List GetContentTypeOptions(bool isForItem) diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 7cdfb7788..8573f32e0 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -23,11 +23,9 @@ namespace MediaBrowser.Controller.Library /// /// The file information. /// The parent. - /// Type of the collection. /// BaseItem. BaseItem ResolvePath(FileSystemInfo fileInfo, - Folder parent = null, - string collectionType = null); + Folder parent = null); /// /// Resolves a set of files into a list of BaseItem diff --git a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs index bd20713de..764a7222f 100644 --- a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs +++ b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs @@ -19,6 +19,7 @@ namespace MediaBrowser.Model.Configuration public CinemaModeConfiguration() { EnableIntrosParentalControl = true; + EnableIntrosFromSimilarMovies = true; TrailerLimit = 2; } } diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 0852e0a5c..730735499 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Configuration { @@ -165,6 +166,8 @@ namespace MediaBrowser.Model.Configuration public bool SaveMetadataHidden { get; set; } + public NameValuePair[] ContentTypes { get; set; } + /// /// Initializes a new instance of the class. /// @@ -192,6 +195,7 @@ namespace MediaBrowser.Model.Configuration FindInternetTrailers = true; PathSubstitutions = new PathSubstitution[] { }; + ContentTypes = new NameValuePair[] { }; PreferredMetadataLanguage = "en"; MetadataCountryCode = "US"; diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index ab50c30fb..d52288f87 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -560,10 +560,9 @@ namespace MediaBrowser.Server.Implementations.Library } public BaseItem ResolvePath(FileSystemInfo fileInfo, - Folder parent = null, - string collectionType = null) + Folder parent = null) { - return ResolvePath(fileInfo, new DirectoryService(_logger), parent, collectionType); + return ResolvePath(fileInfo, new DirectoryService(_logger), parent); } private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null) @@ -573,10 +572,17 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("fileInfo"); } + var fullPath = fileInfo.FullName; + + if (string.IsNullOrWhiteSpace(collectionType)) + { + collectionType = GetConfiguredContentType(fullPath); + } + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, this, directoryService) { Parent = parent, - Path = fileInfo.FullName, + Path = fullPath, FileInfo = fileInfo, CollectionType = collectionType }; @@ -1548,12 +1554,43 @@ namespace MediaBrowser.Server.Implementations.Library public string GetContentType(BaseItem item) { - return GetInheritedContentType(item); + // Types cannot be overridden, so go from the top down until we find a configured content type + + var type = GetTopFolderContentType(item); + + if (!string.IsNullOrWhiteSpace(type)) + { + return type; + } + + type = GetInheritedContentType(item); + + if (!string.IsNullOrWhiteSpace(type)) + { + return type; + } + + return GetConfiguredContentType(item); } public string GetInheritedContentType(BaseItem item) { - return GetTopFolderContentType(item); + return item.Parents + .Select(GetConfiguredContentType) + .LastOrDefault(i => !string.IsNullOrWhiteSpace(i)); + } + + private string GetConfiguredContentType(BaseItem item) + { + return GetConfiguredContentType(item.ContainingFolderPath); + } + + private string GetConfiguredContentType(string path) + { + var type = ConfigurationManager.Configuration.ContentTypes + .FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(i.Name, path)); + + return type == null ? null : type.Value; } private string GetTopFolderContentType(BaseItem item) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 58b5dbc6a..01dc4db8a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -79,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return ResolveVideos /// The series. /// The episode lookup. - /// if set to true [force remove all]. /// Task{System.Boolean}. private async Task RemoveObsoleteOrMissingSeasons(IEnumerable series, - IEnumerable> episodeLookup, - bool forceRemoveAll) + IEnumerable> episodeLookup) { var existingSeasons = (from s in series let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1) @@ -385,11 +395,6 @@ namespace MediaBrowser.Providers.TV var seasonsToRemove = virtualSeasons .Where(i => { - if (forceRemoveAll) - { - return true; - } - if (i.Season.IndexNumber.HasValue) { var seasonNumber = i.Season.IndexNumber.Value + i.SeasonOffset; @@ -409,7 +414,9 @@ namespace MediaBrowser.Providers.TV return false; } - return true; + // Season does not have a number + // Remove if there are no episodes directly in series without a season number + return i.Season.Series.RecursiveChildren.OfType().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder); }) .ToList(); @@ -472,20 +479,22 @@ namespace MediaBrowser.Providers.TV /// The cancellation token. /// Task{Season}. private async Task AddSeason(Series series, - int seasonNumber, + int? seasonNumber, CancellationToken cancellationToken) { - _logger.Info("Creating Season {0} entry for {1}", seasonNumber, series.Name); + var seasonName = seasonNumber == 0 ? + _config.Configuration.SeasonZeroDisplayName : + (seasonNumber.HasValue ? string.Format(_localization.GetLocalizedString("NameSeasonNumber"), seasonNumber.Value.ToString(UsCulture)) : _localization.GetLocalizedString("NameSeasonUnknown")); - var name = seasonNumber == 0 ? _config.Configuration.SeasonZeroDisplayName : string.Format("Season {0}", seasonNumber.ToString(UsCulture)); + _logger.Info("Creating Season {0} entry for {1}", seasonName, series.Name); var season = new Season { - Name = name, + Name = seasonName, IndexNumber = seasonNumber, Parent = series, DisplayMediaType = typeof(Season).Name, - Id = (series.Id + seasonNumber.ToString(UsCulture) + name).GetMBId(typeof(Season)) + Id = (series.Id + (seasonNumber ?? -1).ToString(UsCulture) + seasonName).GetMBId(typeof(Season)) }; await series.AddChild(season, cancellationToken).ConfigureAwait(false); diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index d350d2fe4..e1986a7c1 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -25,12 +26,14 @@ namespace MediaBrowser.Providers.TV private readonly ILibraryManager _libraryManager; private readonly IServerConfigurationManager _config; private readonly ILogger _logger; + private readonly ILocalizationManager _localization; - public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config) + public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization) { _libraryManager = libraryManager; _logger = logger; _config = config; + _localization = localization; } public Task Run(IProgress progress, CancellationToken cancellationToken) @@ -47,7 +50,7 @@ namespace MediaBrowser.Providers.TV var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); - await new MissingEpisodeProvider(_logger, _config, _libraryManager).Run(seriesGroups, cancellationToken).ConfigureAwait(false); + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false); var numComplete = 0; diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index ef9f5427c..52c1ab7dd 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -72,6 +72,10 @@ namespace MediaBrowser.Providers.TV { // Don't fail the provider because this will just keep on going and going. } + catch (DirectoryNotFoundException) + { + // Don't fail the provider because this will just keep on going and going. + } } return list; @@ -101,6 +105,10 @@ namespace MediaBrowser.Providers.TV { // Don't fail the provider because this will just keep on going and going. } + catch (DirectoryNotFoundException) + { + // Don't fail the provider because this will just keep on going and going. + } } return result; @@ -208,8 +216,9 @@ namespace MediaBrowser.Providers.TV /// Fetches the episode data. /// /// The identifier. + /// The identity. /// The series data path. - /// + /// The series provider ids. /// The cancellation token. /// Task{System.Boolean}. private Episode FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary seriesProviderIds, CancellationToken cancellationToken) @@ -279,6 +288,10 @@ namespace MediaBrowser.Providers.TV { break; } + catch (DirectoryNotFoundException) + { + break; + } episodeNumber++; } diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs index efafeae96..1ebd7bed5 100644 --- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs @@ -94,6 +94,10 @@ namespace MediaBrowser.Providers.TV { // No tvdb data yet. Don't blow up } + catch (DirectoryNotFoundException) + { + // No tvdb data yet. Don't blow up + } } return new RemoteImageInfo[] { }; diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 9cc09c40c..08913d3b4 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -87,6 +87,10 @@ namespace MediaBrowser.Providers.TV { // No tvdb data yet. Don't blow up } + catch (DirectoryNotFoundException) + { + // No tvdb data yet. Don't blow up + } } return new RemoteImageInfo[] { }; diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index 376dc3548..67d844543 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -789,7 +790,7 @@ namespace MediaBrowser.Server.Implementations.Connect if (user == null) { // Add user - user = await _userManager.CreateUser(connectEntry.UserName).ConfigureAwait(false); + user = await _userManager.CreateUser(_userManager.MakeValidUsername(connectEntry.UserName)).ConfigureAwait(false); user.ConnectUserName = connectEntry.UserName; user.ConnectUserId = connectEntry.UserId; diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index b141fea1e..967c78c50 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -78,6 +78,11 @@ namespace MediaBrowser.Server.Implementations.Drawing // No biggie sizeDictionary = new Dictionary(); } + catch (DirectoryNotFoundException) + { + // No biggie + sizeDictionary = new Dictionary(); + } catch (Exception ex) { logger.ErrorException("Error parsing image size cache file", ex); diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 3b5e34520..432ea1f69 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -459,11 +459,11 @@ namespace MediaBrowser.Server.Implementations.FileOrganization private bool IsSameEpisode(string sourcePath, string newPath) { - var sourceFileInfo = new FileInfo(sourcePath); - var destinationFileInfo = new FileInfo(newPath); - try { + var sourceFileInfo = new FileInfo(sourcePath); + var destinationFileInfo = new FileInfo(newPath); + if (sourceFileInfo.Length == destinationFileInfo.Length) { return true; @@ -473,6 +473,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { return false; } + catch (DirectoryNotFoundException) + { + return false; + } return false; } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index d52288f87..66125784c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1755,9 +1755,12 @@ namespace MediaBrowser.Server.Implementations.Library var resolver = new EpisodeResolver(new ExtendedNamingOptions(), new Naming.Logging.NullLogger()); + var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ? + FileInfoType.Directory : + FileInfoType.File; + var locationType = episode.LocationType; - var fileType = /*args.IsDirectory ? FileInfoType.Directory :*/ FileInfoType.File; var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ? resolver.Resolve(episode.Path, fileType) : new Naming.TV.EpisodeInfo(); @@ -1769,29 +1772,42 @@ namespace MediaBrowser.Server.Implementations.Library var changed = false; - if (!episode.IndexNumber.HasValue) + if (episodeInfo.IsByDate) { - episode.IndexNumber = episodeInfo.EpisodeNumber; - if (episode.IndexNumber.HasValue) { + episode.IndexNumber = null; changed = true; } - } - - if (!episode.IndexNumberEnd.HasValue) - { - episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber; if (episode.IndexNumberEnd.HasValue) { + episode.IndexNumberEnd = null; changed = true; } - } - if (!episode.ParentIndexNumber.HasValue) - { - episode.ParentIndexNumber = episodeInfo.SeasonNumber; + if (!episode.PremiereDate.HasValue) + { + if (episodeInfo.Year.HasValue && episodeInfo.Month.HasValue && episodeInfo.Day.HasValue) + { + episode.PremiereDate = new DateTime(episodeInfo.Year.Value, episodeInfo.Month.Value, episodeInfo.Day.Value).ToUniversalTime(); + } + + if (episode.PremiereDate.HasValue) + { + changed = true; + } + } + + if (!episode.ProductionYear.HasValue) + { + episode.ProductionYear = episodeInfo.Year; + + if (episode.ProductionYear.HasValue) + { + changed = true; + } + } if (!episode.ParentIndexNumber.HasValue) { @@ -1801,11 +1817,53 @@ namespace MediaBrowser.Server.Implementations.Library { episode.ParentIndexNumber = season.IndexNumber; } + + if (episode.ParentIndexNumber.HasValue) + { + changed = true; + } + } + } + else + { + if (!episode.IndexNumber.HasValue) + { + episode.IndexNumber = episodeInfo.EpisodeNumber; + + if (episode.IndexNumber.HasValue) + { + changed = true; + } } - if (episode.ParentIndexNumber.HasValue) + if (!episode.IndexNumberEnd.HasValue) { - changed = true; + episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber; + + if (episode.IndexNumberEnd.HasValue) + { + changed = true; + } + } + + if (!episode.ParentIndexNumber.HasValue) + { + episode.ParentIndexNumber = episodeInfo.SeasonNumber; + + if (!episode.ParentIndexNumber.HasValue) + { + var season = episode.Season; + + if (season != null) + { + episode.ParentIndexNumber = season.IndexNumber; + } + } + + if (episode.ParentIndexNumber.HasValue) + { + changed = true; + } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index 39b0a93cc..1a873f01e 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -1,7 +1,5 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Naming.Common; -using MediaBrowser.Naming.IO; using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 1d58ad074..02d7c1be1 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -171,6 +171,38 @@ namespace MediaBrowser.Server.Implementations.Library return AuthenticateUser(username, passwordSha1, null, remoteEndPoint); } + public bool IsValidUsername(string username) + { + // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.) + return username.All(IsValidCharacter); + } + + private bool IsValidCharacter(char i) + { + return char.IsLetterOrDigit(i) || char.Equals(i, '-') || char.Equals(i, '_') || char.Equals(i, '\'') || + char.Equals(i, '.'); + } + + public string MakeValidUsername(string username) + { + if (IsValidUsername(username)) + { + return username; + } + + // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.) + var builder = new StringBuilder(); + + foreach (var c in username) + { + if (IsValidCharacter(c)) + { + builder.Append(c); + } + } + return builder.ToString(); + } + public async Task AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint) { if (string.IsNullOrWhiteSpace(username)) @@ -178,7 +210,8 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("username"); } - var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase)); + var user = Users + .FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase)); if (user == null) { @@ -203,20 +236,6 @@ namespace MediaBrowser.Server.Implementations.Library } } - // Maybe user accidently entered connect credentials. let's be flexible - if (!success && user.ConnectLinkType.HasValue && !string.IsNullOrWhiteSpace(passwordMd5)) - { - try - { - await _connectFactory().Authenticate(user.ConnectUserName, passwordMd5).ConfigureAwait(false); - success = true; - } - catch - { - - } - } - // Update LastActivityDate and LastLoginDate, then save if (success) { @@ -273,7 +292,7 @@ namespace MediaBrowser.Server.Implementations.Library // There always has to be at least one user. if (users.Count == 0) { - var name = Environment.UserName; + var name = MakeValidUsername(Environment.UserName); var user = InstantiateNewUser(name, false); @@ -477,6 +496,11 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } + if (!IsValidUsername(name)) + { + throw new ArgumentException("Only alphanumeric characters are allowed."); + } + if (Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) { throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name)); @@ -803,6 +827,10 @@ namespace MediaBrowser.Server.Implementations.Library return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path); } } + catch (DirectoryNotFoundException) + { + return GetDefaultPolicy(user); + } catch (FileNotFoundException) { return GetDefaultPolicy(user); @@ -840,6 +868,8 @@ namespace MediaBrowser.Server.Implementations.Library var path = GetPolifyFilePath(user); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + lock (_policySyncLock) { _xmlSerializer.SerializeToFile(userPolicy, path); @@ -900,6 +930,10 @@ namespace MediaBrowser.Server.Implementations.Library return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path); } } + catch (DirectoryNotFoundException) + { + return new UserConfiguration(); + } catch (FileNotFoundException) { return new UserConfiguration(); @@ -930,6 +964,8 @@ namespace MediaBrowser.Server.Implementations.Library config = _jsonSerializer.DeserializeFromString(json); } + Directory.CreateDirectory(Path.GetDirectoryName(path)); + lock (_configSyncLock) { _xmlSerializer.SerializeToFile(config, path); diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 695200239..827a2388d 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -419,7 +419,7 @@ "HeaderMediaLocations": "Media Locations", "LabelFolderTypeValue": "Folder type: {0}", "LabelPathSubstitutionHelp": "Optional: Path substitution can map server paths to network shares that clients can access for direct playback.", - "FolderTypeMixed": "Mixed videos", + "FolderTypeMixed": "Mixed content", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -658,5 +658,5 @@ "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced.", "MessageBookPluginRequired": "Requires installation of the Bookshelf plugin", "MessageGamePluginRequired": "Requires installation of the GameBrowser plugin", - "MessageMixedContentHelp": "Content will be displayed with as a plain folder structure" + "MessageMixedContentHelp": "Content will be displayed as a plain folder structure" } diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 9a515d492..c0af13950 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -37,7 +37,7 @@ "ButtonOk": "Ok", "ButtonCancel": "Cancel", "ButtonNew": "New", - "FolderTypeMixed": "Mixed videos", + "FolderTypeMixed": "Mixed content", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -48,7 +48,7 @@ "FolderTypeBooks": "Books", "FolderTypeTvShows": "TV", "FolderTypeInherit": "Inherit", - "LabelContentType": "Content type:", + "LabelContentType": "Content type:", "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", @@ -1307,5 +1307,8 @@ "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.", "TabActivity": "Activity", "TitleSync": "Sync", - "OptionAllowSyncContent": "Allow syncing media to devices" + "OptionAllowSyncContent": "Allow syncing media to devices", + "NameSeasonUnknown": "Season Unknown", + "NameSeasonNumber": "Season {0}", + "LabelNewUserNameHelp": "Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)" } diff --git a/MediaBrowser.Server.Implementations/News/NewsService.cs b/MediaBrowser.Server.Implementations/News/NewsService.cs index 9eeadfab7..684363d01 100644 --- a/MediaBrowser.Server.Implementations/News/NewsService.cs +++ b/MediaBrowser.Server.Implementations/News/NewsService.cs @@ -26,6 +26,14 @@ namespace MediaBrowser.Server.Implementations.News { return GetProductNewsInternal(query); } + catch (DirectoryNotFoundException) + { + // No biggie + return new QueryResult + { + Items = new NewsItem[] { } + }; + } catch (FileNotFoundException) { // No biggie diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 86e92530f..0f1d53ea6 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -256,6 +256,10 @@ namespace MediaBrowser.XbmcMetadata.Savers catch (FileNotFoundException) { + } + catch (DirectoryNotFoundException) + { + } writer.WriteEndElement(); -- cgit v1.2.3 From 36577ac42ea9a38a155ca7cd0d17d2d43563a27f Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 24 Dec 2014 01:28:40 -0500 Subject: sync updates --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 3 +- .../Entities/CollectionFolder.cs | 16 +++++++++ MediaBrowser.Controller/Sync/ISyncProvider.cs | 5 +++ .../Images/LocalImageProvider.cs | 1 - .../Savers/XmlSaverHelpers.cs | 2 +- .../MediaBrowser.Model.Portable.csproj | 3 ++ .../MediaBrowser.Model.net35.csproj | 3 ++ MediaBrowser.Model/Dlna/StreamInfo.cs | 14 ++++++-- .../Library/Resolvers/TV/SeriesResolver.cs | 40 +++++----------------- .../Sync/AppSyncProvider.cs | 2 +- .../Sync/SyncManager.cs | 21 +++++++++--- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +-- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +-- 15 files changed, 73 insertions(+), 49 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 7b18fb379..03106b6e7 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -729,7 +729,8 @@ namespace MediaBrowser.Api.Playback return Math.Min(request.MaxAudioChannels.Value, audioStream.Channels.Value); } - return request.MaxAudioChannels.Value; + // If we don't have any media info then limit it to 5 to prevent encoding errors due to asking for too many channels + return Math.Min(request.MaxAudioChannels.Value, 5); } return request.AudioChannels; diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index a10742f01..f47a439a7 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -66,6 +66,22 @@ namespace MediaBrowser.Controller.Entities return CreateResolveArgs(directoryService).FileSystemChildren; } + internal override bool IsValidFromResolver(BaseItem newItem) + { + var newCollectionFolder = newItem as CollectionFolder; + + if (newCollectionFolder != null) + { + if (!string.Equals(CollectionType, newCollectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase)) + { + return false; + } + } + + + return base.IsValidFromResolver(newItem); + } + private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService) { var path = ContainingFolderPath; diff --git a/MediaBrowser.Controller/Sync/ISyncProvider.cs b/MediaBrowser.Controller/Sync/ISyncProvider.cs index 89f61b80e..5ebdee207 100644 --- a/MediaBrowser.Controller/Sync/ISyncProvider.cs +++ b/MediaBrowser.Controller/Sync/ISyncProvider.cs @@ -25,4 +25,9 @@ namespace MediaBrowser.Controller.Sync /// DeviceProfile. DeviceProfile GetDeviceProfile(SyncTarget target); } + + public interface IHasUniqueTargetIds + { + + } } diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index 9b1cce915..a131e7016 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -1,7 +1,6 @@ using MediaBrowser.Common.IO; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs index 3e11c994b..4388ec964 100644 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -649,7 +649,7 @@ namespace MediaBrowser.LocalMetadata.Savers var hasShares = item as IHasShares; if (hasShares != null) { - + AddShares(hasShares, builder); } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 9900484cd..a388e0edb 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1043,6 +1043,9 @@ Sync\SyncDialogOptions.cs + + Sync\SyncHelper.cs + Sync\SyncItem.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index bd98b5b86..5bacb73d7 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -1002,6 +1002,9 @@ Sync\SyncDialogOptions.cs + + Sync\SyncHelper.cs + Sync\SyncItem.cs diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 7ca8ab6b0..703c73566 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -374,9 +374,17 @@ namespace MediaBrowser.Model.Dlna MediaStream stream = TargetAudioStream; int? streamChannels = stream == null ? null : stream.Channels; - return MaxAudioChannels.HasValue && !IsDirectStream - ? (streamChannels.HasValue ? Math.Min(MaxAudioChannels.Value, streamChannels.Value) : MaxAudioChannels.Value) - : streamChannels; + if (MaxAudioChannels.HasValue && !IsDirectStream) + { + if (streamChannels.HasValue) + { + return Math.Min(MaxAudioChannels.Value, streamChannels.Value); + } + + return MaxAudioChannels.Value; + } + + return streamChannels; } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 00bed4086..582412562 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -1,17 +1,15 @@ using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; +using MediaBrowser.Naming.Common; +using MediaBrowser.Naming.TV; using System; using System.Collections.Generic; using System.IO; -using MediaBrowser.Naming.Common; -using MediaBrowser.Naming.IO; -using MediaBrowser.Naming.TV; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { @@ -60,10 +58,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV var collectionType = args.GetCollectionType(); - var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); - // If there's a collection type and it's not tv, it can't be a series - if (!isTvShowsFolder) + if (!string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) { return null; } @@ -73,7 +69,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV return null; } - if (IsSeriesFolder(args.Path, collectionType, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager)) + if (IsSeriesFolder(args.Path, args.FileSystemChildren, args.DirectoryService, _fileSystem, _logger, _libraryManager)) { return new Series { @@ -90,14 +86,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV /// Determines whether [is series folder] [the specified path]. /// /// The path. - /// Type of the collection. /// The file system children. /// The directory service. /// The file system. /// The logger. /// The library manager. /// true if [is series folder] [the specified path]; otherwise, false. - public static bool IsSeriesFolder(string path, string collectionType, IEnumerable fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager) + public static bool IsSeriesFolder(string path, IEnumerable fileSystemChildren, IDirectoryService directoryService, IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager) { foreach (var child in fileSystemChildren) { @@ -118,7 +113,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) { - if (IsSeasonFolder(child.FullName, collectionType)) + if (IsSeasonFolder(child.FullName)) { //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName); return true; @@ -130,22 +125,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if (libraryManager.IsVideoFile(fullName) || IsVideoPlaceHolder(fullName)) { - var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); - - // We can fast track this for known tv folders - if (isTvShowsFolder) - { - return true; - } - - var resolver = new Naming.TV.EpisodeResolver(new ExtendedNamingOptions(), new Naming.Logging.NullLogger()); - - var episodeInfo = resolver.Resolve(fullName, FileInfoType.File, isTvShowsFolder, false); - - if (episodeInfo != null && (episodeInfo.EpisodeNumber.HasValue || episodeInfo.IsByDate)) - { - return true; - } + return true; } } } @@ -176,12 +156,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV /// Determines whether [is season folder] [the specified path]. /// /// The path. - /// Type of the collection. /// true if [is season folder] [the specified path]; otherwise, false. - private static bool IsSeasonFolder(string path, string collectionType) + private static bool IsSeasonFolder(string path) { - var isTvFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); - var seasonNumber = new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(path, isTvFolder).SeasonNumber; + var seasonNumber = new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(path, true).SeasonNumber; return seasonNumber.HasValue; } diff --git a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs index 94eed50f6..deef503ea 100644 --- a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs @@ -8,7 +8,7 @@ using System.Linq; namespace MediaBrowser.Server.Implementations.Sync { - public class AppSyncProvider : ISyncProvider + public class AppSyncProvider : ISyncProvider, IHasUniqueTargetIds { private readonly IDeviceManager _deviceManager; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 6b15aaed7..3006c1be9 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -69,7 +69,12 @@ namespace MediaBrowser.Server.Implementations.Sync } var target = GetSyncTargets(request.UserId) - .First(i => string.Equals(request.TargetId, i.Id)); + .FirstOrDefault(i => string.Equals(request.TargetId, i.Id)); + + if (target == null) + { + throw new ArgumentException("Sync target not found."); + } var jobId = Guid.NewGuid().ToString("N"); @@ -173,17 +178,23 @@ namespace MediaBrowser.Server.Implementations.Sync private IEnumerable GetSyncTargets(ISyncProvider provider, string userId) { - var providerId = GetSyncProviderId(provider); - return provider.GetSyncTargets().Select(i => new SyncTarget { Name = i.Name, - Id = GetSyncTargetId(providerId, i) + Id = GetSyncTargetId(provider, i) }); } - private string GetSyncTargetId(string providerId, SyncTarget target) + private string GetSyncTargetId(ISyncProvider provider, SyncTarget target) { + var hasUniqueId = provider as IHasUniqueTargetIds; + + if (hasUniqueId != null) + { + return target.Id; + } + + var providerId = GetSyncProviderId(provider); return (providerId + "-" + target.Id).GetMD5().ToString("N"); } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 7d2adb590..6dfb39b4c 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.522 + 3.0.523 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 705b3444a..49fd835c3 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.522 + 3.0.523 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 5df3ccb03..d5164f025 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.522 + 3.0.523 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 9e463b7ab..297b0f07e 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.522 + 3.0.523 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 From 0ec3d217e71ea20a9e377e479db88c4d4cd39baf Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 26 Dec 2014 12:45:06 -0500 Subject: sync updates --- MediaBrowser.Api/Images/ImageService.cs | 13 +- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 1 + MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 20 +- MediaBrowser.Api/Playback/Hls/MpegDashService.cs | 16 +- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 15 +- .../Playback/Progressive/VideoService.cs | 12 +- MediaBrowser.Api/Playback/StreamState.cs | 1 + MediaBrowser.Api/Subtitles/SubtitleService.cs | 7 +- MediaBrowser.Api/Sync/SyncService.cs | 29 +- MediaBrowser.Common/MediaBrowser.Common.csproj | 1 - MediaBrowser.Common/Net/MimeTypes.cs | 338 --------------------- .../Library/IUserDataManager.cs | 4 + MediaBrowser.Controller/Sync/ISyncManager.cs | 15 + MediaBrowser.Dlna/Didl/DidlBuilder.cs | 1 + .../Images/LocalImageProvider.cs | 2 +- .../MediaBrowser.Model.Portable.csproj | 31 +- .../MediaBrowser.Model.net35.csproj | 27 +- MediaBrowser.Model/ApiClient/IApiClient.cs | 40 ++- MediaBrowser.Model/Dto/StreamOptions.cs | 67 ---- MediaBrowser.Model/Dto/VideoStreamOptions.cs | 58 +++- MediaBrowser.Model/MediaBrowser.Model.csproj | 9 +- MediaBrowser.Model/Net/HttpResponse.cs | 64 ++++ MediaBrowser.Model/Net/MimeTypes.cs | 273 +++++++++++++++++ MediaBrowser.Model/Sync/ItemFIleInfo.cs | 28 ++ MediaBrowser.Model/Sync/ItemFileType.cs | 19 ++ MediaBrowser.Model/Sync/SyncItem.cs | 9 - MediaBrowser.Model/Sync/SyncJobItem.cs | 6 + MediaBrowser.Model/Sync/SyncedItem.cs | 38 +++ MediaBrowser.Model/Users/UserAction.cs | 14 + MediaBrowser.Model/Users/UserActionType.cs | 8 + MediaBrowser.Providers/Manager/ImageSaver.cs | 1 + .../Connect/ConnectEntryPoint.cs | 2 +- .../HttpServer/HttpResultFactory.cs | 2 +- .../Library/Resolvers/Movies/BoxSetResolver.cs | 6 - .../Library/UserDataManager.cs | 76 +++-- .../Localization/JavaScript/en_US.json | 1 - .../Localization/JavaScript/javascript.json | 2 +- .../Session/SessionManager.cs | 80 +---- .../Sync/SyncJobProcessor.cs | 6 + .../Sync/SyncManager.cs | 68 ++++- .../Sync/SyncRepository.cs | 29 +- .../ApplicationHost.cs | 6 +- MediaBrowser.WebDashboard/Api/DashboardService.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 +- 47 files changed, 859 insertions(+), 599 deletions(-) delete mode 100644 MediaBrowser.Common/Net/MimeTypes.cs delete mode 100644 MediaBrowser.Model/Dto/StreamOptions.cs create mode 100644 MediaBrowser.Model/Net/HttpResponse.cs create mode 100644 MediaBrowser.Model/Net/MimeTypes.cs create mode 100644 MediaBrowser.Model/Sync/ItemFIleInfo.cs create mode 100644 MediaBrowser.Model/Sync/ItemFileType.cs delete mode 100644 MediaBrowser.Model/Sync/SyncItem.cs create mode 100644 MediaBrowser.Model/Sync/SyncedItem.cs create mode 100644 MediaBrowser.Model/Users/UserAction.cs create mode 100644 MediaBrowser.Model/Users/UserActionType.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 0e4ccf0b1..f2586b043 100644 --- a/MediaBrowser.Api/Images/ImageService.cs +++ b/MediaBrowser.Api/Images/ImageService.cs @@ -18,6 +18,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Images { @@ -668,26 +669,26 @@ namespace MediaBrowser.Api.Images { if (format == ImageFormat.Bmp) { - return Common.Net.MimeTypes.GetMimeType("i.bmp"); + return MimeTypes.GetMimeType("i.bmp"); } if (format == ImageFormat.Gif) { - return Common.Net.MimeTypes.GetMimeType("i.gif"); + return MimeTypes.GetMimeType("i.gif"); } if (format == ImageFormat.Jpg) { - return Common.Net.MimeTypes.GetMimeType("i.jpg"); + return MimeTypes.GetMimeType("i.jpg"); } if (format == ImageFormat.Png) { - return Common.Net.MimeTypes.GetMimeType("i.png"); + return MimeTypes.GetMimeType("i.png"); } if (format == ImageFormat.Webp) { - return Common.Net.MimeTypes.GetMimeType("i.webp"); + return MimeTypes.GetMimeType("i.webp"); } - return Common.Net.MimeTypes.GetMimeType(path); + return MimeTypes.GetMimeType(path); } /// diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index 94198d974..8a33a88f2 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -14,6 +14,7 @@ using System.IO; using System.Text; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Net; namespace MediaBrowser.Api.Playback.Hls { diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs index 489259334..86866bdf5 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -20,6 +20,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Playback.Hls { @@ -387,7 +388,7 @@ namespace MediaBrowser.Api.Playback.Hls playlistText = GetMasterPlaylistFileText(state, videoBitrate + audioBitrate); } - return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); + return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); } private string GetMasterPlaylistFileText(StreamState state, int totalBitrate) @@ -603,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls var playlistText = builder.ToString(); - return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); + return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); } protected override string GetAudioArguments(StreamState state) @@ -640,10 +641,19 @@ namespace MediaBrowser.Api.Playback.Hls { var codec = state.OutputVideoCodec; + var args = "-codec:v:0 " + codec; + + if (state.EnableMpegtsM2TsMode) + { + args += " -mpegts_m2ts_mode 1"; + } + // See if we can save come cpu cycles by avoiding encoding - if (string.Equals(codec, "copy", StringComparison.OrdinalIgnoreCase)) + if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) { - return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy"; + return state.VideoStream != null && IsH264(state.VideoStream) ? + args + " -bsf:v h264_mp4toannexb" : + args; } var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", @@ -651,7 +661,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; + args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) diff --git a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs index e91ed98d1..87e2eedcf 100644 --- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs @@ -18,6 +18,7 @@ using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Playback.Hls { @@ -97,7 +98,7 @@ namespace MediaBrowser.Api.Playback.Hls playlistText = GetManifestText(state); } - return ResultFactory.GetResult(playlistText, Common.Net.MimeTypes.GetMimeType("playlist.mpd"), new Dictionary()); + return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.mpd"), new Dictionary()); } private string GetManifestText(StreamState state) @@ -583,10 +584,19 @@ namespace MediaBrowser.Api.Playback.Hls { var codec = state.OutputVideoCodec; + var args = "-codec:v:0 " + codec; + + if (state.EnableMpegtsM2TsMode) + { + args += " -mpegts_m2ts_mode 1"; + } + // See if we can save come cpu cycles by avoiding encoding if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) { - return IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy"; + return state.VideoStream != null && IsH264(state.VideoStream) ? + args + " -bsf:v h264_mp4toannexb" : + args; } var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", @@ -594,7 +604,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; + args+= " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; args += " -r 24 -g 24"; diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 14f7175a9..de845c88d 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -134,18 +134,27 @@ namespace MediaBrowser.Api.Playback.Hls { var codec = state.OutputVideoCodec; + var args = "-codec:v:0 " + codec; + + if (state.EnableMpegtsM2TsMode) + { + args += " -mpegts_m2ts_mode 1"; + } + // See if we can save come cpu cycles by avoiding encoding if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) { - return state.VideoStream != null && IsH264(state.VideoStream) ? "-codec:v:0 copy -bsf:v h264_mp4toannexb" : "-codec:v:0 copy"; + return state.VideoStream != null && IsH264(state.VideoStream) ? + args + " -bsf:v h264_mp4toannexb" : + args; } - + var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", state.SegmentLength.ToString(UsCulture)); var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; + args += " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index fb2d30732..5ef72a495 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -124,7 +124,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// System.String. private string GetVideoArguments(StreamState state, string codec) { - var args = "-vcodec " + codec; + var args = "-codec:v:0 " + codec; if (state.EnableMpegtsM2TsMode) { @@ -134,7 +134,9 @@ namespace MediaBrowser.Api.Playback.Progressive // See if we can save come cpu cycles by avoiding encoding if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) { - return state.VideoStream != null && IsH264(state.VideoStream) ? args + " -bsf:v h264_mp4toannexb" : args; + return state.VideoStream != null && IsH264(state.VideoStream) && string.Equals(state.OutputContainer, "ts", StringComparison.OrdinalIgnoreCase) ? + args + " -bsf:v h264_mp4toannexb" : + args; } var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", @@ -182,13 +184,13 @@ namespace MediaBrowser.Api.Playback.Progressive // Get the output codec name var codec = state.OutputAudioCodec; + var args = "-codec:a:0 " + codec; + if (codec.Equals("copy", StringComparison.OrdinalIgnoreCase)) { - return "-acodec copy"; + return args; } - var args = "-acodec " + codec; - // Add the number of audio channels var channels = state.OutputAudioChannels; diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index d26259a3a..40e765f1a 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -11,6 +11,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Threading; +using MediaBrowser.Model.Net; namespace MediaBrowser.Api.Playback { diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs index a2a93d50e..32e6ba076 100644 --- a/MediaBrowser.Api/Subtitles/SubtitleService.cs +++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Subtitles { @@ -175,7 +176,7 @@ namespace MediaBrowser.Api.Subtitles builder.AppendLine("#EXT-X-ENDLIST"); - return ResultFactory.GetResult(builder.ToString(), Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); + return ResultFactory.GetResult(builder.ToString(), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary()); } public object Get(GetSubtitle request) @@ -199,7 +200,7 @@ namespace MediaBrowser.Api.Subtitles var stream = GetSubtitles(request).Result; - return ResultFactory.GetResult(stream, Common.Net.MimeTypes.GetMimeType("file." + request.Format)); + return ResultFactory.GetResult(stream, MimeTypes.GetMimeType("file." + request.Format)); } private async Task GetSubtitles(GetSubtitle request) @@ -240,7 +241,7 @@ namespace MediaBrowser.Api.Subtitles { var result = _subtitleManager.GetRemoteSubtitles(request.Id, CancellationToken.None).Result; - return ResultFactory.GetResult(result.Stream, Common.Net.MimeTypes.GetMimeType("file." + result.Format)); + return ResultFactory.GetResult(result.Stream, MimeTypes.GetMimeType("file." + result.Format)); } public void Post(DownloadRemoteSubtitles request) diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs index 26e4a2669..29172ef05 100644 --- a/MediaBrowser.Api/Sync/SyncService.cs +++ b/MediaBrowser.Api/Sync/SyncService.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; +using MediaBrowser.Model.Users; using ServiceStack; using System; using System.Collections.Generic; @@ -60,7 +61,7 @@ namespace MediaBrowser.Api.Sync [ApiMember(Name = "ParentId", Description = "ParentId", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string ParentId { get; set; } - + [ApiMember(Name = "Category", Description = "Category", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public SyncCategory? Category { get; set; } } @@ -79,6 +80,11 @@ namespace MediaBrowser.Api.Sync public string Id { get; set; } } + [Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")] + public class ReportOfflineActions : List, IReturnVoid + { + } + [Authenticated] public class SyncService : BaseApiService { @@ -173,9 +179,9 @@ namespace MediaBrowser.Api.Sync .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions { Fields = new List - { - ItemFields.SyncInfo - } + { + ItemFields.SyncInfo + } })) .ToList(); @@ -184,5 +190,20 @@ namespace MediaBrowser.Api.Sync return ToOptimizedResult(result); } + + public void Post(ReportOfflineActions request) + { + var task = PostAsync(request); + + Task.WaitAll(task); + } + + public async Task PostAsync(ReportOfflineActions request) + { + foreach (var action in request) + { + await _syncManager.ReportOfflineAction(action).ConfigureAwait(false); + } + } } } diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 9fdfccaaf..140a4ae0e 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -74,7 +74,6 @@ - diff --git a/MediaBrowser.Common/Net/MimeTypes.cs b/MediaBrowser.Common/Net/MimeTypes.cs deleted file mode 100644 index 14052e759..000000000 --- a/MediaBrowser.Common/Net/MimeTypes.cs +++ /dev/null @@ -1,338 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace MediaBrowser.Common.Net -{ - /// - /// Class MimeTypes - /// - public static class MimeTypes - { - /// - /// The json MIME type - /// - public static string JsonMimeType = "application/json"; - - /// - /// Any extension in this list is considered a video file - can be added to at runtime for extensibility - /// - private static readonly List VideoFileExtensions = new List - { - ".mkv", - ".m2t", - ".m2ts", - ".img", - ".iso", - ".mk3d", - ".ts", - ".rmvb", - ".mov", - ".avi", - ".mpg", - ".mpeg", - ".wmv", - ".mp4", - ".divx", - ".dvr-ms", - ".wtv", - ".ogm", - ".ogv", - ".asf", - ".m4v", - ".flv", - ".f4v", - ".3gp", - ".webm", - ".mts", - ".m2v", - ".rec" - }; - - private static readonly Dictionary VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - - /// - /// Determines whether [is video file] [the specified path]. - /// - /// The path. - /// true if [is video file] [the specified path]; otherwise, false. - public static bool IsVideoFile(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - var extension = Path.GetExtension(path); - - if (string.IsNullOrEmpty(extension)) - { - return false; - } - - return VideoFileExtensionsDictionary.ContainsKey(extension); - } - - /// - /// Gets the type of the MIME. - /// - /// The path. - /// System.String. - /// path - /// Argument not supported: + path - public static string GetMimeType(string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException("path"); - } - - var ext = Path.GetExtension(path) ?? string.Empty; - - // http://en.wikipedia.org/wiki/Internet_media_type - // Add more as needed - - // Type video - if (ext.Equals(".mpg", StringComparison.OrdinalIgnoreCase) || ext.EndsWith("mpeg", StringComparison.OrdinalIgnoreCase)) - { - return "video/mpeg"; - } - if (ext.Equals(".ogv", StringComparison.OrdinalIgnoreCase)) - { - return "video/ogg"; - } - if (ext.Equals(".mov", StringComparison.OrdinalIgnoreCase)) - { - return "video/quicktime"; - } - if (ext.Equals(".webm", StringComparison.OrdinalIgnoreCase)) - { - return "video/webm"; - } - if (ext.Equals(".mkv", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-matroska"; - } - if (ext.Equals(".wmv", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-ms-wmv"; - } - if (ext.Equals(".flv", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-flv"; - } - if (ext.Equals(".avi", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-msvideo"; - } - if (ext.Equals(".m4v", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-m4v"; - } - if (ext.EndsWith("asf", StringComparison.OrdinalIgnoreCase)) - { - return "video/x-ms-asf"; - } - if (ext.Equals(".3gp", StringComparison.OrdinalIgnoreCase)) - { - return "video/3gpp"; - } - if (ext.Equals(".3g2", StringComparison.OrdinalIgnoreCase)) - { - return "video/3gpp2"; - } - if (ext.Equals(".ts", StringComparison.OrdinalIgnoreCase)) - { - return "video/mp2t"; - } - if (ext.Equals(".mpd", StringComparison.OrdinalIgnoreCase)) - { - return "video/vnd.mpeg.dash.mpd"; - } - - // Catch-all for all video types that don't require specific mime types - if (VideoFileExtensionsDictionary.ContainsKey(ext)) - { - return "video/" + ext.TrimStart('.').ToLower(); - } - - // Type text - if (ext.Equals(".css", StringComparison.OrdinalIgnoreCase)) - { - return "text/css"; - } - if (ext.Equals(".csv", StringComparison.OrdinalIgnoreCase)) - { - return "text/csv"; - } - if (ext.Equals(".html", StringComparison.OrdinalIgnoreCase) || ext.Equals(".htm", StringComparison.OrdinalIgnoreCase)) - { - return "text/html; charset=UTF-8"; - } - if (ext.Equals(".txt", StringComparison.OrdinalIgnoreCase)) - { - return "text/plain"; - } - if (ext.Equals(".xml", StringComparison.OrdinalIgnoreCase)) - { - return "application/xml"; - } - - // Type document - if (ext.Equals(".pdf", StringComparison.OrdinalIgnoreCase)) - { - return "application/pdf"; - } - if (ext.Equals(".mobi", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-mobipocket-ebook"; - } - if (ext.Equals(".epub", StringComparison.OrdinalIgnoreCase)) - { - return "application/epub+zip"; - } - if (ext.Equals(".cbz", StringComparison.OrdinalIgnoreCase) || ext.Equals(".cbr", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-cdisplay"; - } - - // Type image - if (ext.Equals(".gif", StringComparison.OrdinalIgnoreCase)) - { - return "image/gif"; - } - if (ext.Equals(".jpg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".tbn", StringComparison.OrdinalIgnoreCase)) - { - return "image/jpeg"; - } - if (ext.Equals(".png", StringComparison.OrdinalIgnoreCase)) - { - return "image/png"; - } - if (ext.Equals(".webp", StringComparison.OrdinalIgnoreCase)) - { - return "image/webp"; - } - if (ext.Equals(".ico", StringComparison.OrdinalIgnoreCase)) - { - return "image/vnd.microsoft.icon"; - } - - // Type audio - if (ext.Equals(".mp3", StringComparison.OrdinalIgnoreCase)) - { - return "audio/mpeg"; - } - if (ext.Equals(".m4a", StringComparison.OrdinalIgnoreCase) || ext.Equals(".aac", StringComparison.OrdinalIgnoreCase)) - { - return "audio/mp4"; - } - if (ext.Equals(".webma", StringComparison.OrdinalIgnoreCase)) - { - return "audio/webm"; - } - if (ext.Equals(".wav", StringComparison.OrdinalIgnoreCase)) - { - return "audio/wav"; - } - if (ext.Equals(".wma", StringComparison.OrdinalIgnoreCase)) - { - return "audio/x-ms-wma"; - } - if (ext.Equals(".flac", StringComparison.OrdinalIgnoreCase)) - { - return "audio/flac"; - } - if (ext.Equals(".aac", StringComparison.OrdinalIgnoreCase)) - { - return "audio/x-aac"; - } - if (ext.Equals(".ogg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".oga", StringComparison.OrdinalIgnoreCase)) - { - return "audio/ogg"; - } - - // Playlists - if (ext.Equals(".m3u8", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-mpegURL"; - } - - // Misc - if (ext.Equals(".dll", StringComparison.OrdinalIgnoreCase)) - { - return "application/octet-stream"; - } - - // Web - if (ext.Equals(".js", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-javascript"; - } - if (ext.Equals(".json", StringComparison.OrdinalIgnoreCase)) - { - return JsonMimeType; - } - if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase)) - { - return "application/x-javascript"; - } - - if (ext.Equals(".woff", StringComparison.OrdinalIgnoreCase)) - { - return "font/woff"; - } - - if (ext.Equals(".ttf", StringComparison.OrdinalIgnoreCase)) - { - return "font/ttf"; - } - if (ext.Equals(".eot", StringComparison.OrdinalIgnoreCase)) - { - return "application/vnd.ms-fontobject"; - } - if (ext.Equals(".svg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".svgz", StringComparison.OrdinalIgnoreCase)) - { - return "image/svg+xml"; - } - - if (ext.Equals(".srt", StringComparison.OrdinalIgnoreCase)) - { - return "text/plain"; - } - - if (ext.Equals(".vtt", StringComparison.OrdinalIgnoreCase)) - { - return "text/vtt"; - } - - if (ext.Equals(".ttml", StringComparison.OrdinalIgnoreCase)) - { - return "application/ttml+xml"; - } - - if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase)) - { - return "application/octet-stream"; - } - - throw new ArgumentException("Argument not supported: " + path); - } - - private static readonly Dictionary MimeExtensions = - new Dictionary(StringComparer.OrdinalIgnoreCase) - { - {"image/jpeg", "jpg"}, - {"image/jpg", "jpg"}, - {"image/png", "png"}, - {"image/gif", "gif"}, - {"image/webp", "webp"} - }; - - public static string ToExtension(string mimeType) - { - return "." + MimeExtensions[mimeType]; - } - } -} diff --git a/MediaBrowser.Controller/Library/IUserDataManager.cs b/MediaBrowser.Controller/Library/IUserDataManager.cs index 226f77525..06e7d1763 100644 --- a/MediaBrowser.Controller/Library/IUserDataManager.cs +++ b/MediaBrowser.Controller/Library/IUserDataManager.cs @@ -61,5 +61,9 @@ namespace MediaBrowser.Controller.Library /// Task SaveAllUserData(Guid userId, IEnumerable userData, CancellationToken cancellationToken); + /// + /// Updates playstate for an item and returns true or false indicating if it was played to completion + /// + bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks); } } diff --git a/MediaBrowser.Controller/Sync/ISyncManager.cs b/MediaBrowser.Controller/Sync/ISyncManager.cs index 47339f677..e16a978c3 100644 --- a/MediaBrowser.Controller/Sync/ISyncManager.cs +++ b/MediaBrowser.Controller/Sync/ISyncManager.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; using System.Collections.Generic; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Sync { @@ -80,5 +81,19 @@ namespace MediaBrowser.Controller.Sync /// The identifier. /// SyncJobItem. SyncJobItem GetJobItem(string id); + + /// + /// Gets the job item information. + /// + /// The identifier. + /// SyncedItem. + SyncedItem GetJobItemInfo(string id); + + /// + /// Reports the offline action. + /// + /// The action. + /// Task. + Task ReportOfflineAction(UserAction action); } } diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index bdb1c4cbf..d1941c856 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -18,6 +18,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Xml; +using MediaBrowser.Model.Net; namespace MediaBrowser.Dlna.Didl { diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index a131e7016..7f83aa61d 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -169,8 +169,8 @@ namespace MediaBrowser.LocalMetadata.Images var names = new List { "folder", - "cover", "poster", + "cover", "default" }; diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index a388e0edb..68df777bd 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -10,8 +10,8 @@ Properties MediaBrowser.Model MediaBrowser.Model - v4.0 - Profile344 + v4.5 + Profile259 512 {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} ..\ @@ -479,9 +479,6 @@ Dto\RecommendationType.cs - - Dto\StreamOptions.cs - Dto\StudioDto.cs @@ -797,6 +794,12 @@ Net\HttpException.cs + + Net\HttpResponse.cs + + + Net\MimeTypes.cs + Net\NetworkShare.cs @@ -1037,18 +1040,24 @@ Session\UserDataChangeInfo.cs + + Sync\ItemFIleInfo.cs + + + Sync\ItemFileType.cs + Sync\SyncCategory.cs Sync\SyncDialogOptions.cs + + Sync\SyncedItem.cs + Sync\SyncHelper.cs - - Sync\SyncItem.cs - Sync\SyncJob.cs @@ -1151,6 +1160,12 @@ Users\PinRedeemResult.cs + + Users\UserAction.cs + + + Users\UserActionType.cs + Users\UserPolicy.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 5bacb73d7..bc4e58233 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -444,9 +444,6 @@ Dto\RecommendationType.cs - - Dto\StreamOptions.cs - Dto\StudioDto.cs @@ -756,6 +753,12 @@ Net\HttpException.cs + + Net\HttpResponse.cs + + + Net\MimeTypes.cs + Net\NetworkShare.cs @@ -996,18 +999,24 @@ Session\UserDataChangeInfo.cs + + Sync\ItemFIleInfo.cs + + + Sync\ItemFileType.cs + Sync\SyncCategory.cs Sync\SyncDialogOptions.cs + + Sync\SyncedItem.cs + Sync\SyncHelper.cs - - Sync\SyncItem.cs - Sync\SyncJob.cs @@ -1110,6 +1119,12 @@ Users\PinRedeemResult.cs + + Users\UserAction.cs + + + Users\UserActionType.cs + Users\UserPolicy.cs diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 0181325fe..883e54308 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -7,6 +7,7 @@ using MediaBrowser.Model.Events; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Notifications; using MediaBrowser.Model.Playlists; using MediaBrowser.Model.Plugins; @@ -185,6 +186,22 @@ namespace MediaBrowser.Model.ApiClient /// url Task GetImageStreamAsync(string url, CancellationToken cancellationToken = default(CancellationToken)); + /// + /// Gets the stream. + /// + /// The URL. + /// The cancellation token. + /// Task<Stream>. + Task GetStream(string url, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Gets the response. + /// + /// The URL. + /// The cancellation token. + /// Task<HttpResponse>. + Task GetResponse(string url, CancellationToken cancellationToken = default(CancellationToken)); + /// /// Updates the user configuration. /// @@ -1299,15 +1316,6 @@ namespace MediaBrowser.Model.ApiClient /// Task<QueryResult<BaseItemDto>>. Task> GetPlaylistItems(PlaylistItemQuery query); - /// - /// Gets the url needed to stream an audio file - /// - /// The options. - /// System.String. - /// options - [Obsolete] - string GetAudioStreamUrl(StreamOptions options); - /// /// Gets the url needed to stream a video file /// @@ -1411,5 +1419,19 @@ namespace MediaBrowser.Model.ApiClient /// The web socket factory. /// The keep alive timer ms. void OpenWebSocket(Func webSocketFactory, int keepAliveTimerMs = 60000); + + /// + /// Reports the offline actions. + /// + /// The actions. + /// Task. + Task ReportOfflineActions(List actions); + + /// + /// Gets the ready synchronize items. + /// + /// The target identifier. + /// List<SyncedItem>. + Task> GetReadySyncItems(string targetId); } } \ No newline at end of file diff --git a/MediaBrowser.Model/Dto/StreamOptions.cs b/MediaBrowser.Model/Dto/StreamOptions.cs deleted file mode 100644 index 5b7cdc6fb..000000000 --- a/MediaBrowser.Model/Dto/StreamOptions.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Dto -{ - /// - /// Class StreamOptions - /// - [Obsolete] - public class StreamOptions - { - /// - /// Gets or sets the audio bit rate. - /// - /// The audio bit rate. - public int? AudioBitRate { get; set; } - - /// - /// Gets or sets the audio codec. - /// Omit to copy the original stream - /// - /// The audio encoding format. - public string AudioCodec { get; set; } - - /// - /// Gets or sets the item id. - /// - /// The item id. - public string ItemId { get; set; } - - /// - /// Gets or sets the max audio channels. - /// - /// The max audio channels. - public int? MaxAudioChannels { get; set; } - - /// - /// Gets or sets the max audio sample rate. - /// - /// The max audio sample rate. - public int? MaxAudioSampleRate { get; set; } - - /// - /// Gets or sets the start time ticks. - /// - /// The start time ticks. - public long? StartTimeTicks { get; set; } - - /// - /// Gets or sets a value indicating whether the original media should be served statically - /// Only used with progressive streaming - /// - /// true if static; otherwise, false. - public bool? Static { get; set; } - - /// - /// Gets or sets the output file extension. - /// - /// The output file extension. - public string OutputFileExtension { get; set; } - - /// - /// Gets or sets the device id. - /// - /// The device id. - public string DeviceId { get; set; } - } -} diff --git a/MediaBrowser.Model/Dto/VideoStreamOptions.cs b/MediaBrowser.Model/Dto/VideoStreamOptions.cs index 606e928f2..e9a83bd12 100644 --- a/MediaBrowser.Model/Dto/VideoStreamOptions.cs +++ b/MediaBrowser.Model/Dto/VideoStreamOptions.cs @@ -6,8 +6,64 @@ namespace MediaBrowser.Model.Dto /// Class VideoStreamOptions /// [Obsolete] - public class VideoStreamOptions : StreamOptions + public class VideoStreamOptions { + /// + /// Gets or sets the audio bit rate. + /// + /// The audio bit rate. + public int? AudioBitRate { get; set; } + + /// + /// Gets or sets the audio codec. + /// Omit to copy the original stream + /// + /// The audio encoding format. + public string AudioCodec { get; set; } + + /// + /// Gets or sets the item id. + /// + /// The item id. + public string ItemId { get; set; } + + /// + /// Gets or sets the max audio channels. + /// + /// The max audio channels. + public int? MaxAudioChannels { get; set; } + + /// + /// Gets or sets the max audio sample rate. + /// + /// The max audio sample rate. + public int? MaxAudioSampleRate { get; set; } + + /// + /// Gets or sets the start time ticks. + /// + /// The start time ticks. + public long? StartTimeTicks { get; set; } + + /// + /// Gets or sets a value indicating whether the original media should be served statically + /// Only used with progressive streaming + /// + /// true if static; otherwise, false. + public bool? Static { get; set; } + + /// + /// Gets or sets the output file extension. + /// + /// The output file extension. + public string OutputFileExtension { get; set; } + + /// + /// Gets or sets the device id. + /// + /// The device id. + public string DeviceId { get; set; } + /// /// Gets or sets the video codec. /// Omit to copy diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index e1f0e78f4..47a31853b 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -133,7 +133,6 @@ - @@ -155,6 +154,8 @@ + + @@ -366,10 +367,12 @@ + + + - @@ -423,6 +426,8 @@ + + diff --git a/MediaBrowser.Model/Net/HttpResponse.cs b/MediaBrowser.Model/Net/HttpResponse.cs new file mode 100644 index 000000000..f4bd8e681 --- /dev/null +++ b/MediaBrowser.Model/Net/HttpResponse.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; + +namespace MediaBrowser.Model.Net +{ + public class HttpResponse : IDisposable + { + /// + /// Gets or sets the type of the content. + /// + /// The type of the content. + public string ContentType { get; set; } + + /// + /// Gets or sets the response URL. + /// + /// The response URL. + public string ResponseUrl { get; set; } + + /// + /// Gets or sets the content. + /// + /// The content. + public Stream Content { get; set; } + + /// + /// Gets or sets the status code. + /// + /// The status code. + public HttpStatusCode StatusCode { get; set; } + + /// + /// Gets or sets the length of the content. + /// + /// The length of the content. + public long? ContentLength { get; set; } + + /// + /// Gets or sets the headers. + /// + /// The headers. + public Dictionary Headers { get; set; } + + private readonly IDisposable _disposable; + + public HttpResponse(IDisposable disposable) + { + _disposable = disposable; + } + public HttpResponse() + { + } + + public void Dispose() + { + if (_disposable != null) + { + _disposable.Dispose(); + } + } + } +} diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs new file mode 100644 index 000000000..6eaac8f03 --- /dev/null +++ b/MediaBrowser.Model/Net/MimeTypes.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Model.Net +{ + /// + /// Class MimeTypes + /// + public static class MimeTypes + { + /// + /// Any extension in this list is considered a video file - can be added to at runtime for extensibility + /// + private static readonly List VideoFileExtensions = new List + { + ".mkv", + ".m2t", + ".m2ts", + ".img", + ".iso", + ".mk3d", + ".ts", + ".rmvb", + ".mov", + ".avi", + ".mpg", + ".mpeg", + ".wmv", + ".mp4", + ".divx", + ".dvr-ms", + ".wtv", + ".ogm", + ".ogv", + ".asf", + ".m4v", + ".flv", + ".f4v", + ".3gp", + ".webm", + ".mts", + ".m2v", + ".rec" + }; + + private static readonly Dictionary VideoFileExtensionsDictionary = VideoFileExtensions.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + + // http://en.wikipedia.org/wiki/Internet_media_type + // Add more as needed + + private static readonly Dictionary MimeTypeLookup = + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".tbn", "image/jpeg"}, + {".png", "image/png"}, + {".gif", "image/gif"}, + {".webp", "image/webp"}, + {".ico", "image/vnd.microsoft.icon"}, + {".mpg", "video/mpeg"}, + {".mpeg", "video/mpeg"}, + {".ogv", "video/ogg"}, + {".mov", "video/quicktime"}, + {".webm", "video/webm"}, + {".mkv", "video/x-matroska"}, + {".wmv", "video/x-ms-wmv"}, + {".flv", "video/x-flv"}, + {".avi", "video/x-msvideo"}, + {".asf", "video/x-ms-asf"}, + {".m4v", "video/x-m4v"} + }; + + private static readonly Dictionary ExtensionLookup = + MimeTypeLookup + .GroupBy(i => i.Value) + .ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase); + + /// + /// Gets the type of the MIME. + /// + /// The path. + /// System.String. + /// path + /// Argument not supported: + path + public static string GetMimeType(string path) + { + if (string.IsNullOrEmpty(path)) + { + throw new ArgumentNullException("path"); + } + + var ext = Path.GetExtension(path) ?? string.Empty; + + string result; + if (MimeTypeLookup.TryGetValue(ext, out result)) + { + return result; + } + + // Type video + if (ext.Equals(".3gp", StringComparison.OrdinalIgnoreCase)) + { + return "video/3gpp"; + } + if (ext.Equals(".3g2", StringComparison.OrdinalIgnoreCase)) + { + return "video/3gpp2"; + } + if (ext.Equals(".ts", StringComparison.OrdinalIgnoreCase)) + { + return "video/mp2t"; + } + if (ext.Equals(".mpd", StringComparison.OrdinalIgnoreCase)) + { + return "video/vnd.mpeg.dash.mpd"; + } + + // Catch-all for all video types that don't require specific mime types + if (VideoFileExtensionsDictionary.ContainsKey(ext)) + { + return "video/" + ext.TrimStart('.').ToLower(); + } + + // Type text + if (ext.Equals(".css", StringComparison.OrdinalIgnoreCase)) + { + return "text/css"; + } + if (ext.Equals(".csv", StringComparison.OrdinalIgnoreCase)) + { + return "text/csv"; + } + if (ext.Equals(".html", StringComparison.OrdinalIgnoreCase) || ext.Equals(".htm", StringComparison.OrdinalIgnoreCase)) + { + return "text/html; charset=UTF-8"; + } + if (ext.Equals(".txt", StringComparison.OrdinalIgnoreCase)) + { + return "text/plain"; + } + if (ext.Equals(".xml", StringComparison.OrdinalIgnoreCase)) + { + return "application/xml"; + } + + // Type document + if (ext.Equals(".pdf", StringComparison.OrdinalIgnoreCase)) + { + return "application/pdf"; + } + if (ext.Equals(".mobi", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-mobipocket-ebook"; + } + if (ext.Equals(".epub", StringComparison.OrdinalIgnoreCase)) + { + return "application/epub+zip"; + } + if (ext.Equals(".cbz", StringComparison.OrdinalIgnoreCase) || ext.Equals(".cbr", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-cdisplay"; + } + + // Type audio + if (ext.Equals(".mp3", StringComparison.OrdinalIgnoreCase)) + { + return "audio/mpeg"; + } + if (ext.Equals(".m4a", StringComparison.OrdinalIgnoreCase) || ext.Equals(".aac", StringComparison.OrdinalIgnoreCase)) + { + return "audio/mp4"; + } + if (ext.Equals(".webma", StringComparison.OrdinalIgnoreCase)) + { + return "audio/webm"; + } + if (ext.Equals(".wav", StringComparison.OrdinalIgnoreCase)) + { + return "audio/wav"; + } + if (ext.Equals(".wma", StringComparison.OrdinalIgnoreCase)) + { + return "audio/x-ms-wma"; + } + if (ext.Equals(".flac", StringComparison.OrdinalIgnoreCase)) + { + return "audio/flac"; + } + if (ext.Equals(".aac", StringComparison.OrdinalIgnoreCase)) + { + return "audio/x-aac"; + } + if (ext.Equals(".ogg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".oga", StringComparison.OrdinalIgnoreCase)) + { + return "audio/ogg"; + } + + // Playlists + if (ext.Equals(".m3u8", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-mpegURL"; + } + + // Misc + if (ext.Equals(".dll", StringComparison.OrdinalIgnoreCase)) + { + return "application/octet-stream"; + } + + // Web + if (ext.Equals(".js", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-javascript"; + } + if (ext.Equals(".json", StringComparison.OrdinalIgnoreCase)) + { + return "application/json"; + } + if (ext.Equals(".map", StringComparison.OrdinalIgnoreCase)) + { + return "application/x-javascript"; + } + + if (ext.Equals(".woff", StringComparison.OrdinalIgnoreCase)) + { + return "font/woff"; + } + + if (ext.Equals(".ttf", StringComparison.OrdinalIgnoreCase)) + { + return "font/ttf"; + } + if (ext.Equals(".eot", StringComparison.OrdinalIgnoreCase)) + { + return "application/vnd.ms-fontobject"; + } + if (ext.Equals(".svg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".svgz", StringComparison.OrdinalIgnoreCase)) + { + return "image/svg+xml"; + } + + if (ext.Equals(".srt", StringComparison.OrdinalIgnoreCase)) + { + return "text/plain"; + } + + if (ext.Equals(".vtt", StringComparison.OrdinalIgnoreCase)) + { + return "text/vtt"; + } + + if (ext.Equals(".ttml", StringComparison.OrdinalIgnoreCase)) + { + return "application/ttml+xml"; + } + + if (ext.Equals(".bif", StringComparison.OrdinalIgnoreCase)) + { + return "application/octet-stream"; + } + + throw new ArgumentException("Argument not supported: " + path); + } + + public static string ToExtension(string mimeType) + { + return ExtensionLookup[mimeType]; + } + } +} diff --git a/MediaBrowser.Model/Sync/ItemFIleInfo.cs b/MediaBrowser.Model/Sync/ItemFIleInfo.cs new file mode 100644 index 000000000..6ae9ceb18 --- /dev/null +++ b/MediaBrowser.Model/Sync/ItemFIleInfo.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Model.Sync +{ + public class ItemFileInfo + { + /// + /// Gets or sets the type. + /// + /// The type. + public ItemFileType Type { get; set; } + /// + /// Gets or sets the item identifier. + /// + /// The item identifier. + public string ItemId { get; set; } + /// + /// Gets or sets the name. + /// + /// The name. + public string Name { get; set; } + /// + /// Gets or sets the type of the image. + /// + /// The type of the image. + public ImageType ImageType { get; set; } + } +} diff --git a/MediaBrowser.Model/Sync/ItemFileType.cs b/MediaBrowser.Model/Sync/ItemFileType.cs new file mode 100644 index 000000000..305f4c502 --- /dev/null +++ b/MediaBrowser.Model/Sync/ItemFileType.cs @@ -0,0 +1,19 @@ + +namespace MediaBrowser.Model.Sync +{ + public enum ItemFileType + { + /// + /// The media + /// + Media = 0, + /// + /// The image + /// + Image = 1, + /// + /// The subtitles + /// + Subtitles = 2 + } +} diff --git a/MediaBrowser.Model/Sync/SyncItem.cs b/MediaBrowser.Model/Sync/SyncItem.cs deleted file mode 100644 index d50ae98c9..000000000 --- a/MediaBrowser.Model/Sync/SyncItem.cs +++ /dev/null @@ -1,9 +0,0 @@ -using MediaBrowser.Model.Dto; - -namespace MediaBrowser.Model.Sync -{ - public class SyncItem - { - public BaseItemDto Item { get; set; } - } -} diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs index 063f7feb2..d9fb1ed09 100644 --- a/MediaBrowser.Model/Sync/SyncJobItem.cs +++ b/MediaBrowser.Model/Sync/SyncJobItem.cs @@ -22,6 +22,12 @@ namespace MediaBrowser.Model.Sync /// The item identifier. public string ItemId { get; set; } + /// + /// Gets or sets the media source identifier. + /// + /// The media source identifier. + public string MediaSourceId { get; set; } + /// /// Gets or sets the target identifier. /// diff --git a/MediaBrowser.Model/Sync/SyncedItem.cs b/MediaBrowser.Model/Sync/SyncedItem.cs new file mode 100644 index 000000000..784a12bc9 --- /dev/null +++ b/MediaBrowser.Model/Sync/SyncedItem.cs @@ -0,0 +1,38 @@ +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Model.Sync +{ + public class SyncedItem + { + /// + /// Gets or sets the server identifier. + /// + /// The server identifier. + public string ServerId { get; set; } + /// + /// Gets or sets the synchronize job identifier. + /// + /// The synchronize job identifier. + public string SyncJobId { get; set; } + /// + /// Gets or sets the synchronize job item identifier. + /// + /// The synchronize job item identifier. + public string SyncJobItemId { get; set; } + /// + /// Gets or sets the name of the original file. + /// + /// The name of the original file. + public string OriginalFileName { get; set; } + /// + /// Gets or sets the item. + /// + /// The item. + public BaseItemDto Item { get; set; } + /// + /// Gets or sets the user identifier. + /// + /// The user identifier. + public string UserId { get; set; } + } +} diff --git a/MediaBrowser.Model/Users/UserAction.cs b/MediaBrowser.Model/Users/UserAction.cs new file mode 100644 index 000000000..93c22d726 --- /dev/null +++ b/MediaBrowser.Model/Users/UserAction.cs @@ -0,0 +1,14 @@ +using System; + +namespace MediaBrowser.Model.Users +{ + public class UserAction + { + public string ServerId { get; set; } + public string UserId { get; set; } + public string ItemId { get; set; } + public UserActionType Type { get; set; } + public DateTime Date { get; set; } + public long? PositionTicks { get; set; } + } +} diff --git a/MediaBrowser.Model/Users/UserActionType.cs b/MediaBrowser.Model/Users/UserActionType.cs new file mode 100644 index 000000000..493de6272 --- /dev/null +++ b/MediaBrowser.Model/Users/UserActionType.cs @@ -0,0 +1,8 @@ + +namespace MediaBrowser.Model.Users +{ + public enum UserActionType + { + PlayedItem = 0 + } +} diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index 2c97f2c16..700bca0fa 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -16,6 +16,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Net; namespace MediaBrowser.Providers.Manager { diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs index 52c252d24..52ec5c9b1 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Server.Implementations.Connect { LoadCachedAddress(); - _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(10), TimeSpan.FromHours(6)); + _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3)); } private async void TimerCallback(object state) diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs index e13e27d5a..681d3ac5e 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -12,7 +12,7 @@ using System.IO; using System.Net; using System.Text; using System.Threading.Tasks; -using MimeTypes = MediaBrowser.Common.Net.MimeTypes; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Server.Implementations.HttpServer { diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs index cc261c3e7..e3447afc9 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/BoxSetResolver.cs @@ -30,12 +30,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { return null; } - - // This is a bit of a one-off but it's here to combat MCM's over-aggressive placement of collection.xml files where they don't belong, including in series folders. - if (args.ContainsMetaFileByName("series.xml")) - { - return null; - } if (filename.IndexOf("[boxset]", StringComparison.OrdinalIgnoreCase) != -1 || args.ContainsFileSystemEntryByName("collection.xml")) diff --git a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs index 3f132ab7f..ed3503c1b 100644 --- a/MediaBrowser.Server.Implementations/Library/UserDataManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserDataManager.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using MediaBrowser.Common.Events; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Model.Dto; @@ -23,9 +25,11 @@ namespace MediaBrowser.Server.Implementations.Library private readonly ConcurrentDictionary _userData = new ConcurrentDictionary(); private readonly ILogger _logger; + private readonly IServerConfigurationManager _config; - public UserDataManager(ILogManager logManager) + public UserDataManager(ILogManager logManager, IServerConfigurationManager config) { + _config = config; _logger = logManager.GetLogger(GetType().Name); } @@ -35,22 +39,6 @@ namespace MediaBrowser.Server.Implementations.Library /// The repository. public IUserDataRepository Repository { get; set; } - /// - /// Saves the user data. - /// - /// The user id. - /// The item. - /// The user data. - /// The reason. - /// The cancellation token. - /// Task. - /// userData - /// or - /// cancellationToken - /// or - /// userId - /// or - /// key public async Task SaveUserData(Guid userId, IHasUserData item, UserItemData userData, UserDataSaveReason reason, CancellationToken cancellationToken) { if (userData == null) @@ -219,5 +207,59 @@ namespace MediaBrowser.Server.Implementations.Library Key = data.Key }; } + + public bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks) + { + var playedToCompletion = false; + + var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0; + + // If a position has been reported, and if we know the duration + if (positionTicks > 0 && hasRuntime) + { + var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100; + + // Don't track in very beginning + if (pctIn < _config.Configuration.MinResumePct) + { + positionTicks = 0; + } + + // If we're at the end, assume completed + else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value) + { + positionTicks = 0; + data.Played = playedToCompletion = true; + } + + else + { + // Enforce MinResumeDuration + var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds; + + if (durationSeconds < _config.Configuration.MinResumeDurationSeconds) + { + positionTicks = 0; + data.Played = playedToCompletion = true; + } + } + } + else if (!hasRuntime) + { + // If we don't know the runtime we'll just have to assume it was fully played + data.Played = playedToCompletion = true; + positionTicks = 0; + } + + if (item is Audio) + { + positionTicks = 0; + } + + data.PlaybackPositionTicks = positionTicks; + + return playedToCompletion; + } + } } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json index 7a0b1e46a..ad12450df 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json @@ -251,7 +251,6 @@ "HeaderDeleteItem": "Delete Item", "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?", "MessagePleaseEnterNameOrId": "Please enter a name or an external Id.", - "MessageValueNotCorrect": "The value entered is not correct. Please try again.", "MessageItemSaved": "Item saved.", "OptionEnded": "Ended", "OptionContinuing": "Continuing", diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index b5c1ea0d3..f70e110b0 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -252,7 +252,7 @@ "ButtonMoveRight": "Move right", "ButtonBrowseOnlineImages": "Browse online images", "HeaderDeleteItem": "Delete Item", - "ConfirmDeleteItem": "Are you sure you wish to delete this item from your library?", + "ConfirmDeleteItem": "Deleting this item will delete it from both the file system and your media library. Are you sure you wish to continue?", "MessagePleaseEnterNameOrId": "Please enter a name or an external Id.", "MessageValueNotCorrect": "The value entered is not correct. Please try again.", "MessageItemSaved": "Item saved.", diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 1f294c325..4c587d1ab 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -67,12 +67,6 @@ namespace MediaBrowser.Server.Implementations.Session private readonly IAuthenticationRepository _authRepo; private readonly IDeviceManager _deviceManager; - /// - /// Gets or sets the configuration manager. - /// - /// The configuration manager. - private readonly IServerConfigurationManager _configurationManager; - /// /// The _active connections /// @@ -105,18 +99,9 @@ namespace MediaBrowser.Server.Implementations.Session private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1); - /// - /// Initializes a new instance of the class. - /// - /// The user data repository. - /// The configuration manager. - /// The logger. - /// The user repository. - /// The library manager. - public SessionManager(IUserDataManager userDataRepository, IServerConfigurationManager configurationManager, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager) + public SessionManager(IUserDataManager userDataRepository, ILogger logger, IUserRepository userRepository, ILibraryManager libraryManager, IUserManager userManager, IMusicManager musicManager, IDtoService dtoService, IImageProcessor imageProcessor, IItemRepository itemRepo, IJsonSerializer jsonSerializer, IServerApplicationHost appHost, IHttpClient httpClient, IAuthenticationRepository authRepo, IDeviceManager deviceManager) { _userDataRepository = userDataRepository; - _configurationManager = configurationManager; _logger = logger; _userRepository = userRepository; _libraryManager = libraryManager; @@ -689,7 +674,7 @@ namespace MediaBrowser.Server.Implementations.Session if (positionTicks.HasValue) { - UpdatePlayState(item, data, positionTicks.Value); + _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); await _userDataRepository.SaveUserData(userId, item, data, UserDataSaveReason.PlaybackProgress, CancellationToken.None).ConfigureAwait(false); } @@ -779,7 +764,7 @@ namespace MediaBrowser.Server.Implementations.Session if (positionTicks.HasValue) { - playedToCompletion = UpdatePlayState(item, data, positionTicks.Value); + playedToCompletion = _userDataRepository.UpdatePlayState(item, data, positionTicks.Value); } else { @@ -795,65 +780,6 @@ namespace MediaBrowser.Server.Implementations.Session return playedToCompletion; } - /// - /// Updates playstate position for an item but does not save - /// - /// The item - /// User data for the item - /// The current playback position - private bool UpdatePlayState(BaseItem item, UserItemData data, long positionTicks) - { - var playedToCompletion = false; - - var hasRuntime = item.RunTimeTicks.HasValue && item.RunTimeTicks > 0; - - // If a position has been reported, and if we know the duration - if (positionTicks > 0 && hasRuntime) - { - var pctIn = Decimal.Divide(positionTicks, item.RunTimeTicks.Value) * 100; - - // Don't track in very beginning - if (pctIn < _configurationManager.Configuration.MinResumePct) - { - positionTicks = 0; - } - - // If we're at the end, assume completed - else if (pctIn > _configurationManager.Configuration.MaxResumePct || positionTicks >= item.RunTimeTicks.Value) - { - positionTicks = 0; - data.Played = playedToCompletion = true; - } - - else - { - // Enforce MinResumeDuration - var durationSeconds = TimeSpan.FromTicks(item.RunTimeTicks.Value).TotalSeconds; - - if (durationSeconds < _configurationManager.Configuration.MinResumeDurationSeconds) - { - positionTicks = 0; - data.Played = playedToCompletion = true; - } - } - } - else if (!hasRuntime) - { - // If we don't know the runtime we'll just have to assume it was fully played - data.Played = playedToCompletion = true; - positionTicks = 0; - } - - if (item is Audio) - { - positionTicks = 0; - } - - data.PlaybackPositionTicks = positionTicks; - - return playedToCompletion; - } - /// /// Gets the session. /// diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index 6dda869ee..5c933b4bd 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -358,6 +358,9 @@ namespace MediaBrowser.Server.Implementations.Sync var streamInfo = new StreamBuilder().BuildVideoItem(options); var mediaSource = streamInfo.MediaSource; + jobItem.MediaSourceId = streamInfo.MediaSourceId; + await _syncRepo.Update(jobItem).ConfigureAwait(false); + if (streamInfo.PlayMethod != PlayMethod.Transcode) { if (mediaSource.Protocol == MediaProtocol.File) @@ -389,6 +392,9 @@ namespace MediaBrowser.Server.Implementations.Sync var streamInfo = new StreamBuilder().BuildAudioItem(options); var mediaSource = streamInfo.MediaSource; + jobItem.MediaSourceId = streamInfo.MediaSourceId; + await _syncRepo.Update(jobItem).ConfigureAwait(false); + if (streamInfo.PlayMethod != PlayMethod.Transcode) { if (mediaSource.Protocol == MediaProtocol.File) diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 3006c1be9..f92cbeda3 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -1,5 +1,9 @@ -using MediaBrowser.Common.Extensions; +using System.IO; +using MediaBrowser.Common; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; @@ -7,10 +11,12 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; +using MediaBrowser.Model.Users; using MoreLinq; using System; using System.Collections.Generic; @@ -26,16 +32,20 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IImageProcessor _imageProcessor; private readonly ILogger _logger; private readonly IUserManager _userManager; + private readonly IDtoService _dtoService; + private readonly IApplicationHost _appHost; private ISyncProvider[] _providers = { }; - public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager) + public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, IDtoService dtoService, IApplicationHost appHost) { _libraryManager = libraryManager; _repo = repo; _imageProcessor = imageProcessor; _logger = logger; _userManager = userManager; + _dtoService = dtoService; + _appHost = appHost; } public void AddParts(IEnumerable providers) @@ -251,6 +261,11 @@ namespace MediaBrowser.Server.Implementations.Sync } } + if (item is LiveTvChannel || item is IChannelItem || item is ILiveTvRecording) + { + return false; + } + return true; } @@ -301,5 +316,54 @@ namespace MediaBrowser.Server.Implementations.Sync { return _repo.GetJobItems(query); } + + public SyncedItem GetJobItemInfo(string id) + { + var jobItem = GetJobItem(id); + var job = _repo.GetJob(jobItem.JobId); + + var libraryItem = _libraryManager.GetItemById(jobItem.ItemId); + + var syncedItem = new SyncedItem + { + SyncJobId = jobItem.JobId, + SyncJobItemId = jobItem.Id, + ServerId = _appHost.SystemId, + UserId = job.UserId + }; + + // Get everything + var fields = Enum.GetNames(typeof(ItemFields)).Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)).ToList(); + + syncedItem.Item = _dtoService.GetBaseItemDto(libraryItem, new DtoOptions + { + Fields = fields + }); + + // TODO: this should be the media source of the transcoded output + syncedItem.Item.MediaSources = syncedItem.Item.MediaSources + .Where(i => string.Equals(i.Id, jobItem.MediaSourceId)) + .ToList(); + + var mediaSource = syncedItem.Item.MediaSources + .FirstOrDefault(i => string.Equals(i.Id, jobItem.MediaSourceId)); + + // This will be null for items that are not audio/video + if (mediaSource == null) + { + syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); + } + else + { + syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); + } + + return syncedItem; + } + + public Task ReportOfflineAction(UserAction action) + { + return Task.FromResult(true); + } } } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index e65d4c66e..2ff6d7ae6 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Sync public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "sync6.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "sync7.db"); _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); @@ -45,7 +45,7 @@ namespace MediaBrowser.Server.Implementations.Sync "create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Quality TEXT NOT NULL, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)", "create index if not exists idx_SyncJobs on SyncJobs(Id)", - "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)", + "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, MediaSourceId TEXT, JobId TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)", "create index if not exists idx_SyncJobItems on SyncJobs(Id)", //pragmas @@ -90,10 +90,11 @@ namespace MediaBrowser.Server.Implementations.Sync _saveJobCommand.Parameters.Add(_saveJobCommand, "@ItemCount"); _saveJobItemCommand = _connection.CreateCommand(); - _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)"; + _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @MediaSourceId, @JobId, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)"; _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Id"); _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@ItemId"); + _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@MediaSourceId"); _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@JobId"); _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@OutputPath"); _saveJobItemCommand.Parameters.Add(_saveJobCommand, "@Status"); @@ -103,7 +104,7 @@ namespace MediaBrowser.Server.Implementations.Sync } private const string BaseJobSelectText = "select Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs"; - private const string BaseJobItemSelectText = "select Id, ItemId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems"; + private const string BaseJobItemSelectText = "select Id, ItemId, MediaSourceId, JobId, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems"; public SyncJob GetJob(string id) { @@ -556,6 +557,7 @@ namespace MediaBrowser.Server.Implementations.Sync _saveJobItemCommand.GetParameter(index++).Value = new Guid(jobItem.Id); _saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemId; + _saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSourceId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.JobId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.OutputPath; _saveJobItemCommand.GetParameter(index++).Value = jobItem.Status; @@ -606,26 +608,27 @@ namespace MediaBrowser.Server.Implementations.Sync { Id = reader.GetGuid(0).ToString("N"), ItemId = reader.GetString(1), - JobId = reader.GetString(2) + MediaSourceId = reader.GetString(2), + JobId = reader.GetString(3) }; - if (!reader.IsDBNull(3)) + if (!reader.IsDBNull(4)) { - info.OutputPath = reader.GetString(3); + info.OutputPath = reader.GetString(4); } - if (!reader.IsDBNull(4)) + if (!reader.IsDBNull(5)) { - info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(4), true); + info.Status = (SyncJobItemStatus)Enum.Parse(typeof(SyncJobItemStatus), reader.GetString(5), true); } - info.TargetId = reader.GetString(5); + info.TargetId = reader.GetString(6); - info.DateCreated = reader.GetDateTime(6); + info.DateCreated = reader.GetDateTime(7); - if (!reader.IsDBNull(7)) + if (!reader.IsDBNull(8)) { - info.Progress = reader.GetDouble(7); + info.Progress = reader.GetDouble(8); } return info; diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index c2520ff6b..06d63b355 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -410,7 +410,7 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance(() => new BdInfoExaminer()); - UserDataManager = new UserDataManager(LogManager); + UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager); RegisterSingleInstance(UserDataManager); UserRepository = await GetUserRepository().ConfigureAwait(false); @@ -470,7 +470,7 @@ namespace MediaBrowser.Server.Startup.Common ImageProcessor = new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, MediaEncoder); RegisterSingleInstance(ImageProcessor); - SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager); + SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, DtoService, this); RegisterSingleInstance(SyncManager); DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this); @@ -485,7 +485,7 @@ namespace MediaBrowser.Server.Startup.Common DeviceManager = new DeviceManager(new DeviceRepository(ApplicationPaths, JsonSerializer, Logger), UserManager, FileSystemManager, LibraryMonitor, ConfigurationManager, LogManager.GetLogger("DeviceManager")); RegisterSingleInstance(DeviceManager); - SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager); + SessionManager = new SessionManager(UserDataManager, Logger, UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, ItemRepository, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager); RegisterSingleInstance(SessionManager); var newsService = new Implementations.News.NewsService(ApplicationPaths, JsonSerializer); diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index eb44f6d35..6e3439079 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -8,6 +8,7 @@ using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using ServiceStack; using ServiceStack.Web; diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 6dfb39b4c..8f4e916dd 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.523 + 3.0.530 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 49fd835c3..01fe110fb 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.523 + 3.0.530 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index d5164f025..86a6d19d3 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.523 + 3.0.530 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 297b0f07e..686396f89 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.523 + 3.0.530 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 From 2e53ff1fd0379ed6e4861f062815402230205ff0 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 26 Dec 2014 14:34:39 -0500 Subject: move files out of common --- .../ScheduledTasksWebSocketListener.cs | 1 + .../Session/SessionInfoWebSocketListener.cs | 1 + .../System/ActivityLogWebSocketListener.cs | 4 +- .../System/SystemInfoWebSocketListener.cs | 1 + .../Configuration/ConfigurationHelper.cs | 59 ++++ .../MediaBrowser.Common.Implementations.csproj | 1 + .../Configuration/ConfigurationHelper.cs | 59 ---- MediaBrowser.Common/MediaBrowser.Common.csproj | 3 - .../Net/BasePeriodicWebSocketListener.cs | 326 -------------------- MediaBrowser.Common/Net/IWebSocketListener.cs | 17 -- .../MediaBrowser.Controller.csproj | 2 + .../Net/BasePeriodicWebSocketListener.cs | 327 +++++++++++++++++++++ MediaBrowser.Controller/Net/IWebSocketListener.cs | 18 ++ .../Session/SessionWebSocketListener.cs | 1 + 14 files changed, 413 insertions(+), 407 deletions(-) create mode 100644 MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs delete mode 100644 MediaBrowser.Common/Configuration/ConfigurationHelper.cs delete mode 100644 MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs delete mode 100644 MediaBrowser.Common/Net/IWebSocketListener.cs create mode 100644 MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs create mode 100644 MediaBrowser.Controller/Net/IWebSocketListener.cs (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index f34c53b16..cb8f91ab6 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Tasks; diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs index e6b525e53..25130776e 100644 --- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; diff --git a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs index 4629b2a8c..a951cd3d6 100644 --- a/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs +++ b/MediaBrowser.Api/System/ActivityLogWebSocketListener.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Activity; +using MediaBrowser.Controller.Activity; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Activity; using MediaBrowser.Model.Events; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs index c20cef3b3..49a3e3291 100644 --- a/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs +++ b/MediaBrowser.Api/System/SystemInfoWebSocketListener.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller; +using MediaBrowser.Controller.Net; using MediaBrowser.Model.Logging; using MediaBrowser.Model.System; using System.Threading.Tasks; diff --git a/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs new file mode 100644 index 000000000..ff5b8bd59 --- /dev/null +++ b/MediaBrowser.Common.Implementations/Configuration/ConfigurationHelper.cs @@ -0,0 +1,59 @@ +using MediaBrowser.Model.Serialization; +using System; +using System.IO; +using System.Linq; + +namespace MediaBrowser.Common.Implementations.Configuration +{ + /// + /// Class ConfigurationHelper + /// + public static class ConfigurationHelper + { + /// + /// Reads an xml configuration file from the file system + /// It will immediately re-serialize and save if new serialization data is available due to property changes + /// + /// The type. + /// The path. + /// The XML serializer. + /// System.Object. + public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer) + { + object configuration; + + byte[] buffer = null; + + // Use try/catch to avoid the extra file system lookup using File.Exists + try + { + buffer = File.ReadAllBytes(path); + + configuration = xmlSerializer.DeserializeFromBytes(type, buffer); + } + catch (Exception) + { + configuration = Activator.CreateInstance(type); + } + + using (var stream = new MemoryStream()) + { + xmlSerializer.SerializeToStream(configuration, stream); + + // Take the object we just got and serialize it back to bytes + var newBytes = stream.ToArray(); + + // If the file didn't exist before, or if something has changed, re-save + if (buffer == null || !buffer.SequenceEqual(newBytes)) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + // Save it after load in case we got new items + File.WriteAllBytes(path, newBytes); + } + + return configuration; + } + } + } +} diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 42a402940..0aaf0b4e0 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -80,6 +80,7 @@ + diff --git a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common/Configuration/ConfigurationHelper.cs deleted file mode 100644 index 7212b70e1..000000000 --- a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs +++ /dev/null @@ -1,59 +0,0 @@ -using MediaBrowser.Model.Serialization; -using System; -using System.IO; -using System.Linq; - -namespace MediaBrowser.Common.Configuration -{ - /// - /// Class ConfigurationHelper - /// - public static class ConfigurationHelper - { - /// - /// Reads an xml configuration file from the file system - /// It will immediately re-serialize and save if new serialization data is available due to property changes - /// - /// The type. - /// The path. - /// The XML serializer. - /// System.Object. - public static object GetXmlConfiguration(Type type, string path, IXmlSerializer xmlSerializer) - { - object configuration; - - byte[] buffer = null; - - // Use try/catch to avoid the extra file system lookup using File.Exists - try - { - buffer = File.ReadAllBytes(path); - - configuration = xmlSerializer.DeserializeFromBytes(type, buffer); - } - catch (Exception) - { - configuration = Activator.CreateInstance(type); - } - - using (var stream = new MemoryStream()) - { - xmlSerializer.SerializeToStream(configuration, stream); - - // Take the object we just got and serialize it back to bytes - var newBytes = stream.ToArray(); - - // If the file didn't exist before, or if something has changed, re-save - if (buffer == null || !buffer.SequenceEqual(newBytes)) - { - Directory.CreateDirectory(Path.GetDirectoryName(path)); - - // Save it after load in case we got new items - File.WriteAllBytes(path, newBytes); - } - - return configuration; - } - } - } -} diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 140a4ae0e..b4cc17f51 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -53,7 +53,6 @@ Properties\SharedVersion.cs - @@ -64,11 +63,9 @@ - - diff --git a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs deleted file mode 100644 index a2af3707b..000000000 --- a/MediaBrowser.Common/Net/BasePeriodicWebSocketListener.cs +++ /dev/null @@ -1,326 +0,0 @@ -using MediaBrowser.Model.Logging; -using MediaBrowser.Model.Net; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// - /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received - /// - /// The type of the T return data type. - /// The type of the T state type. - public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable - where TStateType : WebSocketListenerState, new() - where TReturnDataType : class - { - /// - /// The _active connections - /// - protected readonly List> ActiveConnections = - new List>(); - - /// - /// Gets the name. - /// - /// The name. - protected abstract string Name { get; } - - /// - /// Gets the data to send. - /// - /// The state. - /// Task{`1}. - protected abstract Task GetDataToSend(TStateType state); - - /// - /// The logger - /// - protected ILogger Logger; - - /// - /// Initializes a new instance of the class. - /// - /// The logger. - /// logger - protected BasePeriodicWebSocketListener(ILogger logger) - { - if (logger == null) - { - throw new ArgumentNullException("logger"); - } - - Logger = logger; - } - - /// - /// The null task result - /// - protected Task NullTaskResult = Task.FromResult(true); - - /// - /// Processes the message. - /// - /// The message. - /// Task. - public Task ProcessMessage(WebSocketMessageInfo message) - { - if (message.MessageType.Equals(Name + "Start", StringComparison.OrdinalIgnoreCase)) - { - Start(message); - } - - if (message.MessageType.Equals(Name + "Stop", StringComparison.OrdinalIgnoreCase)) - { - Stop(message); - } - - return NullTaskResult; - } - - protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - protected virtual bool SendOnTimer - { - get - { - return true; - } - } - - /// - /// Starts sending messages over a web socket - /// - /// The message. - private void Start(WebSocketMessageInfo message) - { - var vals = message.Data.Split(','); - - var dueTimeMs = long.Parse(vals[0], UsCulture); - var periodMs = long.Parse(vals[1], UsCulture); - - var cancellationTokenSource = new CancellationTokenSource(); - - Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); - - var timer = SendOnTimer ? - new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : - null; - - var state = new TStateType - { - IntervalMs = periodMs, - InitialDelayMs = dueTimeMs - }; - - var semaphore = new SemaphoreSlim(1, 1); - - lock (ActiveConnections) - { - ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state, semaphore)); - } - - if (timer != null) - { - timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); - } - } - - /// - /// Timers the callback. - /// - /// The state. - private void TimerCallback(object state) - { - var connection = (IWebSocketConnection)state; - - Tuple tuple; - - lock (ActiveConnections) - { - tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); - } - - if (tuple == null) - { - return; - } - - if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) - { - DisposeConnection(tuple); - return; - } - - SendData(tuple); - } - - protected void SendData(bool force) - { - List> tuples; - - lock (ActiveConnections) - { - tuples = ActiveConnections - .Where(c => - { - if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) - { - var state = c.Item4; - - if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) - { - return true; - } - } - - return false; - }) - .ToList(); - } - - foreach (var tuple in tuples) - { - SendData(tuple); - } - } - - private async void SendData(Tuple tuple) - { - var connection = tuple.Item1; - - try - { - await tuple.Item5.WaitAsync(tuple.Item2.Token).ConfigureAwait(false); - - var state = tuple.Item4; - - var data = await GetDataToSend(state).ConfigureAwait(false); - - if (data != null) - { - await connection.SendAsync(new WebSocketMessage - { - MessageType = Name, - Data = data - - }, tuple.Item2.Token).ConfigureAwait(false); - - state.DateLastSendUtc = DateTime.UtcNow; - } - - tuple.Item5.Release(); - } - catch (OperationCanceledException) - { - if (tuple.Item2.IsCancellationRequested) - { - DisposeConnection(tuple); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error sending web socket message {0}", ex, Name); - DisposeConnection(tuple); - } - } - - /// - /// Stops sending messages over a web socket - /// - /// The message. - private void Stop(WebSocketMessageInfo message) - { - lock (ActiveConnections) - { - var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); - - if (connection != null) - { - DisposeConnection(connection); - } - } - } - - /// - /// Disposes the connection. - /// - /// The connection. - private void DisposeConnection(Tuple connection) - { - Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); - - var timer = connection.Item3; - - if (timer != null) - { - try - { - timer.Dispose(); - } - catch (ObjectDisposedException) - { - - } - } - - try - { - connection.Item2.Cancel(); - connection.Item2.Dispose(); - } - catch (ObjectDisposedException) - { - - } - - try - { - connection.Item5.Dispose(); - } - catch (ObjectDisposedException) - { - - } - - ActiveConnections.Remove(connection); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool dispose) - { - if (dispose) - { - lock (ActiveConnections) - { - foreach (var connection in ActiveConnections.ToList()) - { - DisposeConnection(connection); - } - } - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(true); - } - } - - public class WebSocketListenerState - { - public DateTime DateLastSendUtc { get; set; } - public long InitialDelayMs { get; set; } - public long IntervalMs { get; set; } - } -} diff --git a/MediaBrowser.Common/Net/IWebSocketListener.cs b/MediaBrowser.Common/Net/IWebSocketListener.cs deleted file mode 100644 index 4b6c4111d..000000000 --- a/MediaBrowser.Common/Net/IWebSocketListener.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Net -{ - /// - ///This is an interface for listening to messages coming through a web socket connection - /// - public interface IWebSocketListener - { - /// - /// Processes the message. - /// - /// The message. - /// Task. - Task ProcessMessage(WebSocketMessageInfo message); - } -} diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 3b9f3a5b2..21ae6bf61 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -207,6 +207,7 @@ + @@ -218,6 +219,7 @@ + diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs new file mode 100644 index 000000000..f1e371c1a --- /dev/null +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -0,0 +1,327 @@ +using MediaBrowser.Common.Net; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Net; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Net +{ + /// + /// Starts sending data over a web socket periodically when a message is received, and then stops when a corresponding stop message is received + /// + /// The type of the T return data type. + /// The type of the T state type. + public abstract class BasePeriodicWebSocketListener : IWebSocketListener, IDisposable + where TStateType : WebSocketListenerState, new() + where TReturnDataType : class + { + /// + /// The _active connections + /// + protected readonly List> ActiveConnections = + new List>(); + + /// + /// Gets the name. + /// + /// The name. + protected abstract string Name { get; } + + /// + /// Gets the data to send. + /// + /// The state. + /// Task{`1}. + protected abstract Task GetDataToSend(TStateType state); + + /// + /// The logger + /// + protected ILogger Logger; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// logger + protected BasePeriodicWebSocketListener(ILogger logger) + { + if (logger == null) + { + throw new ArgumentNullException("logger"); + } + + Logger = logger; + } + + /// + /// The null task result + /// + protected Task NullTaskResult = Task.FromResult(true); + + /// + /// Processes the message. + /// + /// The message. + /// Task. + public Task ProcessMessage(WebSocketMessageInfo message) + { + if (message.MessageType.Equals(Name + "Start", StringComparison.OrdinalIgnoreCase)) + { + Start(message); + } + + if (message.MessageType.Equals(Name + "Stop", StringComparison.OrdinalIgnoreCase)) + { + Stop(message); + } + + return NullTaskResult; + } + + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + protected virtual bool SendOnTimer + { + get + { + return true; + } + } + + /// + /// Starts sending messages over a web socket + /// + /// The message. + private void Start(WebSocketMessageInfo message) + { + var vals = message.Data.Split(','); + + var dueTimeMs = long.Parse(vals[0], UsCulture); + var periodMs = long.Parse(vals[1], UsCulture); + + var cancellationTokenSource = new CancellationTokenSource(); + + Logger.Info("{1} Begin transmitting over websocket to {0}", message.Connection.RemoteEndPoint, GetType().Name); + + var timer = SendOnTimer ? + new Timer(TimerCallback, message.Connection, Timeout.Infinite, Timeout.Infinite) : + null; + + var state = new TStateType + { + IntervalMs = periodMs, + InitialDelayMs = dueTimeMs + }; + + var semaphore = new SemaphoreSlim(1, 1); + + lock (ActiveConnections) + { + ActiveConnections.Add(new Tuple(message.Connection, cancellationTokenSource, timer, state, semaphore)); + } + + if (timer != null) + { + timer.Change(TimeSpan.FromMilliseconds(dueTimeMs), TimeSpan.FromMilliseconds(periodMs)); + } + } + + /// + /// Timers the callback. + /// + /// The state. + private void TimerCallback(object state) + { + var connection = (IWebSocketConnection)state; + + Tuple tuple; + + lock (ActiveConnections) + { + tuple = ActiveConnections.FirstOrDefault(c => c.Item1 == connection); + } + + if (tuple == null) + { + return; + } + + if (connection.State != WebSocketState.Open || tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + return; + } + + SendData(tuple); + } + + protected void SendData(bool force) + { + List> tuples; + + lock (ActiveConnections) + { + tuples = ActiveConnections + .Where(c => + { + if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) + { + var state = c.Item4; + + if (force || (DateTime.UtcNow - state.DateLastSendUtc).TotalMilliseconds >= state.IntervalMs) + { + return true; + } + } + + return false; + }) + .ToList(); + } + + foreach (var tuple in tuples) + { + SendData(tuple); + } + } + + private async void SendData(Tuple tuple) + { + var connection = tuple.Item1; + + try + { + await tuple.Item5.WaitAsync(tuple.Item2.Token).ConfigureAwait(false); + + var state = tuple.Item4; + + var data = await GetDataToSend(state).ConfigureAwait(false); + + if (data != null) + { + await connection.SendAsync(new WebSocketMessage + { + MessageType = Name, + Data = data + + }, tuple.Item2.Token).ConfigureAwait(false); + + state.DateLastSendUtc = DateTime.UtcNow; + } + + tuple.Item5.Release(); + } + catch (OperationCanceledException) + { + if (tuple.Item2.IsCancellationRequested) + { + DisposeConnection(tuple); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error sending web socket message {0}", ex, Name); + DisposeConnection(tuple); + } + } + + /// + /// Stops sending messages over a web socket + /// + /// The message. + private void Stop(WebSocketMessageInfo message) + { + lock (ActiveConnections) + { + var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); + + if (connection != null) + { + DisposeConnection(connection); + } + } + } + + /// + /// Disposes the connection. + /// + /// The connection. + private void DisposeConnection(Tuple connection) + { + Logger.Info("{1} stop transmitting over websocket to {0}", connection.Item1.RemoteEndPoint, GetType().Name); + + var timer = connection.Item3; + + if (timer != null) + { + try + { + timer.Dispose(); + } + catch (ObjectDisposedException) + { + + } + } + + try + { + connection.Item2.Cancel(); + connection.Item2.Dispose(); + } + catch (ObjectDisposedException) + { + + } + + try + { + connection.Item5.Dispose(); + } + catch (ObjectDisposedException) + { + + } + + ActiveConnections.Remove(connection); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool dispose) + { + if (dispose) + { + lock (ActiveConnections) + { + foreach (var connection in ActiveConnections.ToList()) + { + DisposeConnection(connection); + } + } + } + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + } + } + + public class WebSocketListenerState + { + public DateTime DateLastSendUtc { get; set; } + public long InitialDelayMs { get; set; } + public long IntervalMs { get; set; } + } +} diff --git a/MediaBrowser.Controller/Net/IWebSocketListener.cs b/MediaBrowser.Controller/Net/IWebSocketListener.cs new file mode 100644 index 000000000..2b4fc7676 --- /dev/null +++ b/MediaBrowser.Controller/Net/IWebSocketListener.cs @@ -0,0 +1,18 @@ +using MediaBrowser.Common.Net; +using System.Threading.Tasks; + +namespace MediaBrowser.Controller.Net +{ + /// + ///This is an interface for listening to messages coming through a web socket connection + /// + public interface IWebSocketListener + { + /// + /// Processes the message. + /// + /// The message. + /// Task. + Task ProcessMessage(WebSocketMessageInfo message); + } +} diff --git a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs index ed590a1f2..36a7fcbd8 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionWebSocketListener.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; -- cgit v1.2.3 From 55b9bffabcd2322d398d405eadf848a84744121d Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 27 Dec 2014 00:08:39 -0500 Subject: added optional SeasonUserData --- MediaBrowser.Api/IHasDtoOptions.cs | 12 +----- MediaBrowser.Api/Library/LibraryService.cs | 41 +++++++------------- MediaBrowser.Api/Movies/CollectionService.cs | 5 ++- MediaBrowser.Api/Movies/MoviesService.cs | 28 ++++++++------ MediaBrowser.Api/Sync/SyncService.cs | 16 ++++---- MediaBrowser.Api/UserLibrary/ArtistsService.cs | 9 ++--- MediaBrowser.Api/UserLibrary/GameGenresService.cs | 7 ++-- MediaBrowser.Api/UserLibrary/GenresService.cs | 7 ++-- MediaBrowser.Api/UserLibrary/MusicGenresService.cs | 7 ++-- MediaBrowser.Api/UserLibrary/PersonsService.cs | 7 ++-- MediaBrowser.Api/UserLibrary/StudiosService.cs | 7 ++-- MediaBrowser.Api/UserLibrary/UserLibraryService.cs | 45 ++++++++++------------ MediaBrowser.Api/UserLibrary/YearsService.cs | 7 ++-- MediaBrowser.Api/VideosService.cs | 8 ++-- MediaBrowser.Controller/Entities/TV/Series.cs | 14 ++++++- MediaBrowser.Model/Dto/BaseItemDto.cs | 5 +++ MediaBrowser.Model/Dto/DtoOptions.cs | 17 +++++++- MediaBrowser.Model/Querying/ItemFields.cs | 7 +++- MediaBrowser.Providers/TV/SeriesMetadataService.cs | 25 ------------ MediaBrowser.Providers/TV/SeriesPostScanTask.cs | 4 -- .../Channels/ChannelManager.cs | 35 +++++------------ .../Dto/DtoService.cs | 20 +++++++--- .../LiveTv/LiveTvManager.cs | 5 +-- .../Localization/JavaScript/javascript.json | 1 + .../Localization/Server/server.json | 2 +- .../Sync/SyncManager.cs | 8 +--- 26 files changed, 157 insertions(+), 192 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs index f7fb57f01..2e677e816 100644 --- a/MediaBrowser.Api/IHasDtoOptions.cs +++ b/MediaBrowser.Api/IHasDtoOptions.cs @@ -28,17 +28,7 @@ namespace MediaBrowser.Api options.ImageTypeLimit = request.ImageTypeLimit.Value; } - if (string.IsNullOrWhiteSpace(request.EnableImageTypes)) - { - if (options.EnableImages) - { - // Get everything - options.ImageTypes = Enum.GetNames(typeof(ImageType)) - .Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true)) - .ToList(); - } - } - else + if (!string.IsNullOrWhiteSpace(request.EnableImageTypes)) { options.ImageTypes = (request.EnableImageTypes ?? string.Empty).Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true)).ToList(); } diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index e85f2cbf9..37d00b937 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -272,16 +272,13 @@ namespace MediaBrowser.Api.Library items = items.Where(i => i.IsHidden == val).ToList(); } - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); + var dtoOptions = new DtoOptions(); var result = new ItemsResult { TotalRecordCount = items.Count, - Items = items.Select(i => _dtoService.GetBaseItemDto(i, fields)).ToArray() + Items = items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions)).ToArray() }; return ToOptimizedResult(result); @@ -347,10 +344,7 @@ namespace MediaBrowser.Api.Library var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); + var dtoOptions = new DtoOptions(); BaseItem parent = item.Parent; @@ -361,7 +355,7 @@ namespace MediaBrowser.Api.Library parent = TranslateParentItem(parent, user); } - baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, fields, user)); + baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); parent = parent.Parent; } @@ -583,11 +577,6 @@ namespace MediaBrowser.Api.Library item = item.Parent; } - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); - var themeSongIds = GetThemeSongIds(item); if (themeSongIds.Count == 0 && request.InheritFromParent) @@ -607,10 +596,12 @@ namespace MediaBrowser.Api.Library } } } - + + var dtoOptions = new DtoOptions(); + var dtos = themeSongIds.Select(_libraryManager.GetItemById) .OrderBy(i => i.SortName) - .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item)); + .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item)); var items = dtos.ToArray(); @@ -651,11 +642,6 @@ namespace MediaBrowser.Api.Library item = item.Parent; } - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); - var themeVideoIds = GetThemeVideoIds(item); if (themeVideoIds.Count == 0 && request.InheritFromParent) @@ -681,9 +667,11 @@ namespace MediaBrowser.Api.Library } } + var dtoOptions = new DtoOptions(); + var dtos = themeVideoIds.Select(_libraryManager.GetItemById) .OrderBy(i => i.SortName) - .Select(i => _dtoService.GetBaseItemDto(i, fields, user, item)); + .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item)); var items = dtos.ToArray(); @@ -754,10 +742,7 @@ namespace MediaBrowser.Api.Library : (Folder)_libraryManager.RootFolder) : _libraryManager.GetItemById(id); - // Get everything - var fields = Enum.GetNames(typeof(ItemFields)) - .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) - .ToList(); + var dtoOptions = new DtoOptions(); var dtos = GetSoundtrackSongIds(item, inheritFromParent) .Select(_libraryManager.GetItemById) @@ -765,7 +750,7 @@ namespace MediaBrowser.Api.Library .SelectMany(i => i.RecursiveChildren) .OfType