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 --- .../Localization/JavaScript/javascript.json | 2 +- MediaBrowser.Server.Implementations/Localization/Server/server.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Localization') diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index b903702463..debb3c03a1 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -650,7 +650,7 @@ "OptionLow": "Low", "HeaderSettings": "Settings", "OptionAutomaticallySyncNewContent": "Automatically sync new content", - "OptionAutomaticallySyncNewContentHelp": "New content added to these folders will be automatically synced to the device.", + "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.", "OptionSyncUnwatchedVideosOnly": "Sync unwatched videos only", "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", "LabelItemLimit": "Item limit:", diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 09cd286b43..2db5ac6349 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -1295,5 +1295,6 @@ "LabelEnableSingleImageInDidlLimit": "Limit to single embedded image", "LabelEnableSingleImageInDidlLimitHelp": "Some devices will not render properly if multiple images are embedded within Didl.", "TabActivity": "Activity", - "TitleSync": "Sync" + "TitleSync": "Sync", + "OptionAllowSyncContent": "Allow syncing media to devices" } -- 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.Server.Implementations/Localization') diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 5cb007f8fe..e85f2cbf91 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 3afe72866d..f3dcf57e03 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 69f1f34891..5103d1b5cd 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 1a8c1d849e..203a62dfcb 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 c2a9b963c5..94198d9745 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 7903724e8d..4892593346 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 ca46df05d0..e91ed98d1b 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 ae592c428a..725526ecdc 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 a64866d68a..fb2d307327 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 d2881893ba..4f47b9f54c 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 9c8216a03c..760cb07fd9 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 f618c8a255..5a9fc33227 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 ede366dab0..896d598bb0 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 5362cc1954..8482e38dff 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 72e2b110a9..f0eafcbdff 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 447328ea13..623ae8968d 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 1f7c62de0b..90edfcce70 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 2d9e052b1a..e9cc13c667 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 1d57c46e69..aea04187d9 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 ea7ecfb4a0..381b2101d2 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 87ad9c3804..fba5d082d9 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 e4d0323590..bf32d3e634 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 f2fec4397e..7584989779 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 9dc600675f..6563da8de7 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 30bf0fefc5..4c1aac7006 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 d7cd62aa68..4ca8cf1c5a 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 367db5dcb5..a3d8921814 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 982b1ef17f..24ebf88153 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 e270bbdf30..6b6f07d4c2 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 2df90244c3..ceddbbc3b7 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 4c0d1fdfb6..8e43c45e07 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 bb165d7909..7a1eef8dbb 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 3dfc8cc7d7..626afcfdfe 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 926ffa19c1..0364ff6782 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 9dc16ba4d2..f7fbc9c20e 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 9f8d67a487..b95d67ad82 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 df118b25fe..de72accff8 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 266eaabee2..29b23a551e 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 66de812132..6fc985643a 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 7bd810b8d1..d7250d9d2f 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 2629dac8b1..8994b16c37 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 4840777a5c..fbde4c92d6 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 f0a27a2b90..01f90a0ba4 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 b81b4c1fd6..47bb62a321 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 b458e28546..4d09ae8e87 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 bfdbb8ccf2..ce939aeb48 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 cbd75cdeb7..376dc3548b 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 56e2e52471..b754a943a8 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 57d87749c3..13563ce197 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 f32ed2b202..05ff270fc2 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 71b6c0843f..edbc87415f 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 166465f72c..34237622d9 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 0e5ed18251..58b5dbc6ae 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 e8582a52a4..2761aa5d7e 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 6d8f89226a..7cdfb7788a 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 ec41ffe0b5..f18c53cd36 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 01aaad2ac1..f17215988c 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 66bdb8ce3e..9bd15fc8f6 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 0000000000..2d55e8f2a1 --- /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 0dd5442edf..759c671e93 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 9647461bf8..ab50c30fbd 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 9bf06c50bc..9a515d492f 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 42b14166029d5251e952b72f5c16cd9ae96aa8cb Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 22 Dec 2014 22:58:14 -0500 Subject: begin work on daily episodes --- MediaBrowser.Api/ItemUpdateService.cs | 3 +- .../Configuration/BaseConfigurationManager.cs | 4 + .../Devices/DeviceId.cs | 5 +- .../Security/MBLicenseFile.cs | 4 + MediaBrowser.Common/Extensions/BaseExtensions.cs | 11 +++ MediaBrowser.Common/Plugins/BasePlugin.cs | 4 + MediaBrowser.Controller/Entities/TV/Episode.cs | 11 ++- MediaBrowser.Controller/Entities/TV/Season.cs | 78 ++++++++++++------- MediaBrowser.Controller/Library/IUserManager.cs | 7 ++ MediaBrowser.LocalMetadata/BaseXmlProvider.cs | 6 -- .../Subtitles/SubtitleEncoder.cs | 4 + MediaBrowser.Model/ApiClient/IApiClient.cs | 18 ----- .../Movies/FanartMovieImageProvider.cs | 4 + .../Music/FanArtAlbumProvider.cs | 4 + .../Music/FanArtArtistProvider.cs | 4 + .../People/TvdbPersonImageProvider.cs | 4 + MediaBrowser.Providers/TV/FanArtSeasonProvider.cs | 4 + MediaBrowser.Providers/TV/FanartSeriesProvider.cs | 4 + .../TV/MissingEpisodeProvider.cs | 63 +++++++++------- MediaBrowser.Providers/TV/SeriesPostScanTask.cs | 11 ++- MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs | 15 +++- .../TV/TvdbSeasonImageProvider.cs | 4 + .../TV/TvdbSeriesImageProvider.cs | 4 + .../Connect/ConnectManager.cs | 3 +- .../Drawing/ImageProcessor.cs | 5 ++ .../FileOrganization/EpisodeFileOrganizer.cs | 10 ++- .../Library/LibraryManager.cs | 88 ++++++++++++++++++---- .../Library/Resolvers/TV/EpisodeResolver.cs | 2 - .../Library/UserManager.cs | 68 +++++++++++++---- .../Localization/JavaScript/javascript.json | 4 +- .../Localization/Server/server.json | 9 ++- .../News/NewsService.cs | 8 ++ MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 4 + 33 files changed, 349 insertions(+), 128 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Localization') diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 020908ddd5..272dff3ecc 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -3,6 +3,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Providers; @@ -73,7 +74,7 @@ namespace MediaBrowser.Api if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) { - if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder)) + if (!(item is ICollectionFolder) && !(item is UserView) && !(item is AggregateFolder) && !(item is LiveTvChannel) && !(item is IItemByName)) { var collectionType = _libraryManager.GetInheritedContentType(item); if (string.IsNullOrWhiteSpace(collectionType)) diff --git a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs index 89f6229ace..c53947e443 100644 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs @@ -223,6 +223,10 @@ namespace MediaBrowser.Common.Implementations.Configuration { return Activator.CreateInstance(configurationType); } + catch (DirectoryNotFoundException) + { + return Activator.CreateInstance(configurationType); + } catch (Exception ex) { Logger.ErrorException("Error loading configuration file: {0}", ex, path); diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs index 5af236026e..7c0dc1e1f0 100644 --- a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs +++ b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs @@ -38,7 +38,10 @@ namespace MediaBrowser.Common.Implementations.Devices _logger.Error("Invalid value found in device id file"); } } - catch (FileNotFoundException ex) + catch (DirectoryNotFoundException) + { + } + catch (FileNotFoundException) { } catch (Exception ex) diff --git a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs index 8f3225f4e9..63381efcdf 100644 --- a/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs +++ b/MediaBrowser.Common.Implementations/Security/MBLicenseFile.cs @@ -101,6 +101,10 @@ namespace MediaBrowser.Common.Implementations.Security { contents = File.ReadAllLines(licenseFile); } + catch (DirectoryNotFoundException) + { + (File.Create(licenseFile)).Close(); + } catch (FileNotFoundException) { (File.Create(licenseFile)).Close(); diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 8e96373f44..4c94f3aa20 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -54,6 +56,15 @@ namespace MediaBrowser.Common.Extensions return sb.ToString(); } + public static string RemoveDiacritics(this string text) + { + return String.Concat( + text.Normalize(NormalizationForm.FormD) + .Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != + UnicodeCategory.NonSpacingMark) + ).Normalize(NormalizationForm.FormC); + } + /// /// Gets the M d5. /// diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index 1a536b4ffb..ce068463ea 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -204,6 +204,10 @@ namespace MediaBrowser.Common.Plugins { return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path); } + catch (DirectoryNotFoundException) + { + return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); + } catch (FileNotFoundException) { return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index 6b6f07d4c2..6b67cebc88 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -1,11 +1,11 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Users; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -178,6 +178,15 @@ namespace MediaBrowser.Controller.Entities.TV } } + [IgnoreDataMember] + public bool IsInSeasonFolder + { + get + { + return FindParent() != null; + } + } + [IgnoreDataMember] public string SeriesName { diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index ceddbbc3b7..54db12b6f8 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,13 +1,12 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Localization; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Users; +using MoreLinq; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -156,24 +155,6 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - private IEnumerable GetEpisodes() - { - var series = Series; - - if (series != null && series.ContainsEpisodesWithoutSeasonFolders) - { - var seasonNumber = IndexNumber; - - if (seasonNumber.HasValue) - { - return series.RecursiveChildren.OfType() - .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value); - } - } - - return Children.OfType(); - } - [IgnoreDataMember] public bool IsMissingSeason { @@ -221,16 +202,32 @@ namespace MediaBrowser.Controller.Entities.TV var episodes = GetRecursiveChildren(user) .OfType(); - if (IndexNumber.HasValue) + var series = Series; + + if (IndexNumber.HasValue && series != null) { - var series = Series; + return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); + } - if (series != null) + if (series != null && series.ContainsEpisodesWithoutSeasonFolders) + { + var seasonNumber = IndexNumber; + var list = episodes.ToList(); + + if (seasonNumber.HasValue) { - return series.GetEpisodes(user, IndexNumber.Value, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); + list.AddRange(series.GetRecursiveChildren(user).OfType() + .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); + } + else + { + list.AddRange(series.GetRecursiveChildren(user).OfType() + .Where(i => !i.ParentIndexNumber.HasValue)); } - } + episodes = list.DistinctBy(i => i.Id); + } + if (!includeMissingEpisodes) { episodes = episodes.Where(i => !i.IsMissingEpisode); @@ -245,6 +242,33 @@ namespace MediaBrowser.Controller.Entities.TV .Cast(); } + private IEnumerable GetEpisodes() + { + var episodes = RecursiveChildren.OfType(); + var series = Series; + + if (series != null && series.ContainsEpisodesWithoutSeasonFolders) + { + var seasonNumber = IndexNumber; + var list = episodes.ToList(); + + if (seasonNumber.HasValue) + { + list.AddRange(series.RecursiveChildren.OfType() + .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); + } + else + { + list.AddRange(series.RecursiveChildren.OfType() + .Where(i => !i.ParentIndexNumber.HasValue)); + } + + episodes = list.DistinctBy(i => i.Id); + } + + return episodes; + } + public override IEnumerable GetChildren(User user, bool includeLinkedChildren) { return GetEpisodes(user); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index f7fbc9c20e..f5846973eb 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -186,5 +186,12 @@ namespace MediaBrowser.Controller.Library /// The user identifier. /// The user policy. Task UpdateUserPolicy(string userId, UserPolicy userPolicy); + + /// + /// Makes the valid username. + /// + /// The username. + /// System.String. + string MakeValidUsername(string username); } } diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index 82e7809e89..74e3b61caa 100644 --- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs @@ -28,8 +28,6 @@ namespace MediaBrowser.LocalMetadata var path = file.FullName; - //await XmlProviderUtils.XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); - try { result.Item = new T(); @@ -45,10 +43,6 @@ namespace MediaBrowser.LocalMetadata { result.HasMetadata = false; } - finally - { - //XmlProviderUtils.XmlParsingResourcePool.Release(); - } return result; } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7c512840b7..67c9123f57 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -612,6 +612,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles catch (FileNotFoundException) { + } + catch (DirectoryNotFoundException) + { + } catch (IOException ex) { diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index dde6ca0b12..0181325fe7 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -505,15 +505,6 @@ namespace MediaBrowser.Model.ApiClient /// The cancellation token. /// Task<PublicSystemInfo>. Task GetPublicSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// Gets a person - /// - /// The name. - /// The user id. - /// Task{BaseItemDto}. - /// userId - Task GetPersonAsync(string name, string userId); /// /// Gets a list of plugins installed on the server @@ -967,15 +958,6 @@ namespace MediaBrowser.Model.ApiClient /// item string GetPersonImageUrl(BaseItemPerson item, ImageOptions options); - /// - /// Gets an image url that can be used to download an image from the api - /// - /// The name of the person - /// The options. - /// System.String. - /// name - string GetPersonImageUrl(string name, ImageOptions options); - /// /// Gets an image url that can be used to download an image from the api /// diff --git a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index a7ccf3f6ec..6813f2ff5e 100644 --- a/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs +++ b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs @@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.Movies { // No biggie. Don't blow up } + catch (DirectoryNotFoundException) + { + // No biggie. Don't blow up + } } var language = item.GetPreferredMetadataLanguage(); diff --git a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs index 94d682f44b..123ff9e290 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -82,6 +82,10 @@ namespace MediaBrowser.Providers.Music catch (FileNotFoundException) { + } + catch (DirectoryNotFoundException) + { + } } diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index a8df95fd1b..6f633cfc87 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -90,6 +90,10 @@ namespace MediaBrowser.Providers.Music catch (FileNotFoundException) { + } + catch (DirectoryNotFoundException) + { + } } diff --git a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs index 63d0546647..253acc13f1 100644 --- a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs +++ b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs @@ -83,6 +83,10 @@ namespace MediaBrowser.Providers.People { return null; } + catch (DirectoryNotFoundException) + { + return null; + } } private RemoteImageInfo GetImageInfo(string xmlFile, string personName, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs index 05244af747..9f0cd4ff12 100644 --- a/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/FanArtSeasonProvider.cs @@ -98,6 +98,10 @@ namespace MediaBrowser.Providers.TV { // No biggie. Don't blow up } + catch (DirectoryNotFoundException) + { + // No biggie. Don't blow up + } } } diff --git a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs index afc71698bb..8ba25e9f1f 100644 --- a/MediaBrowser.Providers/TV/FanartSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/FanartSeriesProvider.cs @@ -106,6 +106,10 @@ namespace MediaBrowser.Providers.TV { // No biggie. Don't blow up } + catch (DirectoryNotFoundException) + { + // No biggie. Don't blow up + } } var language = item.GetPreferredMetadataLanguage(); diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 21d41ca00c..0b52956de5 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -2,6 +2,7 @@ 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; @@ -22,14 +23,16 @@ namespace MediaBrowser.Providers.TV private readonly IServerConfigurationManager _config; private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; + private readonly ILocalizationManager _localization; private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager) + public MissingEpisodeProvider(ILogger logger, IServerConfigurationManager config, ILibraryManager libraryManager, ILocalizationManager localization) { _logger = logger; _config = config; _libraryManager = libraryManager; + _localization = localization; } public async Task Run(IEnumerable> series, CancellationToken cancellationToken) @@ -93,16 +96,16 @@ namespace MediaBrowser.Providers.TV var hasBadData = HasInvalidContent(group); - var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup, false) + var anySeasonsRemoved = await RemoveObsoleteOrMissingSeasons(group, episodeLookup) .ConfigureAwait(false); - var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup, false) + var anyEpisodesRemoved = await RemoveObsoleteOrMissingEpisodes(group, episodeLookup) .ConfigureAwait(false); var hasNewEpisodes = false; var hasNewSeasons = false; - foreach (var series in group.Where(s => s.ContainsEpisodesWithoutSeasonFolders)) + foreach (var series in group) { hasNewSeasons = await AddDummySeasonFolders(series, cancellationToken).ConfigureAwait(false); } @@ -165,14 +168,15 @@ namespace MediaBrowser.Providers.TV /// private async Task AddDummySeasonFolders(Series series, CancellationToken cancellationToken) { - var existingEpisodes = series.RecursiveChildren + var episodesInSeriesFolder = series.RecursiveChildren .OfType() + .Where(i => !i.IsInSeasonFolder) .ToList(); var hasChanges = false; // Loop through the unique season numbers - foreach (var seasonNumber in existingEpisodes.Select(i => i.ParentIndexNumber ?? -1) + foreach (var seasonNumber in episodesInSeriesFolder.Select(i => i.ParentIndexNumber ?? -1) .Where(i => i >= 0) .Distinct() .ToList()) @@ -188,6 +192,20 @@ namespace MediaBrowser.Providers.TV } } + // Unknown season - create a dummy season to put these under + if (episodesInSeriesFolder.Any(i => !i.ParentIndexNumber.HasValue)) + { + var hasSeason = series.Children.OfType() + .Any(i => !i.IndexNumber.HasValue); + + if (!hasSeason) + { + await AddSeason(series, null, cancellationToken).ConfigureAwait(false); + + hasChanges = true; + } + } + return hasChanges; } @@ -292,8 +310,7 @@ namespace MediaBrowser.Providers.TV /// Removes the virtual entry after a corresponding physical version has been added /// private async Task RemoveObsoleteOrMissingEpisodes(IEnumerable series, - IEnumerable> episodeLookup, - bool forceRemoveAll) + IEnumerable> episodeLookup) { var existingEpisodes = (from s in series let seasonOffset = TvdbSeriesProvider.GetSeriesOffset(s.ProviderIds) ?? ((s.AnimeSeriesIndex ?? 1) - 1) @@ -312,11 +329,6 @@ namespace MediaBrowser.Providers.TV var episodesToRemove = virtualEpisodes .Where(i => { - if (forceRemoveAll) - { - return true; - } - if (i.Episode.IndexNumber.HasValue && i.Episode.ParentIndexNumber.HasValue) { var seasonNumber = i.Episode.ParentIndexNumber.Value + i.SeasonOffset; @@ -362,11 +374,9 @@ namespace MediaBrowser.Providers.TV /// /// 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 d350d2fe42..e1986a7c19 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 ef9f5427c4..52c1ab7dde 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 efafeae96e..1ebd7bed55 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 9cc09c40c9..08913d3b49 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 376dc3548b..67d8445438 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 b141fea1ed..967c78c50f 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 3b5e34520f..432ea1f696 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 d52288f871..66125784c1 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 39b0a93cc1..1a873f01e6 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 1d58ad074f..02d7c1be1a 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 6952002398..827a2388df 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 9a515d492f..c0af139500 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 9eeadfab7b..684363d01a 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 86e92530f1..0f1d53ea63 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 bade42783c0be3e4f16c799adcede6a81de42c28 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 22 Dec 2014 23:53:52 -0500 Subject: added in-app help --- MediaBrowser.Server.Implementations/Library/UserManager.cs | 2 +- .../Localization/JavaScript/javascript.json | 3 ++- .../MediaBrowser.Server.Implementations.csproj | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Localization') diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 02d7c1be1a..1a45d35a0c 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -498,7 +498,7 @@ namespace MediaBrowser.Server.Implementations.Library if (!IsValidUsername(name)) { - throw new ArgumentException("Only alphanumeric characters are allowed."); + throw new ArgumentException("Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)"); } if (Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index 827a2388df..b5c1ea0d3f 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json @@ -40,6 +40,7 @@ "LabelStopping": "Stopping", "LabelCancelled": "(cancelled)", "LabelFailed": "(failed)", + "ButtonHelp": "Help", "LabelAbortedByServerShutdown": "(Aborted by server shutdown)", "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.", "HeaderDeleteTaskTrigger": "Delete Task Trigger", @@ -658,5 +659,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 as a plain folder structure" + "MessageMixedContentHelp": "Content will be displayed as a plain folder structure" } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 123f3fe87d..4d21d2e943 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -51,7 +51,7 @@ False - ..\packages\MediaBrowser.Naming.1.0.0.21\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll + ..\packages\MediaBrowser.Naming.1.0.0.22\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll False -- 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.Server.Implementations/Localization') diff --git a/MediaBrowser.Api/Images/ImageService.cs b/MediaBrowser.Api/Images/ImageService.cs index 0e4ccf0b17..f2586b0438 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 94198d9745..8a33a88f28 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 4892593346..86866bdf5e 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 e91ed98d1b..87e2eedcf5 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 14f7175a9c..de845c88d8 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 fb2d307327..5ef72a4952 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 d26259a3ae..40e765f1ae 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 a2a93d50e3..32e6ba076d 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 26e4a2669a..29172ef05f 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 9fdfccaaf6..140a4ae0e4 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 14052e7599..0000000000 --- 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 226f77525b..06e7d1763e 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 47339f6773..e16a978c39 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 bdb1c4cbff..d1941c8563 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 a131e70161..7f83aa61d9 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 a388e0edb0..68df777bd7 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 5bacb73d7c..bc4e582331 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 0181325fe7..883e54308d 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 5b7cdc6fb1..0000000000 --- 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 606e928f21..e9a83bd12a 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 e1f0e78f4c..47a31853ba 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 0000000000..f4bd8e681d --- /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 0000000000..6eaac8f031 --- /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 0000000000..6ae9ceb18d --- /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 0000000000..305f4c502d --- /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 d50ae98c99..0000000000 --- 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 063f7feb25..d9fb1ed095 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 0000000000..784a12bc94 --- /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 0000000000..93c22d726f --- /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 0000000000..493de62729 --- /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 2c97f2c169..700bca0fab 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 52c252d24b..52ec5c9b12 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 e13e27d5ad..681d3ac5e5 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 cc261c3e7b..e3447afc99 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 3f132ab7fa..ed3503c1b9 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 7a0b1e46a6..ad12450df4 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 b5c1ea0d3f..f70e110b05 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 1f294c325e..4c587d1ab6 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 6dda869eee..5c933b4bd5 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 3006c1be92..f92cbeda3d 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 e65d4c66e9..2ff6d7ae6b 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 c2520ff6bb..06d63b355e 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 eb44f6d35c..6e34390797 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 6dfb39b4c6..8f4e916dde 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 49fd835c33..01fe110fba 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 d5164f0254..86a6d19d3b 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 297b0f07ec..686396f894 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 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.Server.Implementations/Localization') diff --git a/MediaBrowser.Api/IHasDtoOptions.cs b/MediaBrowser.Api/IHasDtoOptions.cs index f7fb57f014..2e677e816e 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 e85f2cbf91..37d00b9378 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