diff options
194 files changed, 2243 insertions, 2461 deletions
diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index d386373d4..a05d7d1b2 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -1,7 +1,9 @@ using MediaBrowser.Api.Playback; -using MediaBrowser.Controller; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; using System; @@ -33,7 +35,7 @@ namespace MediaBrowser.Api /// <summary> /// The application paths /// </summary> - private readonly IServerApplicationPaths _appPaths; + private readonly IServerConfigurationManager _config; private readonly ISessionManager _sessionManager; @@ -43,13 +45,13 @@ namespace MediaBrowser.Api /// Initializes a new instance of the <see cref="ApiEntryPoint" /> class. /// </summary> /// <param name="logger">The logger.</param> - /// <param name="appPaths">The application paths.</param> /// <param name="sessionManager">The session manager.</param> - public ApiEntryPoint(ILogger logger, IServerApplicationPaths appPaths, ISessionManager sessionManager) + /// <param name="config">The configuration.</param> + public ApiEntryPoint(ILogger logger, ISessionManager sessionManager, IServerConfigurationManager config) { Logger = logger; - _appPaths = appPaths; _sessionManager = sessionManager; + _config = config; Instance = this; } @@ -73,12 +75,17 @@ namespace MediaBrowser.Api } } + public EncodingOptions GetEncodingOptions() + { + return _config.GetConfiguration<EncodingOptions>("encoding"); + } + /// <summary> /// Deletes the encoded media cache. /// </summary> private void DeleteEncodedMediaCache() { - foreach (var file in Directory.EnumerateFiles(_appPaths.TranscodingTempPath, "*", SearchOption.AllDirectories) + foreach (var file in Directory.EnumerateFiles(_config.ApplicationPaths.TranscodingTempPath, "*", SearchOption.AllDirectories) .ToList()) { File.Delete(file); @@ -185,7 +192,9 @@ namespace MediaBrowser.Api CompletionPercentage = percentComplete, Width = state.OutputWidth, Height = state.OutputHeight, - AudioChannels = state.OutputAudioChannels + AudioChannels = state.OutputAudioChannels, + IsAudioDirect = string.Equals(state.OutputAudioCodec, "copy", StringComparison.OrdinalIgnoreCase), + IsVideoDirect = string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase) }); } } diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index 5fe606e16..3eb0296fc 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -123,7 +123,7 @@ namespace MediaBrowser.Api public void Post(AutoSetMetadataOptions request) { - _configurationManager.DisableMetadataService("Media Browser Legacy Xml"); + _configurationManager.DisableMetadataService("Media Browser Xml"); _configurationManager.SaveConfiguration(); } diff --git a/MediaBrowser.Api/ItemUpdateService.cs b/MediaBrowser.Api/ItemUpdateService.cs index 65c51beff..272dff3ec 100644 --- a/MediaBrowser.Api/ItemUpdateService.cs +++ b/MediaBrowser.Api/ItemUpdateService.cs @@ -1,9 +1,14 @@ -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; using ServiceStack; using System; using System.Collections.Generic; @@ -20,14 +25,165 @@ namespace MediaBrowser.Api public string ItemId { get; set; } } + [Route("/Items/{ItemId}/MetadataEditor", "GET", Summary = "Gets metadata editor info for an item")] + public class GetMetadataEditorInfo : IReturn<MetadataEditorInfo> + { + [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string ItemId { get; set; } + } + + [Route("/Items/{ItemId}/ContentType", "POST", Summary = "Updates an item's content type")] + public class UpdateItemContentType : IReturnVoid + { + [ApiMember(Name = "ItemId", Description = "The id of the item", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string ItemId { get; set; } + + [ApiMember(Name = "ContentType", Description = "The content type of the item", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] + public string ContentType { get; set; } + } + [Authenticated] public class ItemUpdateService : BaseApiService { private readonly ILibraryManager _libraryManager; + private readonly IProviderManager _providerManager; + private readonly ILocalizationManager _localizationManager; + private readonly IServerConfigurationManager _config; - public ItemUpdateService(ILibraryManager libraryManager) + public ItemUpdateService(ILibraryManager libraryManager, IProviderManager providerManager, ILocalizationManager localizationManager, IServerConfigurationManager config) { _libraryManager = libraryManager; + _providerManager = providerManager; + _localizationManager = localizationManager; + _config = config; + } + + public object Get(GetMetadataEditorInfo request) + { + var item = _libraryManager.GetItemById(request.ItemId); + + var info = new MetadataEditorInfo + { + ParentalRatingOptions = _localizationManager.GetParentalRatings().ToList(), + ExternalIdInfos = _providerManager.GetExternalIdInfos(item).ToList(), + Countries = _localizationManager.GetCountries().ToList(), + Cultures = _localizationManager.GetCultures().ToList() + }; + + var locationType = item.LocationType; + if (locationType == LocationType.FileSystem || + locationType == LocationType.Offline) + { + 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)) + { + info.ContentTypeOptions = GetContentTypeOptions(true); + info.ContentType = _libraryManager.GetContentType(item); + } + } + } + + return ToOptimizedResult(info); + } + + public void Post(UpdateItemContentType request) + { + var item = _libraryManager.GetItemById(request.ItemId); + var path = item.ContainingFolderPath; + + var types = _config.Configuration.ContentTypes + .Where(i => !string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase)) + .ToList(); + + if (!string.IsNullOrWhiteSpace(request.ContentType)) + { + types.Add(new NameValuePair + { + Name = path, + Value = request.ContentType + }); + } + + _config.Configuration.ContentTypes = types.ToArray(); + _config.SaveConfiguration(); + } + + private List<NameValuePair> GetContentTypeOptions(bool isForItem) + { + var list = new List<NameValuePair>(); + + if (isForItem) + { + list.Add(new NameValuePair + { + Name = "FolderTypeInherit", + Value = "" + }); + } + + list.Add(new NameValuePair + { + Name = "FolderTypeMovies", + Value = "movies" + }); + list.Add(new NameValuePair + { + Name = "FolderTypeMusic", + Value = "music" + }); + list.Add(new NameValuePair + { + Name = "FolderTypeTvShows", + Value = "tvshows" + }); + + if (!isForItem) + { + list.Add(new NameValuePair + { + Name = "FolderTypeBooks", + Value = "books" + }); + list.Add(new NameValuePair + { + Name = "FolderTypeGames", + Value = "games" + }); + } + + list.Add(new NameValuePair + { + Name = "FolderTypeHomeVideos", + Value = "homevideos" + }); + list.Add(new NameValuePair + { + Name = "FolderTypeMusicVideos", + Value = "musicvideos" + }); + list.Add(new NameValuePair + { + Name = "FolderTypePhotos", + Value = "photos" + }); + + if (!isForItem) + { + list.Add(new NameValuePair + { + Name = "FolderTypeMixed", + Value = "" + }); + } + + foreach (var val in list) + { + val.Name = _localizationManager.GetLocalizedString(val.Name); + } + + return list; } public void Post(UpdateItem request) diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 5cb007f8f..e85f2cbf9 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -479,14 +479,14 @@ namespace MediaBrowser.Api.Library } else if (item is ILiveTvRecording) { - if (!user.Configuration.EnableLiveTvManagement) + if (!user.Policy.EnableLiveTvManagement) { throw new UnauthorizedAccessException(); } } else { - if (!user.Configuration.EnableContentDeletion) + if (!user.Policy.EnableContentDeletion) { throw new UnauthorizedAccessException(); } diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 3afe72866..f3dcf57e0 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -319,7 +319,7 @@ namespace MediaBrowser.Api.LiveTv throw new UnauthorizedAccessException("Anonymous live tv management is not allowed."); } - if (!user.Configuration.EnableLiveTvManagement) + if (!user.Policy.EnableLiveTvManagement) { throw new UnauthorizedAccessException("The current user does not have permission to manage live tv."); } diff --git a/MediaBrowser.Api/NotificationsService.cs b/MediaBrowser.Api/NotificationsService.cs index 69f1f3489..5103d1b5c 100644 --- a/MediaBrowser.Api/NotificationsService.cs +++ b/MediaBrowser.Api/NotificationsService.cs @@ -135,7 +135,7 @@ namespace MediaBrowser.Api Level = request.Level, Name = request.Name, Url = request.Url, - UserIds = _userManager.Users.Where(i => i.Configuration.IsAdministrator).Select(i => i.Id.ToString("N")).ToList() + UserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id.ToString("N")).ToList() }; await _notificationManager.SendNotification(notification, CancellationToken.None).ConfigureAwait(false); diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 12ccfb6b1..7b18fb379 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -202,6 +203,10 @@ namespace MediaBrowser.Api.Playback { args += " -map -0:s"; } + else if (state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream) + { + args += " -map 1:0 -sn"; + } return args; } @@ -245,7 +250,7 @@ namespace MediaBrowser.Api.Playback protected EncodingQuality GetQualitySetting() { - var quality = ServerConfigurationManager.Configuration.MediaEncodingQuality; + var quality = ApiEntryPoint.Instance.GetEncodingOptions().EncodingQuality; if (quality == EncodingQuality.Auto) { @@ -273,7 +278,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) { @@ -302,6 +307,21 @@ namespace MediaBrowser.Api.Playback } } + protected string H264Encoder + { + get + { + var lib = ApiEntryPoint.Instance.GetEncodingOptions().H264Encoder; + + if (!string.IsNullOrWhiteSpace(lib)) + { + return lib; + } + + return "libx264"; + } + } + /// <summary> /// Gets the video bitrate to specify on the command line /// </summary> @@ -318,7 +338,7 @@ namespace MediaBrowser.Api.Playback var qualitySetting = GetQualitySetting(); - if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(videoCodec, H264Encoder, StringComparison.OrdinalIgnoreCase)) { switch (qualitySetting) { @@ -442,7 +462,7 @@ namespace MediaBrowser.Api.Playback { if (state.AudioStream != null && state.AudioStream.Channels.HasValue && state.AudioStream.Channels.Value > 5) { - volParam = ",volume=" + ServerConfigurationManager.Configuration.DownMixAudioBoost.ToString(UsCulture); + volParam = ",volume=" + ApiEntryPoint.Instance.GetEncodingOptions().DownMixAudioBoost.ToString(UsCulture); } } @@ -651,9 +671,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); } @@ -761,7 +790,7 @@ namespace MediaBrowser.Api.Playback { if (string.Equals(codec, "h264", StringComparison.OrdinalIgnoreCase)) { - return "libx264"; + return H264Encoder; } if (string.Equals(codec, "vpx", StringComparison.OrdinalIgnoreCase)) { @@ -798,6 +827,21 @@ namespace MediaBrowser.Api.Playback /// <returns>System.String.</returns> 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 && state.VideoType == VideoType.VideoFile && @@ -868,7 +912,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; } @@ -898,8 +942,8 @@ namespace MediaBrowser.Api.Playback /// <param name="cancellationTokenSource">The cancellation token source.</param> /// <param name="workingDirectory">The working directory.</param> /// <returns>Task.</returns> - protected async Task<TranscodingJob> StartFfMpeg(StreamState state, - string outputPath, + protected async Task<TranscodingJob> StartFfMpeg(StreamState state, + string outputPath, CancellationTokenSource cancellationTokenSource, string workingDirectory = null) { @@ -910,7 +954,7 @@ namespace MediaBrowser.Api.Playback var transcodingId = Guid.NewGuid().ToString("N"); var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true); - if (ServerConfigurationManager.Configuration.EnableDebugEncodingLogging) + if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging) { commandLineArgs = "-loglevel debug " + commandLineArgs; } @@ -1088,7 +1132,7 @@ namespace MediaBrowser.Api.Playback if (scale.HasValue) { long val; - + if (long.TryParse(size, NumberStyles.Any, UsCulture, out val)) { bytesTranscoded = val * scale.Value; @@ -1562,9 +1606,6 @@ namespace MediaBrowser.Api.Playback mediaStreams = new List<MediaStream>(); state.DeInterlace = true; - state.OutputAudioSync = "1000"; - state.InputVideoSync = "-1"; - state.InputAudioSync = "1"; // Just to prevent this from being null and causing other methods to fail state.MediaPath = string.Empty; @@ -1630,7 +1671,7 @@ namespace MediaBrowser.Api.Playback if (string.IsNullOrEmpty(container)) { - container = request.Static ? + container = request.Static ? state.InputContainer : (Path.GetExtension(GetOutputFilePath(state)) ?? string.Empty).TrimStart('.'); } @@ -1696,9 +1737,16 @@ namespace MediaBrowser.Api.Playback state.InputFileSize = mediaSource.Size; state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate; + if (state.ReadInputAtNativeFramerate) + { + state.OutputAudioSync = "1000"; + state.InputVideoSync = "-1"; + state.InputAudioSync = "1"; + } + AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest, requestedUrl); } - + private void AttachMediaStreamInfo(StreamState state, List<MediaStream> mediaStreams, VideoStreamRequest videoRequest, diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs index c963636fd..94198d974 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.IO; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Configuration; @@ -6,7 +7,6 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.IO; using System; using System.Collections.Generic; @@ -119,11 +119,7 @@ namespace MediaBrowser.Api.Playback.Hls if (isLive) { - //var file = request.PlaylistId + Path.GetExtension(Request.PathInfo); - - //file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file); - - return ResultFactory.GetStaticFileResult(Request, playlist, FileShare.ReadWrite); + return ResultFactory.GetResult(GetLivePlaylistText(playlist, state.SegmentLength), MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>()); } var audioBitrate = state.OutputAudioBitrate ?? 0; @@ -144,6 +140,22 @@ namespace MediaBrowser.Api.Playback.Hls return ResultFactory.GetResult(playlistText, MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>()); } + private string GetLivePlaylistText(string path, int segmentLength) + { + using (var stream = FileSystem.GetFileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + using (var reader = new StreamReader(stream)) + { + var text = reader.ReadToEnd(); + + var newDuration = "#EXT-X-TARGETDURATION:" + segmentLength.ToString(UsCulture) + Environment.NewLine + "#EXT-X-ALLOW-CACHE:NO"; + + // ffmpeg pads the reported length by a full second + return text.Replace("#EXT-X-TARGETDURATION:" + (segmentLength + 1).ToString(UsCulture), newDuration, StringComparison.OrdinalIgnoreCase); + } + } + } + private string GetMasterPlaylistFileText(string firstPlaylist, int bitrate, bool includeBaselineStream, int baselineStreamBitrate) { var builder = new StringBuilder(); @@ -227,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 fe3bd12fb..489259334 100644 --- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs @@ -651,7 +651,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg; + var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) @@ -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 260a4c467..e91ed98d1 100644 --- a/MediaBrowser.Api/Playback/Hls/MpegDashService.cs +++ b/MediaBrowser.Api/Playback/Hls/MpegDashService.cs @@ -594,7 +594,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg; + var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; args += " -r 24 -g 24"; @@ -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/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index 06fa4065c..14f7175a9 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -9,8 +9,6 @@ using MediaBrowser.Model.IO; using ServiceStack; using System; using System.IO; -using System.Linq; -using System.Threading.Tasks; namespace MediaBrowser.Api.Playback.Hls { @@ -147,7 +145,7 @@ namespace MediaBrowser.Api.Playback.Hls var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; - var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, "libx264", true) + keyFrameArg; + var args = "-codec:v:0 " + codec + " " + GetVideoQualityParam(state, H264Encoder, true) + keyFrameArg; // Add resolution params, if specified if (!hasGraphicalSubs) diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index ae592c428..725526ecd 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -82,7 +82,7 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"", + return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"", inputModifier, GetInputArgument(transcodingJobId, state), threads, diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index a64866d68..fb2d30732 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -103,7 +103,7 @@ namespace MediaBrowser.Api.Playback.Progressive var inputModifier = GetInputModifier(state); - return string.Format("{0} -i {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"", + return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"", inputModifier, GetInputArgument(transcodingJobId, state), keyFrame, diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs index d2881893b..4f47b9f54 100644 --- a/MediaBrowser.Api/Session/SessionsService.cs +++ b/MediaBrowser.Api/Session/SessionsService.cs @@ -373,12 +373,12 @@ namespace MediaBrowser.Api.Session var user = _userManager.GetUserById(request.ControllableByUserId.Value); - if (!user.Configuration.EnableRemoteControlOfOtherUsers) + if (!user.Policy.EnableRemoteControlOfOtherUsers) { result = result.Where(i => i.ContainsUser(request.ControllableByUserId.Value)); } - if (!user.Configuration.EnableSharedDeviceControl) + if (!user.Policy.EnableSharedDeviceControl) { result = result.Where(i => !i.UserId.HasValue); } diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs index cefb0e46e..26e4a2669 100644 --- a/MediaBrowser.Api/Sync/SyncService.cs +++ b/MediaBrowser.Api/Sync/SyncService.cs @@ -55,8 +55,14 @@ namespace MediaBrowser.Api.Sync [ApiMember(Name = "UserId", Description = "UserId", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] public string UserId { get; set; } - [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + [ApiMember(Name = "ItemIds", Description = "ItemIds", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string ItemIds { get; set; } + + [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; } } [Route("/Sync/JobItems/{Id}/Transferred", "POST", Summary = "Reports that a sync job item has successfully been transferred.")] @@ -155,19 +161,26 @@ namespace MediaBrowser.Api.Sync result.Targets = _syncManager.GetSyncTargets(request.UserId) .ToList(); - var dtos = request.ItemIds.Split(',') - .Select(_libraryManager.GetItemById) - .Where(i => i != null) - .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions - { - Fields = new List<ItemFields> + if (request.Category.HasValue) + { + result.Options = SyncHelper.GetSyncOptions(request.Category.Value); + } + else + { + var dtos = request.ItemIds.Split(',') + .Select(_libraryManager.GetItemById) + .Where(i => i != null) + .Select(i => _dtoService.GetBaseItemDto(i, new DtoOptions + { + Fields = new List<ItemFields> { ItemFields.SyncInfo } - })) - .ToList(); + })) + .ToList(); - result.Options = SyncHelper.GetSyncOptions(dtos); + result.Options = SyncHelper.GetSyncOptions(dtos); + } return ToOptimizedResult(result); } diff --git a/MediaBrowser.Api/UserService.cs b/MediaBrowser.Api/UserService.cs index 4b720c775..760cb07fd 100644 --- a/MediaBrowser.Api/UserService.cs +++ b/MediaBrowser.Api/UserService.cs @@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; +using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Users; @@ -51,7 +52,7 @@ namespace MediaBrowser.Api /// </summary> /// <value>The id.</value> [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public Guid Id { get; set; } + public string Id { get; set; } } /// <summary> @@ -66,7 +67,7 @@ namespace MediaBrowser.Api /// </summary> /// <value>The id.</value> [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "DELETE")] - public Guid Id { get; set; } + public string Id { get; set; } } /// <summary> @@ -80,7 +81,7 @@ namespace MediaBrowser.Api /// </summary> /// <value>The id.</value> [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public Guid Id { get; set; } + public string Id { get; set; } /// <summary> /// Gets or sets the password. @@ -125,7 +126,7 @@ namespace MediaBrowser.Api /// Gets or sets the id. /// </summary> /// <value>The id.</value> - public Guid Id { get; set; } + public string Id { get; set; } /// <summary> /// Gets or sets the password. @@ -156,6 +157,28 @@ namespace MediaBrowser.Api } /// <summary> + /// Class UpdateUser + /// </summary> + [Route("/Users/{Id}/Policy", "POST", Summary = "Updates a user policy")] + [Authenticated(Roles = "admin")] + public class UpdateUserPolicy : UserPolicy, IReturnVoid + { + [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string Id { get; set; } + } + + /// <summary> + /// Class UpdateUser + /// </summary> + [Route("/Users/{Id}/Configuration", "POST", Summary = "Updates a user configuration")] + [Authenticated] + public class UpdateUserConfiguration : UserConfiguration, IReturnVoid + { + [ApiMember(Name = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] + public string Id { get; set; } + } + + /// <summary> /// Class CreateUser /// </summary> [Route("/Users/New", "POST", Summary = "Creates a user")] @@ -196,12 +219,6 @@ namespace MediaBrowser.Api public IAuthorizationContext AuthorizationContext { get; set; } - /// <summary> - /// Initializes a new instance of the <see cref="UserService" /> class. - /// </summary> - /// <param name="userManager">The user manager.</param> - /// <param name="dtoService">The dto service.</param> - /// <param name="sessionMananger">The session mananger.</param> public UserService(IUserManager userManager, IDtoService dtoService, ISessionManager sessionMananger, IServerConfigurationManager config, INetworkManager networkManager) { _userManager = userManager; @@ -247,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) @@ -428,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); } /// <summary> @@ -495,5 +486,51 @@ namespace MediaBrowser.Api { return _userManager.RedeemPasswordResetPin(request.Pin); } + + public void Post(UpdateUserConfiguration request) + { + var task = _userManager.UpdateConfiguration(request.Id, request); + + Task.WaitAll(task); + } + + public void Post(UpdateUserPolicy 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.Common.Implementations/Configuration/BaseConfigurationManager.cs b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs index 4a70697fa..c53947e44 100644 --- a/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs +++ b/MediaBrowser.Common.Implementations/Configuration/BaseConfigurationManager.cs @@ -105,7 +105,7 @@ namespace MediaBrowser.Common.Implementations.Configuration UpdateCachePath(); } - public void AddParts(IEnumerable<IConfigurationFactory> factories) + public virtual void AddParts(IEnumerable<IConfigurationFactory> factories) { _configurationFactories = factories.ToArray(); @@ -208,20 +208,51 @@ namespace MediaBrowser.Common.Implementations.Configuration lock (_configurationSyncLock) { - return ConfigurationHelper.GetXmlConfiguration(configurationType, file, XmlSerializer); + return LoadConfiguration(file, configurationType); } }); } + private object LoadConfiguration(string path, Type configurationType) + { + try + { + return XmlSerializer.DeserializeFromFile(configurationType, path); + } + catch (FileNotFoundException) + { + return Activator.CreateInstance(configurationType); + } + catch (DirectoryNotFoundException) + { + return Activator.CreateInstance(configurationType); + } + catch (Exception ex) + { + Logger.ErrorException("Error loading configuration file: {0}", ex, path); + + return Activator.CreateInstance(configurationType); + } + } + public void SaveConfiguration(string key, object configuration) { - var configurationType = GetConfigurationType(key); + var configurationStore = GetConfigurationStore(key); + var configurationType = configurationStore.ConfigurationType; if (configuration.GetType() != configurationType) { throw new ArgumentException("Expected configuration type is " + configurationType.Name); } + var validatingStore = configurationStore as IValidatingConfiguration; + if (validatingStore != null) + { + var currentConfiguration = GetConfiguration(key); + + validatingStore.Validate(currentConfiguration, configuration); + } + EventHelper.FireEventIfNotNull(NamedConfigurationUpdating, this, new ConfigurationUpdateEventArgs { Key = key, @@ -239,6 +270,11 @@ namespace MediaBrowser.Common.Implementations.Configuration XmlSerializer.SerializeToFile(configuration, path); } + OnNamedConfigurationUpdated(key, configuration); + } + + protected virtual void OnNamedConfigurationUpdated(string key, object configuration) + { EventHelper.FireEventIfNotNull(NamedConfigurationUpdated, this, new ConfigurationUpdateEventArgs { Key = key, @@ -249,9 +285,14 @@ namespace MediaBrowser.Common.Implementations.Configuration public Type GetConfigurationType(string key) { - return _configurationStores - .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)) + return GetConfigurationStore(key) .ConfigurationType; } + + private ConfigurationStore GetConfigurationStore(string key) + { + return _configurationStores + .First(i => string.Equals(i.Key, key, StringComparison.OrdinalIgnoreCase)); + } } } diff --git a/MediaBrowser.Common.Implementations/Devices/DeviceId.cs b/MediaBrowser.Common.Implementations/Devices/DeviceId.cs index 5af236026..7c0dc1e1f 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 8f3225f4e..63381efcd 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.Implementations/Serialization/XmlSerializer.cs b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs index cef744753..04030522f 100644 --- a/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs +++ b/MediaBrowser.Common.Implementations/Serialization/XmlSerializer.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Serialization; using System; +using System.Collections.Concurrent; using System.IO; using System.Xml; @@ -10,6 +11,17 @@ namespace MediaBrowser.Common.Implementations.Serialization /// </summary> public class XmlSerializer : IXmlSerializer { + // Need to cache these + // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html + private readonly ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer> _serializers = + new ConcurrentDictionary<string, System.Xml.Serialization.XmlSerializer>(); + + private System.Xml.Serialization.XmlSerializer GetSerializer(Type type) + { + var key = type.FullName; + return _serializers.GetOrAdd(key, k => new System.Xml.Serialization.XmlSerializer(type)); + } + /// <summary> /// Serializes to writer. /// </summary> @@ -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.Common/Configuration/ConfigurationHelper.cs b/MediaBrowser.Common/Configuration/ConfigurationHelper.cs index 8c904b0db..7212b70e1 100644 --- a/MediaBrowser.Common/Configuration/ConfigurationHelper.cs +++ b/MediaBrowser.Common/Configuration/ConfigurationHelper.cs @@ -55,20 +55,5 @@ namespace MediaBrowser.Common.Configuration return configuration; } } - - /// <summary> - /// Reads an xml configuration file from the file system - /// It will immediately save the configuration after loading it, just - /// in case there are new serializable properties - /// </summary> - /// <typeparam name="T"></typeparam> - /// <param name="path">The path.</param> - /// <param name="xmlSerializer">The XML serializer.</param> - /// <returns>``0.</returns> - public static T GetXmlConfiguration<T>(string path, IXmlSerializer xmlSerializer) - where T : class - { - return GetXmlConfiguration(typeof(T), path, xmlSerializer) as T; - } } } diff --git a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs index d418d0a42..6ed638536 100644 --- a/MediaBrowser.Common/Configuration/IConfigurationFactory.cs +++ b/MediaBrowser.Common/Configuration/IConfigurationFactory.cs @@ -14,4 +14,9 @@ namespace MediaBrowser.Common.Configuration public Type ConfigurationType { get; set; } } + + public interface IValidatingConfiguration + { + void Validate(object oldConfig, object newConfig); + } } diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 8e96373f4..4c94f3aa2 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); + } + /// <summary> /// Gets the M d5. /// </summary> diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index 6bbd69f04..ce068463e 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -164,11 +164,7 @@ namespace MediaBrowser.Common.Plugins /// <summary> /// The _configuration sync lock /// </summary> - private object _configurationSyncLock = new object(); - /// <summary> - /// The _configuration initialized - /// </summary> - private bool _configurationInitialized; + private readonly object _configurationSyncLock = new object(); /// <summary> /// The _configuration /// </summary> @@ -182,17 +178,43 @@ namespace MediaBrowser.Common.Plugins get { // Lazy load - LazyInitializer.EnsureInitialized(ref _configuration, ref _configurationInitialized, ref _configurationSyncLock, () => ConfigurationHelper.GetXmlConfiguration(ConfigurationType, ConfigurationFilePath, XmlSerializer) as TConfigurationType); + if (_configuration == null) + { + lock (_configurationSyncLock) + { + if (_configuration == null) + { + _configuration = LoadConfiguration(); + } + } + } return _configuration; } protected set { _configuration = value; + } + } - if (value == null) - { - _configurationInitialized = false; - } + private TConfigurationType LoadConfiguration() + { + var path = ConfigurationFilePath; + + try + { + return (TConfigurationType)XmlSerializer.DeserializeFromFile(typeof(TConfigurationType), path); + } + catch (DirectoryNotFoundException) + { + return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); + } + catch (FileNotFoundException) + { + return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); + } + catch (Exception ex) + { + return (TConfigurationType)Activator.CreateInstance(typeof(TConfigurationType)); } } diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index f618c8a25..5a9fc3322 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Channels public override bool IsVisible(User user) { - if (user.Configuration.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) + if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { return false; } diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs index ede366dab..896d598bb 100644 --- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.Entities; using System.Collections.Generic; using System.Linq; using System.Threading; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -25,8 +26,8 @@ namespace MediaBrowser.Controller.Channels public string OriginalImageUrl { get; set; } public List<ChannelMediaInfo> ChannelMediaSources { get; set; } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); } diff --git a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs index 5362cc195..8482e38df 100644 --- a/MediaBrowser.Controller/Channels/ChannelFolderItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelFolderItem.cs @@ -5,6 +5,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Querying; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -20,7 +21,7 @@ namespace MediaBrowser.Controller.Channels public string OriginalImageUrl { get; set; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. return false; diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs index 72e2b110a..f0eafcbdf 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.Channels return ExternalId; } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.ChannelContent); } diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs index 447328ea1..623ae8968 100644 --- a/MediaBrowser.Controller/Entities/Audio/Audio.cs +++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -173,7 +174,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs index 1f7c62de0..90edfcce7 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Audio { @@ -154,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 2d9e052b1..a60258d1a 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); } @@ -135,7 +136,7 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh songs foreach (var item in songs) { - if (tasks.Count >= 3) + if (tasks.Count >= 2) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); @@ -172,37 +173,23 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh all non-songs foreach (var item in others) { - if (tasks.Count >= 3) - { - await Task.WhenAll(tasks).ConfigureAwait(false); - tasks.Clear(); - } - cancellationToken.ThrowIfCancellationRequested(); - var innerProgress = new ActionableProgress<double>(); // Avoid implicitly captured closure var currentChild = item; - innerProgress.RegisterAction(p => - { - lock (percentages) - { - percentages[currentChild.Id] = p / 100; - var percent = percentages.Values.Sum(); - percent /= totalItems; - percent *= 100; - progress.Report(percent); - } - }); + await item.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); + lock (percentages) + { + percentages[currentChild.Id] = 1; - // Avoid implicitly captured closure - var taskChild = item; - tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); + var percent = percentages.Values.Sum(); + percent /= totalItems; + percent *= 100; + progress.Report(percent); + } } - await Task.WhenAll(tasks).ConfigureAwait(false); - progress.Report(100); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index ed950b1c5..aea04187d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -21,6 +21,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -45,6 +46,8 @@ namespace MediaBrowser.Controller.Entities /// </summary> public static readonly string[] SupportedImageExtensions = { ".png", ".jpg", ".jpeg", ".tbn" }; + public static readonly List<string> SupportedImageExtensionsList = SupportedImageExtensions.ToList(); + /// <summary> /// The trailer folder name /// </summary> @@ -593,7 +596,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>PlayAccess.</returns> public PlayAccess GetPlayAccess(User user) { - if (!user.Configuration.EnableMediaPlayback) + if (!user.Policy.EnableMediaPlayback) { return PlayAccess.None; } @@ -985,7 +988,7 @@ namespace MediaBrowser.Controller.Entities return false; } - var maxAllowedRating = user.Configuration.MaxParentalRating; + var maxAllowedRating = user.Policy.MaxParentalRating; if (maxAllowedRating == null) { @@ -1001,7 +1004,7 @@ namespace MediaBrowser.Controller.Entities if (string.IsNullOrWhiteSpace(rating)) { - return !GetBlockUnratedValue(user.Configuration); + return !GetBlockUnratedValue(user.Policy); } var value = LocalizationManager.GetRatingLevel(rating); @@ -1021,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; } @@ -1035,7 +1038,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="config">The configuration.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> - protected virtual bool GetBlockUnratedValue(UserConfiguration config) + protected virtual bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index ea7ecfb4a..381b2101d 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -36,7 +37,7 @@ namespace MediaBrowser.Controller.Entities Tags = new List<string>(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Book); } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 87ad9c380..2761aa5d7 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; } @@ -545,7 +545,7 @@ namespace MediaBrowser.Controller.Entities foreach (var child in children) { - if (tasks.Count >= 3) + if (tasks.Count >= 2) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); @@ -708,7 +708,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> protected virtual IEnumerable<BaseItem> 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/Entities/Game.cs b/MediaBrowser.Controller/Entities/Game.cs index e4d032359..bf32d3e63 100644 --- a/MediaBrowser.Controller/Entities/Game.cs +++ b/MediaBrowser.Controller/Entities/Game.cs @@ -4,6 +4,7 @@ using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -108,7 +109,7 @@ namespace MediaBrowser.Controller.Entities return base.GetDeletePaths(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Game); } diff --git a/MediaBrowser.Controller/Entities/GameSystem.cs b/MediaBrowser.Controller/Entities/GameSystem.cs index f2fec4397..758498977 100644 --- a/MediaBrowser.Controller/Entities/GameSystem.cs +++ b/MediaBrowser.Controller/Entities/GameSystem.cs @@ -2,6 +2,7 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using System; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -43,7 +44,7 @@ namespace MediaBrowser.Controller.Entities return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. Determine by game return false; diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs index 9dc600675..6563da8de 100644 --- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs +++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { @@ -67,7 +68,7 @@ namespace MediaBrowser.Controller.Entities.Movies /// <value>The display order.</value> 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 e749d89e4..4c1aac700 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.Movies { @@ -146,14 +147,21 @@ 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); } public MovieInfo GetLookupInfo() { - return GetItemLookupInfo<MovieInfo>(); + var info = GetItemLookupInfo<MovieInfo>(); + + if (!IsInMixedFolder) + { + info.Name = System.IO.Path.GetFileName(ContainingFolderPath); + } + + return info; } public override bool BeforeMetadataRefresh() diff --git a/MediaBrowser.Controller/Entities/MusicVideo.cs b/MediaBrowser.Controller/Entities/MusicVideo.cs index d7cd62aa6..4ca8cf1c5 100644 --- a/MediaBrowser.Controller/Entities/MusicVideo.cs +++ b/MediaBrowser.Controller/Entities/MusicVideo.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -80,7 +81,7 @@ namespace MediaBrowser.Controller.Entities return this.GetProviderId(MetadataProviders.Tmdb) ?? this.GetProviderId(MetadataProviders.Imdb) ?? base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Music); } diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 367db5dcb..a3d892181 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Drawing; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -69,8 +70,8 @@ namespace MediaBrowser.Controller.Entities public double? Longitude { get; set; } public double? Altitude { get; set; } public int? IsoSpeedRating { get; set; } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/PhotoAlbum.cs b/MediaBrowser.Controller/Entities/PhotoAlbum.cs index 982b1ef17..24ebf8815 100644 --- a/MediaBrowser.Controller/Entities/PhotoAlbum.cs +++ b/MediaBrowser.Controller/Entities/PhotoAlbum.cs @@ -1,6 +1,7 @@ using MediaBrowser.Model.Configuration; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -22,8 +23,8 @@ namespace MediaBrowser.Controller.Entities return true; } } - - protected override bool GetBlockUnratedValue(UserConfiguration config) + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Other); } diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs index cc0fc6812..6b67cebc8 100644 --- a/MediaBrowser.Controller/Entities/TV/Episode.cs +++ b/MediaBrowser.Controller/Entities/TV/Episode.cs @@ -1,7 +1,7 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Providers; +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; @@ -179,6 +179,15 @@ namespace MediaBrowser.Controller.Entities.TV } [IgnoreDataMember] + public bool IsInSeasonFolder + { + get + { + return FindParent<Season>() != null; + } + } + + [IgnoreDataMember] public string SeriesName { get @@ -275,7 +284,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); } @@ -301,51 +310,9 @@ namespace MediaBrowser.Controller.Entities.TV { var hasChanges = base.BeforeMetadataRefresh(); - var locationType = LocationType; - if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) - { - if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) - { - IndexNumber = LibraryManager.GetEpisodeNumberFromFile(Path, true); - - // If a change was made record it - if (IndexNumber.HasValue) - { - hasChanges = true; - } - } - - if (!IndexNumberEnd.HasValue && !string.IsNullOrEmpty(Path)) - { - IndexNumberEnd = LibraryManager.GetEndingEpisodeNumberFromFile(Path); - - // If a change was made record it - if (IndexNumberEnd.HasValue) - { - hasChanges = true; - } - } - } - - if (!ParentIndexNumber.HasValue) + if (LibraryManager.FillMissingEpisodeNumbersFromPath(this)) { - var season = Season; - - if (season != null) - { - ParentIndexNumber = season.IndexNumber; - } - - if (!ParentIndexNumber.HasValue && !string.IsNullOrEmpty(Path)) - { - ParentIndexNumber = LibraryManager.GetSeasonNumberFromEpisodeFile(Path); - } - - // If a change was made record it - if (ParentIndexNumber.HasValue) - { - hasChanges = true; - } + hasChanges = true; } return hasChanges; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index 2df90244c..54db12b6f 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -1,9 +1,9 @@ -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; @@ -155,24 +155,6 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - private IEnumerable<Episode> GetEpisodes() - { - var series = Series; - - if (series != null && series.ContainsEpisodesWithoutSeasonFolders) - { - var seasonNumber = IndexNumber; - - if (seasonNumber.HasValue) - { - return series.RecursiveChildren.OfType<Episode>() - .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value); - } - } - - return Children.OfType<Episode>(); - } - [IgnoreDataMember] public bool IsMissingSeason { @@ -220,16 +202,32 @@ namespace MediaBrowser.Controller.Entities.TV var episodes = GetRecursiveChildren(user) .OfType<Episode>(); - 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<Episode>() + .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); + } + else + { + list.AddRange(series.GetRecursiveChildren(user).OfType<Episode>() + .Where(i => !i.ParentIndexNumber.HasValue)); } - } + episodes = list.DistinctBy(i => i.Id); + } + if (!includeMissingEpisodes) { episodes = episodes.Where(i => !i.IsMissingEpisode); @@ -244,12 +242,39 @@ namespace MediaBrowser.Controller.Entities.TV .Cast<Episode>(); } + private IEnumerable<Episode> GetEpisodes() + { + var episodes = RecursiveChildren.OfType<Episode>(); + var series = Series; + + if (series != null && series.ContainsEpisodesWithoutSeasonFolders) + { + var seasonNumber = IndexNumber; + var list = episodes.ToList(); + + if (seasonNumber.HasValue) + { + list.AddRange(series.RecursiveChildren.OfType<Episode>() + .Where(i => i.ParentIndexNumber.HasValue && i.ParentIndexNumber.Value == seasonNumber.Value)); + } + else + { + list.AddRange(series.RecursiveChildren.OfType<Episode>() + .Where(i => !i.ParentIndexNumber.HasValue)); + } + + episodes = list.DistinctBy(i => i.Id); + } + + return episodes; + } + public override IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) { return GetEpisodes(user); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. Let either the entire series rating or episode rating determine it return false; diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 4c0d1fdfb..8e43c45e0 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities.TV { @@ -246,7 +247,7 @@ namespace MediaBrowser.Controller.Entities.TV }); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Series); } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index bb165d790..7a1eef8db 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.Serialization; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Entities { @@ -98,7 +99,7 @@ namespace MediaBrowser.Controller.Entities return base.GetUserDataKey(); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Trailer); } diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index 3dfc8cc7d..626afcfdf 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Connect; @@ -107,37 +106,27 @@ namespace MediaBrowser.Controller.Entities /// <value>The last activity date.</value> public DateTime? LastActivityDate { get; set; } - /// <summary> - /// The _configuration - /// </summary> - private UserConfiguration _configuration; - /// <summary> - /// The _configuration initialized - /// </summary> - private bool _configurationInitialized; - /// <summary> - /// The _configuration sync lock - /// </summary> - private object _configurationSyncLock = new object(); - /// <summary> - /// Gets the user's configuration - /// </summary> - /// <value>The configuration.</value> + 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")); } - /// <summary> - /// Gets the path to the user's configuration file - /// </summary> - /// <value>The configuration file path.</value> - [IgnoreDataMember] - public string ConfigurationFilePath - { - get - { - return System.IO.Path.Combine(ConfigurationDirectoryPath, "config.xml"); - } - } - - /// <summary> - /// Updates the configuration. - /// </summary> - /// <param name="config">The config.</param> - /// <exception cref="System.ArgumentNullException">config</exception> - public void UpdateConfiguration(UserConfiguration config) - { - if (config == null) - { - throw new ArgumentNullException("config"); - } - - Configuration = config; - UserManager.UpdateConfiguration(this, Configuration); - } - public bool IsParentalScheduleAllowed() { return IsParentalScheduleAllowed(DateTime.UtcNow); @@ -292,7 +252,7 @@ namespace MediaBrowser.Controller.Entities public bool IsParentalScheduleAllowed(DateTime date) { - var schedules = Configuration.AccessSchedules; + var schedules = Policy.AccessSchedules; if (schedules.Length == 0) { diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 926ffa19c..0364ff678 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -63,7 +63,8 @@ namespace MediaBrowser.Controller.Entities { CollectionType.Books, CollectionType.HomeVideos, - CollectionType.Photos + CollectionType.Photos, + string.Empty }; var collectionFolder = folder as ICollectionFolder; diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 33dea4dca..8573f32e0 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Controller.Sorting; @@ -22,11 +23,9 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="fileInfo">The file information.</param> /// <param name="parent">The parent.</param> - /// <param name="collectionType">Type of the collection.</param> /// <returns>BaseItem.</returns> BaseItem ResolvePath(FileSystemInfo fileInfo, - Folder parent = null, - string collectionType = null); + Folder parent = null); /// <summary> /// Resolves a set of files into a list of BaseItem @@ -258,9 +257,16 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="item">The item.</param> /// <returns>System.String.</returns> - string FindCollectionType(BaseItem item); + string GetContentType(BaseItem item); /// <summary> + /// Gets the type of the inherited content. + /// </summary> + /// <param name="item">The item.</param> + /// <returns>System.String.</returns> + string GetInheritedContentType(BaseItem item); + + /// <summary> /// Normalizes the root path list. /// </summary> /// <param name="paths">The paths.</param> @@ -340,26 +346,11 @@ namespace MediaBrowser.Controller.Library int? GetSeasonNumberFromPath(string path); /// <summary> - /// Gets the season number from episode file. - /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.Nullable<System.Int32>.</returns> - int? GetSeasonNumberFromEpisodeFile(string path); - - /// <summary> - /// Gets the ending episode number from file. + /// Fills the missing episode numbers from path. /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.Nullable<System.Int32>.</returns> - int? GetEndingEpisodeNumberFromFile(string path); - - /// <summary> - /// Gets the episode number from file. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="considerSeasonless">if set to <c>true</c> [consider seasonless].</param> - /// <returns>System.Nullable<System.Int32>.</returns> - int? GetEpisodeNumberFromFile(string path, bool considerSeasonless); + /// <param name="episode">The episode.</param> + /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> + bool FillMissingEpisodeNumbersFromPath(Episode episode); /// <summary> /// Parses the name. diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 9dc16ba4d..f5846973e 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -36,13 +36,6 @@ namespace MediaBrowser.Controller.Library event EventHandler<GenericEventArgs<User>> UserPasswordChanged; /// <summary> - /// Updates the configuration. - /// </summary> - /// <param name="user">The user.</param> - /// <param name="newConfiguration">The new configuration.</param> - void UpdateConfiguration(User user, UserConfiguration newConfiguration); - - /// <summary> /// Gets a User by Id /// </summary> /// <param name="id">The id.</param> @@ -173,10 +166,32 @@ namespace MediaBrowser.Controller.Library UserPolicy GetUserPolicy(User user); /// <summary> + /// Gets the user configuration. + /// </summary> + /// <param name="user">The user.</param> + /// <returns>UserConfiguration.</returns> + UserConfiguration GetUserConfiguration(User user); + + /// <summary> + /// Updates the configuration. + /// </summary> + /// <param name="userId">The user identifier.</param> + /// <param name="newConfiguration">The new configuration.</param> + /// <returns>Task.</returns> + Task UpdateConfiguration(string userId, UserConfiguration newConfiguration); + + /// <summary> /// Updates the user policy. /// </summary> /// <param name="userId">The user identifier.</param> /// <param name="userPolicy">The user policy.</param> Task UpdateUserPolicy(string userId, UserPolicy userPolicy); + + /// <summary> + /// Makes the valid username. + /// </summary> + /// <param name="username">The username.</param> + /// <returns>System.String.</returns> + string MakeValidUsername(string username); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs index 9f8d67a48..b95d67ad8 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs index df118b25f..de72accff 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs @@ -6,6 +6,7 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using System.Collections.Generic; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -33,7 +34,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvChannel); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 266eaabee..29b23a551 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -6,6 +6,7 @@ using System; using System.Threading; using System.Threading.Tasks; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -199,7 +200,7 @@ namespace MediaBrowser.Controller.LiveTv return ItemRepository.SaveItem(this, cancellationToken); } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs index 66de81213..6fc985643 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs @@ -2,6 +2,7 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System.Linq; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { @@ -78,7 +79,7 @@ namespace MediaBrowser.Controller.LiveTv } } - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.LiveTvProgram); } diff --git a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs index 7bd810b8d..d7250d9d2 100644 --- a/MediaBrowser.Controller/LiveTv/RecordingGroup.cs +++ b/MediaBrowser.Controller/LiveTv/RecordingGroup.cs @@ -1,11 +1,12 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.LiveTv { public class RecordingGroup : Folder { - protected override bool GetBlockUnratedValue(UserConfiguration config) + protected override bool GetBlockUnratedValue(UserPolicy config) { // Don't block. return false; diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index c198a58d4..3b9f3a5b2 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -198,16 +198,13 @@ <Compile Include="LiveTv\SeriesTimerInfo.cs" /> <Compile Include="LiveTv\TimerInfo.cs" /> <Compile Include="Localization\ILocalizationManager.cs" /> - <Compile Include="MediaEncoding\EncodingOptions.cs" /> <Compile Include="MediaEncoding\ChapterImageRefreshOptions.cs" /> - <Compile Include="MediaEncoding\EncodingResult.cs" /> <Compile Include="MediaEncoding\IEncodingManager.cs" /> <Compile Include="MediaEncoding\ImageEncodingOptions.cs" /> <Compile Include="MediaEncoding\IMediaEncoder.cs" /> <Compile Include="MediaEncoding\InternalMediaInfoResult.cs" /> <Compile Include="MediaEncoding\ISubtitleEncoder.cs" /> <Compile Include="MediaEncoding\MediaStreamSelector.cs" /> - <Compile Include="MediaEncoding\VideoEncodingOptions.cs" /> <Compile Include="Net\AuthenticatedAttribute.cs" /> <Compile Include="Net\AuthorizationInfo.cs" /> <Compile Include="Net\IAuthorizationContext.cs" /> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs deleted file mode 100644 index 26182ebc4..000000000 --- a/MediaBrowser.Controller/MediaEncoding/EncodingOptions.cs +++ /dev/null @@ -1,80 +0,0 @@ -using MediaBrowser.Controller.Dlna; -using MediaBrowser.Model.Dlna; - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class EncodingOptions - { - /// <summary> - /// Gets or sets the item identifier. - /// </summary> - /// <value>The item identifier.</value> - public string ItemId { get; set; } - - /// <summary> - /// Gets or sets the media source identifier. - /// </summary> - /// <value>The media source identifier.</value> - public string MediaSourceId { get; set; } - - /// <summary> - /// Gets or sets the device profile. - /// </summary> - /// <value>The device profile.</value> - public DeviceProfile DeviceProfile { get; set; } - - /// <summary> - /// Gets or sets the output path. - /// </summary> - /// <value>The output path.</value> - public string OutputPath { get; set; } - - /// <summary> - /// Gets or sets the container. - /// </summary> - /// <value>The container.</value> - public string Container { get; set; } - - /// <summary> - /// Gets or sets the audio codec. - /// </summary> - /// <value>The audio codec.</value> - public string AudioCodec { get; set; } - - /// <summary> - /// Gets or sets the start time ticks. - /// </summary> - /// <value>The start time ticks.</value> - public long? StartTimeTicks { get; set; } - - /// <summary> - /// Gets or sets the maximum channels. - /// </summary> - /// <value>The maximum channels.</value> - public int? MaxAudioChannels { get; set; } - - /// <summary> - /// Gets or sets the channels. - /// </summary> - /// <value>The channels.</value> - public int? AudioChannels { get; set; } - - /// <summary> - /// Gets or sets the sample rate. - /// </summary> - /// <value>The sample rate.</value> - public int? AudioSampleRate { get; set; } - - /// <summary> - /// Gets or sets the bit rate. - /// </summary> - /// <value>The bit rate.</value> - public int? AudioBitRate { get; set; } - - /// <summary> - /// Gets or sets the maximum audio bit rate. - /// </summary> - /// <value>The maximum audio bit rate.</value> - public int? MaxAudioBitRate { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs b/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs deleted file mode 100644 index 75ee90e42..000000000 --- a/MediaBrowser.Controller/MediaEncoding/EncodingResult.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class EncodingResult - { - public string OutputPath { get; set; } - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs b/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs deleted file mode 100644 index 773f0ea46..000000000 --- a/MediaBrowser.Controller/MediaEncoding/VideoEncodingOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ - -namespace MediaBrowser.Controller.MediaEncoding -{ - public class VideoEncodingOptions : EncodingOptions - { - public string VideoCodec { get; set; } - - public string VideoProfile { get; set; } - - public double? VideoLevel { get; set; } - - public int? VideoStreamIndex { get; set; } - - public int? AudioStreamIndex { get; set; } - - public int? SubtitleStreamIndex { get; set; } - - public int? MaxWidth { get; set; } - - public int? MaxHeight { get; set; } - - public int? Height { get; set; } - - public int? Width { get; set; } - } -} diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index 6f8047e4c..74e3b61ca 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; } @@ -90,7 +84,7 @@ namespace MediaBrowser.LocalMetadata { get { - return "Media Browser Legacy Xml"; + return "Media Browser Xml"; } } diff --git a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs index 044d29a1b..9b1cce915 100644 --- a/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs +++ b/MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs @@ -76,11 +76,14 @@ namespace MediaBrowser.LocalMetadata.Images { return directoryService.GetFileSystemEntries(path) .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase) || - (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory); + (i.Attributes & FileAttributes.Directory) == FileAttributes.Directory) + + .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty)); } return directoryService.GetFiles(path) - .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)); + .Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase)) + .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty)); } public List<LocalImageInfo> GetImages(IHasImages item, IDirectoryService directoryService) @@ -109,6 +112,7 @@ namespace MediaBrowser.LocalMetadata.Images return !string.IsNullOrEmpty(ext) && BaseItem.SupportedImageExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase); }) + .OrderBy(i => BaseItem.SupportedImageExtensionsList.IndexOf(i.Extension ?? string.Empty)) .ToList(); var list = new List<LocalImageInfo>(); @@ -402,13 +406,7 @@ namespace MediaBrowser.LocalMetadata.Images private FileSystemInfo GetImage(IEnumerable<FileSystemInfo> files, string name) { - var candidates = files - .Where(i => string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase)) - .ToList(); - - return BaseItem.SupportedImageExtensions - .Select(i => candidates.FirstOrDefault(c => string.Equals(c.Extension, i, StringComparison.OrdinalIgnoreCase))) - .FirstOrDefault(i => i != null); + return files.FirstOrDefault(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && string.Equals(name, _fileSystem.GetFileNameWithoutExtension(i), StringComparison.OrdinalIgnoreCase)); } } } diff --git a/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs new file mode 100644 index 000000000..17470d206 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Configuration/EncodingConfigurationFactory.cs @@ -0,0 +1,45 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Configuration; +using System.Collections.Generic; +using System.IO; + +namespace MediaBrowser.MediaEncoding.Configuration +{ + public class EncodingConfigurationFactory : IConfigurationFactory + { + public IEnumerable<ConfigurationStore> GetConfigurations() + { + return new[] + { + new EncodingConfigurationStore() + }; + } + } + + public class EncodingConfigurationStore : ConfigurationStore, IValidatingConfiguration + { + public EncodingConfigurationStore() + { + ConfigurationType = typeof(EncodingOptions); + Key = "encoding"; + } + + public void Validate(object oldConfig, object newConfig) + { + var oldEncodingConfig = (EncodingOptions)oldConfig; + var newEncodingConfig = (EncodingOptions)newConfig; + + var newPath = newEncodingConfig.TranscodingTempPath; + + if (!string.IsNullOrWhiteSpace(newPath) + && !string.Equals(oldEncodingConfig.TranscodingTempPath ?? string.Empty, newPath)) + { + // Validate + if (!Directory.Exists(newPath)) + { + throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath)); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 6f59b7bec..5c472ebc8 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -56,6 +56,7 @@ <Link>Properties\SharedVersion.cs</Link> </Compile> <Compile Include="BdInfo\BdInfoExaminer.cs" /> + <Compile Include="Configuration\EncodingConfigurationFactory.cs" /> <Compile Include="Encoder\EncodingUtils.cs" /> <Compile Include="Encoder\MediaEncoder.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7c512840b..67c9123f5 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -613,6 +613,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles { } + catch (DirectoryNotFoundException) + { + + } catch (IOException ex) { _logger.ErrorException("Error deleting extracted subtitle {0}", ex, outputPath); diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index 2629dac8b..9900484cd 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -188,6 +188,9 @@ <Compile Include="..\MediaBrowser.Model\Configuration\DynamicDayOfWeek.cs"> <Link>Configuration\DynamicDayOfWeek.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs"> + <Link>Configuration\EncodingOptions.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs"> <Link>Configuration\EncodingQuality.cs</Link> </Compile> @@ -461,6 +464,12 @@ <Compile Include="..\MediaBrowser.Model\Dto\MediaSourceType.cs"> <Link>Dto\MediaSourceType.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs"> + <Link>Dto\MetadataEditorInfo.cs</Link> + </Compile> + <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs"> + <Link>Dto\NameValuePair.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Dto\RatingType.cs"> <Link>Dto\RatingType.cs</Link> </Compile> @@ -1034,6 +1043,9 @@ <Compile Include="..\MediaBrowser.Model\Sync\SyncDialogOptions.cs"> <Link>Sync\SyncDialogOptions.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Sync\SyncItem.cs"> + <Link>Sync\SyncItem.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs"> <Link>Sync\SyncJob.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 4840777a5..bd98b5b86 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -153,6 +153,9 @@ <Compile Include="..\MediaBrowser.Model\Configuration\DynamicDayOfWeek.cs"> <Link>Configuration\DynamicDayOfWeek.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Configuration\EncodingOptions.cs"> + <Link>Configuration\EncodingOptions.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Configuration\EncodingQuality.cs"> <Link>Configuration\EncodingQuality.cs</Link> </Compile> @@ -426,6 +429,12 @@ <Compile Include="..\MediaBrowser.Model\Dto\MediaSourceType.cs"> <Link>Dto\MediaSourceType.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Dto\MetadataEditorInfo.cs"> + <Link>Dto\MetadataEditorInfo.cs</Link> + </Compile> + <Compile Include="..\MediaBrowser.Model\Dto\NameValuePair.cs"> + <Link>Dto\NameValuePair.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Dto\RatingType.cs"> <Link>Dto\RatingType.cs</Link> </Compile> @@ -993,6 +1002,9 @@ <Compile Include="..\MediaBrowser.Model\Sync\SyncDialogOptions.cs"> <Link>Sync\SyncDialogOptions.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Sync\SyncItem.cs"> + <Link>Sync\SyncItem.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Sync\SyncJob.cs"> <Link>Sync\SyncJob.cs</Link> </Compile> diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 9521f8538..0181325fe 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -186,6 +186,14 @@ namespace MediaBrowser.Model.ApiClient Task<Stream> GetImageStreamAsync(string url, CancellationToken cancellationToken = default(CancellationToken)); /// <summary> + /// Updates the user configuration. + /// </summary> + /// <param name="userId">The user identifier.</param> + /// <param name="configuration">The configuration.</param> + /// <returns>Task.</returns> + Task UpdateUserConfiguration(string userId, UserConfiguration configuration); + + /// <summary> /// Gets a BaseItem /// </summary> /// <param name="id">The id.</param> @@ -497,15 +505,6 @@ namespace MediaBrowser.Model.ApiClient /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task<PublicSystemInfo>.</returns> Task<PublicSystemInfo> GetPublicSystemInfoAsync(CancellationToken cancellationToken = default(CancellationToken)); - - /// <summary> - /// Gets a person - /// </summary> - /// <param name="name">The name.</param> - /// <param name="userId">The user id.</param> - /// <returns>Task{BaseItemDto}.</returns> - /// <exception cref="ArgumentNullException">userId</exception> - Task<BaseItemDto> GetPersonAsync(string name, string userId); /// <summary> /// Gets a list of plugins installed on the server @@ -962,15 +961,6 @@ namespace MediaBrowser.Model.ApiClient /// <summary> /// Gets an image url that can be used to download an image from the api /// </summary> - /// <param name="name">The name of the person</param> - /// <param name="options">The options.</param> - /// <returns>System.String.</returns> - /// <exception cref="ArgumentNullException">name</exception> - string GetPersonImageUrl(string name, ImageOptions options); - - /// <summary> - /// Gets an image url that can be used to download an image from the api - /// </summary> /// <param name="year">The year.</param> /// <param name="options">The options.</param> /// <returns>System.String.</returns> diff --git a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs index bd20713de..764a7222f 100644 --- a/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs +++ b/MediaBrowser.Model/Configuration/CinemaModeConfiguration.cs @@ -19,6 +19,7 @@ namespace MediaBrowser.Model.Configuration public CinemaModeConfiguration() { EnableIntrosParentalControl = true; + EnableIntrosFromSimilarMovies = true; TrailerLimit = 2; } } diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs new file mode 100644 index 000000000..f24367298 --- /dev/null +++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs @@ -0,0 +1,19 @@ + +namespace MediaBrowser.Model.Configuration +{ + public class EncodingOptions + { + public EncodingQuality EncodingQuality { get; set; } + public string TranscodingTempPath { get; set; } + public double DownMixAudioBoost { get; set; } + public string H264Encoder { get; set; } + public bool EnableDebugLogging { get; set; } + + public EncodingOptions() + { + H264Encoder = "libx264"; + DownMixAudioBoost = 2; + EncodingQuality = EncodingQuality.Auto; + } + } +} diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index b9eaf7001..730735499 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Model.Configuration { @@ -144,21 +145,8 @@ namespace MediaBrowser.Model.Configuration /// <value>The image saving convention.</value> public ImageSavingConvention ImageSavingConvention { get; set; } - /// <summary> - /// Gets or sets a value indicating whether [enable people prefix sub folders]. - /// </summary> - /// <value><c>true</c> if [enable people prefix sub folders]; otherwise, <c>false</c>.</value> - public bool EnablePeoplePrefixSubFolders { get; set; } - - /// <summary> - /// Gets or sets the encoding quality. - /// </summary> - /// <value>The encoding quality.</value> - public EncodingQuality MediaEncodingQuality { get; set; } - public MetadataOptions[] MetadataOptions { get; set; } - public bool EnableDebugEncodingLogging { get; set; } public string TranscodingTempPath { get; set; } public bool EnableAutomaticRestart { get; set; } @@ -171,8 +159,6 @@ namespace MediaBrowser.Model.Configuration public string UICulture { get; set; } - public double DownMixAudioBoost { get; set; } - public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } @@ -180,7 +166,7 @@ namespace MediaBrowser.Model.Configuration public bool SaveMetadataHidden { get; set; } - public bool PlaylistImagesDeleted { get; set; } + public NameValuePair[] ContentTypes { get; set; } /// <summary> /// Initializes a new instance of the <see cref="ServerConfiguration" /> class. @@ -188,17 +174,14 @@ namespace MediaBrowser.Model.Configuration public ServerConfiguration() : base() { - MediaEncodingQuality = EncodingQuality.Auto; ImageSavingConvention = ImageSavingConvention.Compatible; PublicPort = 8096; HttpServerPortNumber = 8096; EnableDashboardResponseCaching = true; EnableAutomaticRestart = true; - EnablePeoplePrefixSubFolders = true; EnableUPnP = true; - DownMixAudioBoost = 2; MinResumePct = 5; MaxResumePct = 90; @@ -212,6 +195,7 @@ namespace MediaBrowser.Model.Configuration FindInternetTrailers = true; PathSubstitutions = new PathSubstitution[] { }; + ContentTypes = new NameValuePair[] { }; PreferredMetadataLanguage = "en"; MetadataCountryCode = "US"; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index f0a27a2b9..9e33c1c36 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -42,6 +42,10 @@ namespace MediaBrowser.Model.Configuration /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value> public bool IsHidden { get; set; } + /// <summary> + /// Gets or sets a value indicating whether this instance is disabled. + /// </summary> + /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value> 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 HasMigratedToPolicy { get; set; } + /// <summary> /// Initializes a new instance of the <see cref="UserConfiguration" /> class. /// </summary> @@ -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/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 71cefa076..87fdce799 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -549,7 +549,13 @@ namespace MediaBrowser.Model.Dto /// Gets or sets a value indicating whether [supports playlists]. /// </summary> /// <value><c>true</c> if [supports playlists]; otherwise, <c>false</c>.</value> - public bool SupportsPlaylists { get; set; } + public bool SupportsPlaylists + { + get + { + return RunTimeTicks.HasValue || IsFolder || IsGenre || IsMusicGenre || IsArtist; + } + } /// <summary> /// Determines whether the specified type is type. diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs new file mode 100644 index 000000000..9bd15fc8f --- /dev/null +++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs @@ -0,0 +1,27 @@ +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Providers; +using System.Collections.Generic; + +namespace MediaBrowser.Model.Dto +{ + public class MetadataEditorInfo + { + public List<ParentalRating> ParentalRatingOptions { get; set; } + public List<CountryInfo> Countries { get; set; } + public List<CultureDto> Cultures { get; set; } + public List<ExternalIdInfo> ExternalIdInfos { get; set; } + + public string ContentType { get; set; } + public List<NameValuePair> ContentTypeOptions { get; set; } + + public MetadataEditorInfo() + { + ParentalRatingOptions = new List<ParentalRating>(); + Countries = new List<CountryInfo>(); + Cultures = new List<CultureDto>(); + ExternalIdInfos = new List<ExternalIdInfo>(); + ContentTypeOptions = new List<NameValuePair>(); + } + } +} diff --git a/MediaBrowser.Model/Dto/NameValuePair.cs b/MediaBrowser.Model/Dto/NameValuePair.cs new file mode 100644 index 000000000..2d55e8f2a --- /dev/null +++ b/MediaBrowser.Model/Dto/NameValuePair.cs @@ -0,0 +1,17 @@ + +namespace MediaBrowser.Model.Dto +{ + public class NameValuePair + { + /// <summary> + /// Gets or sets the name. + /// </summary> + /// <value>The name.</value> + public string Name { get; set; } + /// <summary> + /// Gets or sets the value. + /// </summary> + /// <value>The value.</value> + public string Value { get; set; } + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index b81b4c1fd..e1f0e78f4 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -96,6 +96,7 @@ <Compile Include="Configuration\ChannelOptions.cs" /> <Compile Include="Configuration\ChapterOptions.cs" /> <Compile Include="Configuration\CinemaModeConfiguration.cs" /> + <Compile Include="Configuration\EncodingOptions.cs" /> <Compile Include="Configuration\MetadataConfiguration.cs" /> <Compile Include="Configuration\PeopleMetadataOptions.cs" /> <Compile Include="Configuration\XbmcMetadataOptions.cs" /> @@ -128,6 +129,8 @@ <Compile Include="Drawing\ImageOrientation.cs" /> <Compile Include="Dto\DtoOptions.cs" /> <Compile Include="Dto\IHasServerId.cs" /> + <Compile Include="Dto\MetadataEditorInfo.cs" /> + <Compile Include="Dto\NameValuePair.cs" /> <Compile Include="MediaInfo\LiveMediaInfoResult.cs" /> <Compile Include="Dto\MediaSourceType.cs" /> <Compile Include="Dto\StreamOptions.cs" /> @@ -366,6 +369,7 @@ <Compile Include="Sync\SyncCategory.cs" /> <Compile Include="Sync\SyncDialogOptions.cs" /> <Compile Include="Sync\SyncHelper.cs" /> + <Compile Include="Sync\SyncItem.cs" /> <Compile Include="Sync\SyncJob.cs" /> <Compile Include="Sync\SyncJobCreationResult.cs" /> <Compile Include="Sync\SyncJobItem.cs" /> diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index 19e30cd8a..f288bfe48 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -7,6 +7,11 @@ namespace MediaBrowser.Model.Querying public enum ItemFields { /// <summary> + /// The air time + /// </summary> + AirTime, + + /// <summary> /// The alternate episode numbers /// </summary> AlternateEpisodeNumbers, @@ -102,11 +107,6 @@ namespace MediaBrowser.Model.Querying Metascore, /// <summary> - /// The metadata settings - /// </summary> - Settings, - - /// <summary> /// The item overview /// </summary> Overview, @@ -152,6 +152,16 @@ namespace MediaBrowser.Model.Querying Revenue, /// <summary> + /// The season name + /// </summary> + SeasonName, + + /// <summary> + /// The settings + /// </summary> + Settings, + + /// <summary> /// The short overview /// </summary> ShortOverview, @@ -182,6 +192,11 @@ namespace MediaBrowser.Model.Querying SortName, /// <summary> + /// The special episode numbers + /// </summary> + SpecialEpisodeNumbers, + + /// <summary> /// The studios of the item /// </summary> Studios, diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs index b3ab32a44..e646d80d3 100644 --- a/MediaBrowser.Model/Session/TranscodingInfo.cs +++ b/MediaBrowser.Model/Session/TranscodingInfo.cs @@ -5,6 +5,8 @@ namespace MediaBrowser.Model.Session public string AudioCodec { get; set; } public string VideoCodec { get; set; } public string Container { get; set; } + public bool IsVideoDirect { get; set; } + public bool IsAudioDirect { get; set; } public int? Bitrate { get; set; } public float? Framerate { get; set; } diff --git a/MediaBrowser.Model/Sync/SyncItem.cs b/MediaBrowser.Model/Sync/SyncItem.cs new file mode 100644 index 000000000..d50ae98c9 --- /dev/null +++ b/MediaBrowser.Model/Sync/SyncItem.cs @@ -0,0 +1,9 @@ +using MediaBrowser.Model.Dto; + +namespace MediaBrowser.Model.Sync +{ + public class SyncItem + { + public BaseItemDto Item { get; set; } + } +} diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index b458e2854..4d09ae8e8 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -1,8 +1,69 @@ - +using MediaBrowser.Model.Configuration; + namespace MediaBrowser.Model.Users { public class UserPolicy { + /// <summary> + /// Gets or sets a value indicating whether this instance is administrator. + /// </summary> + /// <value><c>true</c> if this instance is administrator; otherwise, <c>false</c>.</value> + public bool IsAdministrator { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is hidden. + /// </summary> + /// <value><c>true</c> if this instance is hidden; otherwise, <c>false</c>.</value> + public bool IsHidden { get; set; } + + /// <summary> + /// Gets or sets a value indicating whether this instance is disabled. + /// </summary> + /// <value><c>true</c> if this instance is disabled; otherwise, <c>false</c>.</value> + public bool IsDisabled { get; set; } + + /// <summary> + /// Gets or sets the max parental rating. + /// </summary> + /// <value>The max parental rating.</value> + 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; } + + /// <summary> + /// Gets or sets a value indicating whether [enable synchronize]. + /// </summary> + /// <value><c>true</c> if [enable synchronize]; otherwise, <c>false</c>.</value> 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.Providers/Movies/FanartMovieImageProvider.cs b/MediaBrowser.Providers/Movies/FanartMovieImageProvider.cs index a7ccf3f6e..6813f2ff5 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 94d682f44..123ff9e29 100644 --- a/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtAlbumProvider.cs @@ -83,6 +83,10 @@ namespace MediaBrowser.Providers.Music { } + catch (DirectoryNotFoundException) + { + + } } var language = item.GetPreferredMetadataLanguage(); diff --git a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs index a8df95fd1..6f633cfc8 100644 --- a/MediaBrowser.Providers/Music/FanArtArtistProvider.cs +++ b/MediaBrowser.Providers/Music/FanArtArtistProvider.cs @@ -91,6 +91,10 @@ namespace MediaBrowser.Providers.Music { } + catch (DirectoryNotFoundException) + { + + } } var language = item.GetPreferredMetadataLanguage(); diff --git a/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs b/MediaBrowser.Providers/People/TvdbPersonImageProvider.cs index 63d054664..253acc13f 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 05244af74..9f0cd4ff1 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 afc71698b..8ba25e9f1 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 21d41ca00..0b52956de 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<IGrouping<string, Series>> 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 /// <returns></returns> private async Task<bool> AddDummySeasonFolders(Series series, CancellationToken cancellationToken) { - var existingEpisodes = series.RecursiveChildren + var episodesInSeriesFolder = series.RecursiveChildren .OfType<Episode>() + .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<Season>() + .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 /// </summary> private async Task<bool> RemoveObsoleteOrMissingEpisodes(IEnumerable<Series> series, - IEnumerable<Tuple<int, int>> episodeLookup, - bool forceRemoveAll) + IEnumerable<Tuple<int, int>> 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 /// </summary> /// <param name="series">The series.</param> /// <param name="episodeLookup">The episode lookup.</param> - /// <param name="forceRemoveAll">if set to <c>true</c> [force remove all].</param> /// <returns>Task{System.Boolean}.</returns> private async Task<bool> RemoveObsoleteOrMissingSeasons(IEnumerable<Series> series, - IEnumerable<Tuple<int, int>> episodeLookup, - bool forceRemoveAll) + IEnumerable<Tuple<int, int>> 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<Episode>().All(s => s.ParentIndexNumber.HasValue || s.IsInSeasonFolder); }) .ToList(); @@ -472,20 +479,22 @@ namespace MediaBrowser.Providers.TV /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{Season}.</returns> private async Task<Season> 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/MovieDbSeasonProvider.cs b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs index 26b2711de..80f4c9485 100644 --- a/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs +++ b/MediaBrowser.Providers/TV/MovieDbSeasonProvider.cs @@ -52,18 +52,18 @@ namespace MediaBrowser.Providers.TV if (!string.IsNullOrWhiteSpace(seriesTmdbId) && seasonNumber.HasValue) { - result.HasMetadata = true; - result.Item = new Season(); - try { var seasonInfo = await GetSeasonInfo(seriesTmdbId, seasonNumber.Value, info.MetadataLanguage, cancellationToken) .ConfigureAwait(false); + result.HasMetadata = true; + result.Item = new Season(); result.Item.Name = info.Name; - result.Item.Overview = seasonInfo.overview; result.Item.IndexNumber = seasonNumber; + result.Item.Overview = seasonInfo.overview; + if (seasonInfo.external_ids.tvdb_id > 0) { result.Item.SetProviderId(MetadataProviders.Tvdb, seasonInfo.external_ids.tvdb_id.ToString(CultureInfo.InvariantCulture)); diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index d350d2fe4..e1986a7c1 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -1,11 +1,12 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -25,12 +26,14 @@ namespace MediaBrowser.Providers.TV private readonly ILibraryManager _libraryManager; private readonly IServerConfigurationManager _config; private readonly ILogger _logger; + private readonly ILocalizationManager _localization; - public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config) + public SeriesPostScanTask(ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, ILocalizationManager localization) { _libraryManager = libraryManager; _logger = logger; _config = config; + _localization = localization; } public Task Run(IProgress<double> progress, CancellationToken cancellationToken) @@ -47,7 +50,7 @@ namespace MediaBrowser.Providers.TV var seriesGroups = FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); - await new MissingEpisodeProvider(_logger, _config, _libraryManager).Run(seriesGroups, cancellationToken).ConfigureAwait(false); + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization).Run(seriesGroups, cancellationToken).ConfigureAwait(false); var numComplete = 0; diff --git a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs index ef9f5427c..52c1ab7dd 100644 --- a/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs @@ -72,6 +72,10 @@ namespace MediaBrowser.Providers.TV { // Don't fail the provider because this will just keep on going and going. } + catch (DirectoryNotFoundException) + { + // Don't fail the provider because this will just keep on going and going. + } } return list; @@ -101,6 +105,10 @@ namespace MediaBrowser.Providers.TV { // Don't fail the provider because this will just keep on going and going. } + catch (DirectoryNotFoundException) + { + // Don't fail the provider because this will just keep on going and going. + } } return result; @@ -208,8 +216,9 @@ namespace MediaBrowser.Providers.TV /// Fetches the episode data. /// </summary> /// <param name="id">The identifier.</param> + /// <param name="identity">The identity.</param> /// <param name="seriesDataPath">The series data path.</param> - /// <param name="seriesProviderIds"></param> + /// <param name="seriesProviderIds">The series provider ids.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.Boolean}.</returns> private Episode FetchEpisodeData(EpisodeInfo id, EpisodeIdentity identity, string seriesDataPath, Dictionary<string, string> seriesProviderIds, CancellationToken cancellationToken) @@ -279,6 +288,10 @@ namespace MediaBrowser.Providers.TV { break; } + catch (DirectoryNotFoundException) + { + break; + } episodeNumber++; } diff --git a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs index efafeae96..1ebd7bed5 100644 --- a/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeasonImageProvider.cs @@ -94,6 +94,10 @@ namespace MediaBrowser.Providers.TV { // No tvdb data yet. Don't blow up } + catch (DirectoryNotFoundException) + { + // No tvdb data yet. Don't blow up + } } return new RemoteImageInfo[] { }; diff --git a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs index 9cc09c40c..08913d3b4 100644 --- a/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs +++ b/MediaBrowser.Providers/TV/TvdbSeriesImageProvider.cs @@ -87,6 +87,10 @@ namespace MediaBrowser.Providers.TV { // No tvdb data yet. Don't blow up } + catch (DirectoryNotFoundException) + { + // No tvdb data yet. Don't blow up + } } return new RemoteImageInfo[] { }; diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs index bfdbb8ccf..ce939aeb4 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Channels public static string GetUserDistinctValue(User user) { - var channels = user.Configuration.BlockedChannels + var channels = user.Policy.BlockedChannels .OrderBy(i => i) .ToList(); diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs index 72c524ec5..d266cca6c 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelPostScanTask.cs @@ -72,26 +72,29 @@ namespace MediaBrowser.Server.Implementations.Channels var features = _channelManager.GetChannelFeatures(channelId); const int currentRefreshLevel = 1; - var maxRefreshLevel = features.AutoRefreshLevels ?? 1; + var maxRefreshLevel = features.AutoRefreshLevels ?? 0; - var innerProgress = new ActionableProgress<double>(); - - var startingNumberComplete = numComplete; - innerProgress.RegisterAction(p => + if (maxRefreshLevel > 0) { - double innerPercent = startingNumberComplete; - innerPercent += (p / 100); - innerPercent /= numItems; - progress.Report(innerPercent * 100); - }); + var innerProgress = new ActionableProgress<double>(); - try - { - await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting channel content", ex); + var startingNumberComplete = numComplete; + innerProgress.RegisterAction(p => + { + double innerPercent = startingNumberComplete; + innerPercent += (p / 100); + innerPercent /= numItems; + progress.Report(innerPercent * 100); + }); + + try + { + await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting channel content", ex); + } } numComplete++; diff --git a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs index b9896e9ce..b3b8ccbd8 100644 --- a/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs +++ b/MediaBrowser.Server.Implementations/Configuration/ServerConfigurationManager.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.Configuration; +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Common.Implementations.Configuration; using MediaBrowser.Controller; @@ -32,7 +33,6 @@ namespace MediaBrowser.Server.Implementations.Configuration : base(applicationPaths, logManager, xmlSerializer) { UpdateItemsByNamePath(); - UpdateTranscodingTempPath(); UpdateMetadataPath(); } @@ -71,12 +71,18 @@ namespace MediaBrowser.Server.Implementations.Configuration protected override void OnConfigurationUpdated() { UpdateItemsByNamePath(); - UpdateTranscodingTempPath(); UpdateMetadataPath(); base.OnConfigurationUpdated(); } + public override void AddParts(IEnumerable<IConfigurationFactory> factories) + { + base.AddParts(factories); + + UpdateTranscodingTempPath(); + } + /// <summary> /// Updates the items by name path. /// </summary> @@ -102,9 +108,21 @@ namespace MediaBrowser.Server.Implementations.Configuration /// </summary> private void UpdateTranscodingTempPath() { - ((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(Configuration.TranscodingTempPath) ? + var encodingConfig = this.GetConfiguration<EncodingOptions>("encoding"); + + ((ServerApplicationPaths)ApplicationPaths).TranscodingTempPath = string.IsNullOrEmpty(encodingConfig.TranscodingTempPath) ? null : - Configuration.TranscodingTempPath; + encodingConfig.TranscodingTempPath; + } + + protected override void OnNamedConfigurationUpdated(string key, object configuration) + { + base.OnNamedConfigurationUpdated(key, configuration); + + if (string.Equals(key, "encoding", StringComparison.OrdinalIgnoreCase)) + { + UpdateTranscodingTempPath(); + } } /// <summary> @@ -117,7 +135,6 @@ namespace MediaBrowser.Server.Implementations.Configuration var newConfig = (ServerConfiguration)newConfiguration; ValidateItemByNamePath(newConfig); - ValidateTranscodingTempPath(newConfig); ValidatePathSubstitutions(newConfig); ValidateMetadataPath(newConfig); @@ -158,26 +175,6 @@ namespace MediaBrowser.Server.Implementations.Configuration } /// <summary> - /// Validates the transcoding temporary path. - /// </summary> - /// <param name="newConfig">The new configuration.</param> - /// <exception cref="DirectoryNotFoundException"></exception> - private void ValidateTranscodingTempPath(ServerConfiguration newConfig) - { - var newPath = newConfig.TranscodingTempPath; - - if (!string.IsNullOrWhiteSpace(newPath) - && !string.Equals(Configuration.TranscodingTempPath ?? string.Empty, newPath)) - { - // Validate - if (!Directory.Exists(newPath)) - { - throw new DirectoryNotFoundException(string.Format("{0} does not exist.", newPath)); - } - } - } - - /// <summary> /// Validates the metadata path. /// </summary> /// <param name="newConfig">The new configuration.</param> diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs index cbd75cdeb..67d844543 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; @@ -432,9 +433,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); @@ -791,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; @@ -800,23 +799,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 +841,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 +854,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 +867,7 @@ namespace MediaBrowser.Server.Implementations.Connect } } - if (user.Configuration.SyncConnectImage) + if (syncConnectImage) { var imageUrl = authorization.UserImageUrl; diff --git a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs index b141fea1e..967c78c50 100644 --- a/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs +++ b/MediaBrowser.Server.Implementations/Drawing/ImageProcessor.cs @@ -78,6 +78,11 @@ namespace MediaBrowser.Server.Implementations.Drawing // No biggie sizeDictionary = new Dictionary<Guid, ImageSize>(); } + catch (DirectoryNotFoundException) + { + // No biggie + sizeDictionary = new Dictionary<Guid, ImageSize>(); + } catch (Exception ex) { logger.ErrorException("Error parsing image size cache file", ex); diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 1020a4373..a14a8ad08 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -121,8 +121,6 @@ namespace MediaBrowser.Server.Implementations.Dto ServerId = _appHost.SystemId }; - dto.SupportsPlaylists = item.SupportsAddingToPlaylist; - if (fields.Contains(ItemFields.People)) { AttachPeople(dto, item); @@ -750,7 +748,7 @@ namespace MediaBrowser.Server.Implementations.Dto dto.AspectRatio = hasAspectRatio.AspectRatio; } - if (fields.Contains(ItemFields.ProductionLocations)) + if (fields.Contains(ItemFields.Metascore)) { var hasMetascore = item as IHasMetascore; if (hasMetascore != null) @@ -1132,15 +1130,22 @@ namespace MediaBrowser.Server.Implementations.Dto dto.AbsoluteEpisodeNumber = episode.AbsoluteEpisodeNumber; } - dto.AirsAfterSeasonNumber = episode.AirsAfterSeasonNumber; - dto.AirsBeforeEpisodeNumber = episode.AirsBeforeEpisodeNumber; - dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber; + //if (fields.Contains(ItemFields.SpecialEpisodeNumbers)) + { + dto.AirsAfterSeasonNumber = episode.AirsAfterSeasonNumber; + dto.AirsBeforeEpisodeNumber = episode.AirsBeforeEpisodeNumber; + dto.AirsBeforeSeasonNumber = episode.AirsBeforeSeasonNumber; + } var episodeSeason = episode.Season; if (episodeSeason != null) { dto.SeasonId = episodeSeason.Id.ToString("N"); - dto.SeasonName = episodeSeason.Name; + + if (fields.Contains(ItemFields.SeasonName)) + { + dto.SeasonName = episodeSeason.Name; + } } if (fields.Contains(ItemFields.SeriesGenres)) @@ -1180,7 +1185,11 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.SeriesId = GetDtoId(series); dto.SeriesName = series.Name; - dto.AirTime = series.AirTime; + + if (fields.Contains(ItemFields.AirTime)) + { + dto.AirTime = series.AirTime; + } if (options.GetImageLimit(ImageType.Thumb) > 0) { diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index d4625d402..432ea1f69 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -4,11 +4,11 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.FileOrganization; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Resolvers; -using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.FileOrganization; using MediaBrowser.Model.Logging; +using MediaBrowser.Naming.Common; +using MediaBrowser.Naming.IO; using System; using System.Collections.Generic; using System.Globalization; @@ -16,8 +16,6 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Server.Implementations.Library; -using MediaBrowser.Server.Implementations.Library.Resolvers.TV; namespace MediaBrowser.Server.Implementations.FileOrganization { @@ -57,18 +55,23 @@ namespace MediaBrowser.Server.Implementations.FileOrganization FileSize = new FileInfo(path).Length }; - var seriesName = SeriesResolver.GetSeriesNameFromEpisodeFile(path); + var resolver = new Naming.TV.EpisodeResolver(new ExtendedNamingOptions(), new Naming.Logging.NullLogger()); + + var episodeInfo = resolver.Resolve(path, FileInfoType.File) ?? + new Naming.TV.EpisodeInfo(); + + var seriesName = episodeInfo.SeriesName; if (!string.IsNullOrEmpty(seriesName)) { - var season = SeriesResolver.GetSeasonNumberFromEpisodeFile(path); + var season = episodeInfo.SeasonNumber; result.ExtractedSeasonNumber = season; if (season.HasValue) { // Passing in true will include a few extra regex's - var episode = SeriesResolver.GetEpisodeNumberFromFile(path, true); + var episode = episodeInfo.EpisodeNumber; result.ExtractedEpisodeNumber = episode; @@ -76,7 +79,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { _logger.Debug("Extracted information from {0}. Series name {1}, Season {2}, Episode {3}", path, seriesName, season, episode); - var endingEpisodeNumber = SeriesResolver.GetEndingEpisodeNumberFromFile(path); + var endingEpisodeNumber = episodeInfo.EndingEpsiodeNumber; result.ExtractedEndingEpisodeNumber = endingEpisodeNumber; @@ -251,7 +254,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization var folder = Path.GetDirectoryName(targetPath); var targetFileNameWithoutExtension = _fileSystem.GetFileNameWithoutExtension(targetPath); - + try { var filesOfOtherExtensions = Directory.EnumerateFiles(folder, "*", SearchOption.TopDirectoryOnly) @@ -456,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; @@ -470,6 +473,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization { return false; } + catch (DirectoryNotFoundException) + { + return false; + } return false; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs index 56e2e5247..b754a943a 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -206,8 +206,8 @@ namespace MediaBrowser.Server.Implementations.HttpServer HostContext.Config.HandlerFactoryPath = ListenerRequest.GetHandlerPathIfAny(UrlPrefixes.First()); _listener = _supportsNativeWebSocket && NativeWebSocket.IsSupported - ? _listener = new HttpListenerServer(_logger, OnRequestReceived) - //? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) + //? _listener = new HttpListenerServer(_logger, OnRequestReceived) + ? _listener = new WebSocketSharpListener(_logger, OnRequestReceived) : _listener = new WebSocketSharpListener(_logger, OnRequestReceived); _listener.WebSocketHandler = WebSocketHandler; diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index 57d87749c..13563ce19 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -68,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security if (user != null) { - if (user.Configuration.IsDisabled) + if (user.Policy.IsDisabled) { throw new SecurityException("User account has been disabled.") { @@ -76,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security }; } - if (!user.Configuration.IsAdministrator && + if (!user.Policy.IsAdministrator && !authAttribtues.EscapeParentalControl && !user.IsParentalScheduleAllowed()) { @@ -135,7 +135,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security { if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Configuration.IsAdministrator) + if (user == null || !user.Policy.IsAdministrator) { throw new SecurityException("User does not have admin access.") { @@ -145,7 +145,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security } if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase)) { - if (user == null || !user.Configuration.EnableContentDeletion) + if (user == null || !user.Policy.EnableContentDeletion) { throw new SecurityException("User does not have delete access.") { diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 4cb39778c..66125784c 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -18,8 +18,8 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Naming.Audio; using MediaBrowser.Naming.Common; using MediaBrowser.Naming.IO; +using MediaBrowser.Naming.TV; using MediaBrowser.Naming.Video; -using MediaBrowser.Server.Implementations.Library.Resolvers.TV; using MediaBrowser.Server.Implementations.Library.Validators; using MediaBrowser.Server.Implementations.ScheduledTasks; using System; @@ -560,10 +560,9 @@ namespace MediaBrowser.Server.Implementations.Library } public BaseItem ResolvePath(FileSystemInfo fileInfo, - Folder parent = null, - string collectionType = null) + Folder parent = null) { - return ResolvePath(fileInfo, new DirectoryService(_logger), parent, collectionType); + return ResolvePath(fileInfo, new DirectoryService(_logger), parent); } private BaseItem ResolvePath(FileSystemInfo fileInfo, IDirectoryService directoryService, Folder parent = null, string collectionType = null) @@ -573,10 +572,17 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("fileInfo"); } + var fullPath = fileInfo.FullName; + + if (string.IsNullOrWhiteSpace(collectionType)) + { + collectionType = GetConfiguredContentType(fullPath); + } + var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, this, directoryService) { Parent = parent, - Path = fileInfo.FullName, + Path = fullPath, FileInfo = fileInfo, CollectionType = collectionType }; @@ -862,7 +868,7 @@ namespace MediaBrowser.Server.Implementations.Library var type = typeof(T); - if (type == typeof(Person) && ConfigurationManager.Configuration.EnablePeoplePrefixSubFolders) + if (type == typeof(Person)) { subFolderPrefix = validFilename.Substring(0, 1); } @@ -1546,12 +1552,48 @@ namespace MediaBrowser.Server.Implementations.Library return ItemRepository.RetrieveItem(id); } - /// <summary> - /// Finds the type of the collection. - /// </summary> - /// <param name="item">The item.</param> - /// <returns>System.String.</returns> - public string FindCollectionType(BaseItem item) + public string GetContentType(BaseItem item) + { + // Types cannot be overridden, so go from the top down until we find a configured content type + + var type = GetTopFolderContentType(item); + + if (!string.IsNullOrWhiteSpace(type)) + { + return type; + } + + type = GetInheritedContentType(item); + + if (!string.IsNullOrWhiteSpace(type)) + { + return type; + } + + return GetConfiguredContentType(item); + } + + public string GetInheritedContentType(BaseItem item) + { + return item.Parents + .Select(GetConfiguredContentType) + .LastOrDefault(i => !string.IsNullOrWhiteSpace(i)); + } + + private string GetConfiguredContentType(BaseItem item) + { + return GetConfiguredContentType(item.ContainingFolderPath); + } + + private string GetConfiguredContentType(string path) + { + var type = ConfigurationManager.Configuration.ContentTypes + .FirstOrDefault(i => string.Equals(i.Name, path, StringComparison.OrdinalIgnoreCase) || _fileSystem.ContainsSubPath(i.Name, path)); + + return type == null ? null : type.Value; + } + + private string GetTopFolderContentType(BaseItem item) { while (!(item.Parent is AggregateFolder) && item.Parent != null) { @@ -1563,14 +1605,11 @@ namespace MediaBrowser.Server.Implementations.Library return null; } - var collectionTypes = GetUserRootFolder().Children + return GetUserRootFolder().Children .OfType<ICollectionFolder>() - .Where(i => !string.IsNullOrEmpty(i.CollectionType) && (string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path))) + .Where(i => string.Equals(i.Path, item.Path, StringComparison.OrdinalIgnoreCase) || i.PhysicalLocations.Contains(item.Path)) .Select(i => i.CollectionType) - .Distinct() - .ToList(); - - return collectionTypes.Count == 1 ? collectionTypes[0] : null; + .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i)); } public async Task<UserView> GetNamedView(string name, @@ -1708,22 +1747,127 @@ namespace MediaBrowser.Server.Implementations.Library public int? GetSeasonNumberFromPath(string path) { - return SeriesResolver.GetSeasonNumberFromPath(path, CollectionType.TvShows); + return new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(path, true).SeasonNumber; } - public int? GetSeasonNumberFromEpisodeFile(string path) + public bool FillMissingEpisodeNumbersFromPath(Episode episode) { - return SeriesResolver.GetSeasonNumberFromEpisodeFile(path); - } + var resolver = new EpisodeResolver(new ExtendedNamingOptions(), + new Naming.Logging.NullLogger()); - public int? GetEndingEpisodeNumberFromFile(string path) - { - return SeriesResolver.GetEndingEpisodeNumberFromFile(path); - } + var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ? + FileInfoType.Directory : + FileInfoType.File; - public int? GetEpisodeNumberFromFile(string path, bool considerSeasonless) - { - return SeriesResolver.GetEpisodeNumberFromFile(path, considerSeasonless); + var locationType = episode.LocationType; + + var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ? + resolver.Resolve(episode.Path, fileType) : + new Naming.TV.EpisodeInfo(); + + if (episodeInfo == null) + { + episodeInfo = new Naming.TV.EpisodeInfo(); + } + + var changed = false; + + if (episodeInfo.IsByDate) + { + if (episode.IndexNumber.HasValue) + { + episode.IndexNumber = null; + changed = true; + } + + if (episode.IndexNumberEnd.HasValue) + { + episode.IndexNumberEnd = null; + changed = true; + } + + 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) + { + var season = episode.Season; + + if (season != null) + { + 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.IndexNumberEnd.HasValue) + { + 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; + } + } + } + + return changed; } public ItemLookupInfo ParseName(string name) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs index f32ed2b20..05ff270fc 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs @@ -37,7 +37,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio /// <value>The priority.</value> 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; + } } /// <summary> @@ -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<MusicAlbum>()) return null; - // Optimization - if (args.HasParent<BoxSet>() || args.HasParent<Series>() || args.HasParent<Season>()) - { - return null; - } - var collectionType = args.GetCollectionType(); - var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, - StringComparison.OrdinalIgnoreCase); + var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not music, don't allow it. if (!isMusicMediaFolder) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index 71b6c0843..edbc87415 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -34,7 +34,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Audio /// <value>The priority.</value> 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; + } } /// <summary> @@ -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<BoxSet>() || args.HasParent<Series>() || args.HasParent<Season>()) - { - return null; - } - var collectionType = args.GetCollectionType(); - var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, - StringComparison.OrdinalIgnoreCase); + var isMusicMediaFolder = string.Equals(collectionType, CollectionType.Music, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not music, it can't be a series if (!isMusicMediaFolder) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs index 166465f72..34237622d 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/FolderResolver.cs @@ -1,10 +1,6 @@ -using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; -using System; -using System.IO; -using System.Linq; namespace MediaBrowser.Server.Implementations.Library.Resolvers { @@ -13,13 +9,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers /// </summary> public class FolderResolver : FolderResolver<Folder> { - private readonly IFileSystem _fileSystem; - - public FolderResolver(IFileSystem fileSystem) - { - _fileSystem = fileSystem; - } - /// <summary> /// Gets the priority. /// </summary> @@ -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(); - } } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs index 276b99d3a..01dc4db8a 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs @@ -79,11 +79,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return ResolveVideos<Video>(parent, files, directoryService, collectionType); } - return ResolveVideos<Movie>(parent, files, directoryService, collectionType); + return ResolveVideos<Video>(parent, files, directoryService, collectionType); } - if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || - string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { return ResolveVideos<Movie>(parent, files, directoryService, collectionType); } @@ -117,7 +116,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies FullName = i.FullName, Type = FileInfoType.File - }).ToList()).ToList(); + }).ToList(), false).ToList(); var result = new MultiItemResolverResult { @@ -168,12 +167,12 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies { if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType, false); + return FindMovie<MusicVideo>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); } if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase)) { - return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType, false); + return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); } if (string.IsNullOrEmpty(collectionType)) @@ -184,17 +183,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies return FindMovie<Video>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); } - // Since the looping is expensive, this is an optimization to help us avoid it - if (args.ContainsMetaFileByName("series.xml")) - { - return null; - } - return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); } - if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || - string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { return FindMovie<Movie>(args.Path, args.Parent, args.FileSystemChildren.ToList(), args.DirectoryService, collectionType); } @@ -216,8 +208,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies } // To find a movie file, the collection type must be movies or boxsets - else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase) || - string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase)) { item = ResolveVideo<Movie>(args, true); } @@ -228,7 +219,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies } else if (string.IsNullOrEmpty(collectionType)) { - item = ResolveVideo<Movie>(args, false); + item = ResolveVideo<Video>(args, false); } if (item != null) @@ -277,9 +268,8 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies /// <param name="fileSystemEntries">The file system entries.</param> /// <param name="directoryService">The directory service.</param> /// <param name="collectionType">Type of the collection.</param> - /// <param name="supportMultiVersion">if set to <c>true</c> [support multi version].</param> /// <returns>Movie.</returns> - private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType, bool supportMultiVersion = true) + private T FindMovie<T>(string path, Folder parent, List<FileSystemInfo> fileSystemEntries, IDirectoryService directoryService, string collectionType) where T : Video, new() { var multiDiscFolders = new List<FileSystemInfo>(); @@ -328,8 +318,11 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies var result = ResolveVideos<T>(parent, fileSystemEntries, directoryService, collectionType); + var supportsMultiVersion = !string.Equals(collectionType, CollectionType.HomeVideos) && + !string.Equals(collectionType, CollectionType.MusicVideos); + // Test for multi-editions - if (result.Items.Count > 1 && supportMultiVersion) + if (result.Items.Count > 1 && supportsMultiVersion) { var filenamePrefix = Path.GetFileName(path); @@ -474,7 +467,6 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.Movies CollectionType.Movies, CollectionType.HomeVideos, CollectionType.MusicVideos, - CollectionType.BoxSets, CollectionType.Movies }; diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs index 2fcfd7086..acae5b801 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/PhotoAlbumResolver.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; using System.IO; @@ -17,7 +18,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers protected override PhotoAlbum Resolve(ItemResolveArgs args) { // Must be an image file within a photo collection - if (!args.IsRoot && args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) + if (args.IsDirectory && string.Equals(args.GetCollectionType(), CollectionType.Photos, StringComparison.OrdinalIgnoreCase)) { if (HasPhotos(args)) { @@ -35,5 +36,14 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers { return args.FileSystemChildren.Any(i => ((i.Attributes & FileAttributes.Directory) != FileAttributes.Directory) && PhotoResolver.IsImageFile(i.FullName)); } + + public override ResolverPriority Priority + { + get + { + // Behind special folder resolver + return ResolverPriority.Second; + } + } } } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs new file mode 100644 index 000000000..0a41a6c04 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs @@ -0,0 +1,79 @@ +using MediaBrowser.Common.IO; +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 +{ + class SpecialFolderResolver : FolderResolver<Folder> + { + private readonly IFileSystem _fileSystem; + + public SpecialFolderResolver(IFileSystem fileSystem) + { + _fileSystem = fileSystem; + } + + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + public override ResolverPriority Priority + { + get { return ResolverPriority.First; } + } + + /// <summary> + /// Resolves the specified args. + /// </summary> + /// <param name="args">The args.</param> + /// <returns>Folder.</returns> + protected override Folder Resolve(ItemResolveArgs args) + { + 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 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/TV/EpisodeResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs index 057425ca9..1a873f01e 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs @@ -37,23 +37,10 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV } // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something - if (season != null || parent is Series || parent.Parents.OfType<Series>().Any()) + if (season != null || args.HasParent<Series>()) { var episode = ResolveVideo<Episode>(args, false); - if (episode != null) - { - if (season != null) - { - episode.ParentIndexNumber = season.IndexNumber; - } - - if (episode.ParentIndexNumber == null) - { - episode.ParentIndexNumber = SeriesResolver.GetSeasonNumberFromEpisodeFile(args.Path); - } - } - return episode; } diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs index 058fb1489..80477e567 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs @@ -1,7 +1,8 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Entities; +using MediaBrowser.Naming.Common; +using MediaBrowser.Naming.TV; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { @@ -35,7 +36,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { var season = new Season { - IndexNumber = SeriesResolver.GetSeasonNumberFromPath(args.Path, CollectionType.TvShows) + IndexNumber = new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(args.Path, true).SeasonNumber }; if (season.IndexNumber.HasValue && season.IndexNumber.Value == 0) diff --git a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs index 72c0bae53..00bed4086 100644 --- a/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs +++ b/MediaBrowser.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.IO; -using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; @@ -9,10 +8,10 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; -using System.Globalization; using System.IO; -using System.Linq; -using System.Text.RegularExpressions; +using MediaBrowser.Naming.Common; +using MediaBrowser.Naming.IO; +using MediaBrowser.Naming.TV; namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { @@ -54,26 +53,22 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if (args.IsDirectory) { // Avoid expensive tests against VF's and all their children by not allowing this - if (args.Parent == null || args.Parent.IsRoot) - { - return null; - } - - // Optimization to avoid running these tests against Seasons - if (args.HasParent<Series>() || args.HasParent<Season>() || args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>()) + if (args.Parent.IsRoot) { return null; } var collectionType = args.GetCollectionType(); - var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, - StringComparison.OrdinalIgnoreCase); + var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); // If there's a collection type and it's not tv, it can't be a series - if (!string.IsNullOrEmpty(collectionType) && - !isTvShowsFolder && - !string.Equals(collectionType, CollectionType.BoxSets, StringComparison.OrdinalIgnoreCase)) + if (!isTvShowsFolder) + { + return null; + } + + if (args.HasParent<Series>() || args.HasParent<Season>()) { return null; } @@ -123,7 +118,7 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) { - if (IsSeasonFolder(child.FullName, collectionType, directoryService, fileSystem)) + if (IsSeasonFolder(child.FullName, collectionType)) { //logger.Debug("{0} is a series because of season folder {1}.", path, child.FullName); return true; @@ -137,7 +132,17 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV { var isTvShowsFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); - if (GetEpisodeNumberFromFile(fullName, isTvShowsFolder).HasValue) + // We can fast track this for known tv folders + if (isTvShowsFolder) + { + return true; + } + + var resolver = new Naming.TV.EpisodeResolver(new ExtendedNamingOptions(), new Naming.Logging.NullLogger()); + + var episodeInfo = resolver.Resolve(fullName, FileInfoType.File, isTvShowsFolder, false); + + if (episodeInfo != null && (episodeInfo.EpisodeNumber.HasValue || episodeInfo.IsByDate)) { return true; } @@ -172,351 +177,13 @@ namespace MediaBrowser.Server.Implementations.Library.Resolvers.TV /// </summary> /// <param name="path">The path.</param> /// <param name="collectionType">Type of the collection.</param> - /// <param name="directoryService">The directory service.</param> - /// <param name="fileSystem">The file system.</param> /// <returns><c>true</c> if [is season folder] [the specified path]; otherwise, <c>false</c>.</returns> - private static bool IsSeasonFolder(string path, string collectionType, IDirectoryService directoryService, IFileSystem fileSystem) - { - var seasonNumber = GetSeasonNumberFromPath(path, collectionType); - var hasSeasonNumber = seasonNumber != null; - - if (!hasSeasonNumber) - { - return false; - } - - //// It's a season folder if it's named as such and does not contain any audio files, apart from theme.mp3 - //foreach (var fileSystemInfo in directoryService.GetFileSystemEntries(path)) - //{ - // var attributes = fileSystemInfo.Attributes; - - // if ((attributes & FileAttributes.Hidden) == FileAttributes.Hidden) - // { - // continue; - // } - - // // Can't enforce this because files saved by Bitcasa are always marked System - // //if ((attributes & FileAttributes.System) == FileAttributes.System) - // //{ - // // continue; - // //} - - // if ((attributes & FileAttributes.Directory) == FileAttributes.Directory) - // { - // //if (IsBadFolder(fileSystemInfo.Name)) - // //{ - // // return false; - // //} - // } - // else - // { - // if (EntityResolutionHelper.IsAudioFile(fileSystemInfo.FullName) && - // !string.Equals(fileSystem.GetFileNameWithoutExtension(fileSystemInfo), BaseItem.ThemeSongFilename)) - // { - // return false; - // } - // } - //} - - return true; - } - - /// <summary> - /// A season folder must contain one of these somewhere in the name - /// </summary> - private static readonly string[] SeasonFolderNames = - { - "season", - "sæson", - "temporada", - "saison", - "staffel", - "series", - "сезон" - }; - - /// <summary> - /// Used to detect paths that represent episodes, need to make sure they don't also - /// match movie titles like "2001 A Space..." - /// Currently we limit the numbers here to 2 digits to try and avoid this - /// </summary> - private static readonly Regex[] EpisodeExpressions = - { - new Regex( - @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS](?<seasonnumber>\d{1,4})[x,X]?[eE](?<epnumber>\d{1,3})[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})[^\\\/]*$", - RegexOptions.Compiled) - }; - private static readonly Regex[] MultipleEpisodeExpressions = - { - new Regex( - @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[eExX](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)[sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3})(-[xE]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )\d{1,4}[xX][eE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>((?![sS]?\d{1,4}[xX]\d{1,3})[^\\\/])*)?([sS]?(?<seasonnumber>\d{1,4})[xX](?<epnumber>\d{1,3}))(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})((-| - )?[xXeE](?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled), - new Regex( - @".*(\\|\/)(?<seriesname>[^\\\/]*)[sS](?<seasonnumber>\d{1,4})[xX\.]?[eE](?<epnumber>\d{1,3})(-[xX]?[eE]?(?<endingepnumber>\d{1,3}))+[^\\\/]*$", - RegexOptions.Compiled) - }; - - /// <summary> - /// To avoid the following matching movies they are only valid when contained in a folder which has been matched as a being season, or the media type is TV series - /// </summary> - private static readonly Regex[] EpisodeExpressionsWithoutSeason = - { - new Regex( - @".*[\\\/](?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.\w+$", - RegexOptions.Compiled), - // "01.avi" - new Regex( - @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\s?-\s?[^\\\/]*$", - RegexOptions.Compiled), - // "01 - blah.avi", "01-blah.avi" - new Regex( - @".*(\\|\/)(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*\.[^\\\/]+$", - RegexOptions.Compiled), - // "01.blah.avi" - new Regex( - @".*[\\\/][^\\\/]* - (?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$", - RegexOptions.Compiled), - // "blah - 01.avi", "blah 2 - 01.avi", "blah - 01 blah.avi", "blah 2 - 01 blah", "blah - 01 - blah.avi", "blah 2 - 01 - blah" - }; - - public static int? GetSeasonNumberFromPath(string path) - { - return GetSeasonNumberFromPath(path, CollectionType.TvShows); - } - - /// <summary> - /// Gets the season number from path. - /// </summary> - /// <param name="path">The path.</param> - /// <param name="collectionType">Type of the collection.</param> - /// <returns>System.Nullable{System.Int32}.</returns> - public static int? GetSeasonNumberFromPath(string path, string collectionType) - { - var filename = Path.GetFileName(path); - - if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(filename, "specials", StringComparison.OrdinalIgnoreCase)) - { - return 0; - } - } - - int val; - if (int.TryParse(filename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) - { - return val; - } - - if (filename.StartsWith("s", StringComparison.OrdinalIgnoreCase)) - { - var testFilename = filename.Substring(1); - - if (int.TryParse(testFilename, NumberStyles.Integer, CultureInfo.InvariantCulture, out val)) - { - return val; - } - } - - // Look for one of the season folder names - foreach (var name in SeasonFolderNames) - { - var index = filename.IndexOf(name, StringComparison.OrdinalIgnoreCase); - - if (index != -1) - { - return GetSeasonNumberFromPathSubstring(filename.Substring(index + name.Length)); - } - } - - return null; - } - - /// <summary> - /// Extracts the season number from the second half of the Season folder name (everything after "Season", or "Staffel") - /// </summary> - /// <param name="path">The path.</param> - /// <returns>System.Nullable{System.Int32}.</returns> - private static int? GetSeasonNumberFromPathSubstring(string path) + private static bool IsSeasonFolder(string path, string collectionType) { - var numericStart = -1; - var length = 0; + var isTvFolder = string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase); + var seasonNumber = new SeasonPathParser(new ExtendedNamingOptions(), new RegexProvider()).Parse(path, isTvFolder).SeasonNumber; - // Find out where the numbers start, and then keep going until they end - for (var i = 0; i < path.Length; i++) - { - if (char.IsNumber(path, i)) - { - if (numericStart == -1) - { - numericStart = i; - } - length++; - } - else if (numericStart != -1) - { - break; - } - } - - if (numericStart == -1) - { - return null; - } - - return int.Parse(path.Substring(numericStart, length), CultureInfo.InvariantCulture); - } - - /// <summary> - /// Episodes the number from file. - /// </summary> - /// <param name="fullPath">The full path.</param> - /// <param name="considerSeasonlessNames">if set to <c>true</c> [is in season].</param> - /// <returns>System.String.</returns> - public static int? GetEpisodeNumberFromFile(string fullPath, bool considerSeasonlessNames) - { - string fl = fullPath.ToLower(); - foreach (var r in EpisodeExpressions) - { - Match m = r.Match(fl); - if (m.Success) - return ParseEpisodeNumber(m.Groups["epnumber"].Value); - } - if (considerSeasonlessNames) - { - var match = EpisodeExpressionsWithoutSeason.Select(r => r.Match(fl)) - .FirstOrDefault(m => m.Success); - - if (match != null) - { - return ParseEpisodeNumber(match.Groups["epnumber"].Value); - } - } - - return null; - } - - public static int? GetEndingEpisodeNumberFromFile(string fullPath) - { - var fl = fullPath.ToLower(); - foreach (var r in MultipleEpisodeExpressions) - { - var m = r.Match(fl); - if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value)) - return ParseEpisodeNumber(m.Groups["endingepnumber"].Value); - } - foreach (var r in EpisodeExpressionsWithoutSeason) - { - var m = r.Match(fl); - if (m.Success && !string.IsNullOrEmpty(m.Groups["endingepnumber"].Value)) - return ParseEpisodeNumber(m.Groups["endingepnumber"].Value); - } - return null; - } - - /// <summary> - /// Seasons the number from episode file. - /// </summary> - /// <param name="fullPath">The full path.</param> - /// <returns>System.String.</returns> - public static int? GetSeasonNumberFromEpisodeFile(string fullPath) - { - string fl = fullPath.ToLower(); - foreach (var r in EpisodeExpressions) - { - Match m = r.Match(fl); - if (m.Success) - { - Group g = m.Groups["seasonnumber"]; - if (g != null) - { - var val = g.Value; - - if (!string.IsNullOrWhiteSpace(val)) - { - int num; - - if (int.TryParse(val, NumberStyles.Integer, UsCulture, out num)) - { - return num; - } - } - } - return null; - } - } - return null; - } - - public static string GetSeriesNameFromEpisodeFile(string fullPath) - { - var fl = fullPath.ToLower(); - foreach (var r in EpisodeExpressions) - { - var m = r.Match(fl); - if (m.Success) - { - var g = m.Groups["seriesname"]; - if (g != null) - { - var val = g.Value; - - if (!string.IsNullOrWhiteSpace(val)) - { - return val; - } - } - return null; - } - } - return null; - } - - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private static int? ParseEpisodeNumber(string val) - { - int num; - - if (!string.IsNullOrEmpty(val) && int.TryParse(val, NumberStyles.Integer, UsCulture, out num)) - { - return num; - } - - return null; + return seasonNumber.HasValue; } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index bd845ef4a..071031b25 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -1,5 +1,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; @@ -105,7 +106,7 @@ namespace MediaBrowser.Server.Implementations.Library if (query.IncludeMedia) { // Add search hints based on item name - hints.AddRange(items.Where(i => !string.IsNullOrWhiteSpace(i.Name)).Select(item => + hints.AddRange(items.Where(i => !string.IsNullOrWhiteSpace(i.Name) && IncludeInSearch(i)).Select(item => { var index = GetIndex(item.Name, searchTerm, terms); @@ -289,6 +290,20 @@ namespace MediaBrowser.Server.Implementations.Library return Task.FromResult(returnValue); } + private bool IncludeInSearch(BaseItem item) + { + var episode = item as Episode; + + if (episode != null) + { + if (episode.IsVirtualUnaired || episode.IsMissingEpisode) + { + return false; + } + } + return true; + } + /// <summary> /// Gets the index. /// </summary> diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index 791cae553..1a45d35a0 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -1,5 +1,4 @@ -using System.Collections.Concurrent; -using MediaBrowser.Common.Events; +using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Net; using MediaBrowser.Controller; @@ -63,6 +62,7 @@ namespace MediaBrowser.Server.Implementations.Library public event EventHandler<GenericEventArgs<User>> UserPasswordChanged; private readonly IXmlSerializer _xmlSerializer; + private readonly IJsonSerializer _jsonSerializer; private readonly INetworkManager _networkManager; @@ -71,13 +71,7 @@ namespace MediaBrowser.Server.Implementations.Library private readonly Func<IConnectManager> _connectFactory; private readonly IServerApplicationHost _appHost; - /// <summary> - /// Initializes a new instance of the <see cref="UserManager" /> class. - /// </summary> - /// <param name="logger">The logger.</param> - /// <param name="configurationManager">The configuration manager.</param> - /// <param name="userRepository">The user repository.</param> - public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost) + public UserManager(ILogger logger, IServerConfigurationManager configurationManager, IUserRepository userRepository, IXmlSerializer xmlSerializer, INetworkManager networkManager, Func<IImageProcessor> imageProcessorFactory, Func<IDtoService> dtoServiceFactory, Func<IConnectManager> connectFactory, IServerApplicationHost appHost, IJsonSerializer jsonSerializer) { _logger = logger; UserRepository = userRepository; @@ -87,6 +81,7 @@ namespace MediaBrowser.Server.Implementations.Library _dtoServiceFactory = dtoServiceFactory; _connectFactory = connectFactory; _appHost = appHost; + _jsonSerializer = jsonSerializer; ConfigurationManager = configurationManager; Users = new List<User>(); @@ -164,6 +159,11 @@ namespace MediaBrowser.Server.Implementations.Library public async Task Initialize() { Users = await LoadUsers().ConfigureAwait(false); + + foreach (var user in Users.ToList()) + { + await DoPolicyMigration(user).ConfigureAwait(false); + } } public Task<bool> AuthenticateUser(string username, string passwordSha1, string remoteEndPoint) @@ -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<bool> AuthenticateUser(string username, string passwordSha1, string passwordMd5, string remoteEndPoint) { if (string.IsNullOrWhiteSpace(username)) @@ -178,14 +210,15 @@ 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) { throw new SecurityException("Invalid username or password entered."); } - if (user.Configuration.IsDisabled) + if (user.Policy.IsDisabled) { throw new SecurityException(string.Format("The {0} account is currently disabled. Please consult with your administrator.", user.Name)); } @@ -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); @@ -283,14 +302,42 @@ namespace MediaBrowser.Server.Implementations.Library users.Add(user); - user.Configuration.IsAdministrator = true; - user.Configuration.EnableRemoteControlOfOtherUsers = true; - UpdateConfiguration(user, user.Configuration); + user.Policy.IsAdministrator = true; + user.Policy.EnableRemoteControlOfOtherUsers = true; + await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); } return users; } + private async Task DoPolicyMigration(User user) + { + if (!user.Configuration.HasMigratedToPolicy) + { + user.Policy.AccessSchedules = user.Configuration.AccessSchedules; + user.Policy.BlockedChannels = user.Configuration.BlockedChannels; + user.Policy.BlockedMediaFolders = user.Configuration.BlockedMediaFolders; + user.Policy.BlockedTags = user.Configuration.BlockedTags; + user.Policy.BlockUnratedItems = user.Configuration.BlockUnratedItems; + user.Policy.EnableContentDeletion = user.Configuration.EnableContentDeletion; + user.Policy.EnableLiveTvAccess = user.Configuration.EnableLiveTvAccess; + user.Policy.EnableLiveTvManagement = user.Configuration.EnableLiveTvManagement; + user.Policy.EnableMediaPlayback = user.Configuration.EnableMediaPlayback; + user.Policy.EnableRemoteControlOfOtherUsers = user.Configuration.EnableRemoteControlOfOtherUsers; + user.Policy.EnableSharedDeviceControl = user.Configuration.EnableSharedDeviceControl; + user.Policy.EnableUserPreferenceAccess = user.Configuration.EnableUserPreferenceAccess; + user.Policy.IsAdministrator = user.Configuration.IsAdministrator; + user.Policy.IsDisabled = user.Configuration.IsDisabled; + user.Policy.IsHidden = user.Configuration.IsHidden; + user.Policy.MaxParentalRating = user.Configuration.MaxParentalRating; + + await UpdateUserPolicy(user.Id.ToString("N"), user.Policy); + + user.Configuration.HasMigratedToPolicy = true; + await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); + } + } + public UserDto GetUserDto(User user, string remoteEndPoint = null) { if (user == null) @@ -449,6 +496,11 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentNullException("name"); } + if (!IsValidUsername(name)) + { + 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))) { throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name)); @@ -509,7 +561,7 @@ namespace MediaBrowser.Server.Implementations.Library throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one user in the system.", user.Name)); } - if (user.Configuration.IsAdministrator && allUsers.Count(i => i.Configuration.IsAdministrator) == 1) + if (user.Policy.IsAdministrator && allUsers.Count(i => i.Policy.IsAdministrator) == 1) { throw new ArgumentException(string.Format("The user '{0}' cannot be deleted because there must be at least one admin user in the system.", user.Name)); } @@ -518,17 +570,17 @@ namespace MediaBrowser.Server.Implementations.Library try { - await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); + var configPath = GetConfigurationFilePath(user); - var path = user.ConfigurationFilePath; + await UserRepository.DeleteUser(user, CancellationToken.None).ConfigureAwait(false); try { - File.Delete(path); + File.Delete(configPath); } catch (IOException ex) { - _logger.ErrorException("Error deleting file {0}", ex, path); + _logger.ErrorException("Error deleting file {0}", ex, configPath); } DeleteUserPolicy(user); @@ -613,15 +665,6 @@ namespace MediaBrowser.Server.Implementations.Library }; } - public void UpdateConfiguration(User user, UserConfiguration newConfiguration) - { - var xmlPath = user.ConfigurationFilePath; - Directory.CreateDirectory(Path.GetDirectoryName(xmlPath)); - _xmlSerializer.SerializeToFile(newConfiguration, xmlPath); - - EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger); - } - private string PasswordResetFile { get { return Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "passwordreset.txt"); } @@ -689,7 +732,7 @@ namespace MediaBrowser.Server.Implementations.Library string pinFile = null; DateTime? expirationDate = null; - if (user != null && !user.Configuration.IsAdministrator) + if (user != null && !user.Policy.IsAdministrator) { action = ForgotPasswordAction.ContactAdmin; } @@ -784,28 +827,65 @@ namespace MediaBrowser.Server.Implementations.Library return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path); } } + catch (DirectoryNotFoundException) + { + return GetDefaultPolicy(user); + } + catch (FileNotFoundException) + { + return GetDefaultPolicy(user); + } catch (Exception ex) { _logger.ErrorException("Error reading policy file: {0}", ex, path); - return new UserPolicy - { - EnableSync = !user.ConnectLinkType.HasValue || user.ConnectLinkType.Value != UserLinkType.Guest - }; + return GetDefaultPolicy(user); } } + private UserPolicy GetDefaultPolicy(User user) + { + return new UserPolicy + { + EnableSync = true + }; + } + private readonly object _policySyncLock = new object(); - public async Task UpdateUserPolicy(string userId, UserPolicy userPolicy) + public Task UpdateUserPolicy(string userId, UserPolicy userPolicy) { var user = GetUserById(userId); + return UpdateUserPolicy(user, userPolicy, true); + } + + private async Task UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent) + { + var updateConfig = user.Policy.IsAdministrator != userPolicy.IsAdministrator || + user.Policy.EnableLiveTvManagement != userPolicy.EnableLiveTvManagement || + user.Policy.EnableLiveTvAccess != userPolicy.EnableLiveTvAccess || + user.Policy.EnableMediaPlayback != userPolicy.EnableMediaPlayback || + user.Policy.EnableContentDeletion != userPolicy.EnableContentDeletion; + var path = GetPolifyFilePath(user); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + lock (_policySyncLock) { _xmlSerializer.SerializeToFile(userPolicy, path); user.Policy = userPolicy; } + + if (updateConfig) + { + user.Configuration.IsAdministrator = user.Policy.IsAdministrator; + user.Configuration.EnableLiveTvManagement = user.Policy.EnableLiveTvManagement; + user.Configuration.EnableLiveTvAccess = user.Policy.EnableLiveTvAccess; + user.Configuration.EnableMediaPlayback = user.Policy.EnableMediaPlayback; + user.Configuration.EnableContentDeletion = user.Policy.EnableContentDeletion; + + await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); + } } private void DeleteUserPolicy(User user) @@ -833,5 +913,69 @@ namespace MediaBrowser.Server.Implementations.Library { return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml"); } + + private string GetConfigurationFilePath(User user) + { + return Path.Combine(user.ConfigurationDirectoryPath, "config.xml"); + } + + public UserConfiguration GetUserConfiguration(User user) + { + var path = GetConfigurationFilePath(user); + + try + { + lock (_configSyncLock) + { + return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path); + } + } + catch (DirectoryNotFoundException) + { + return new UserConfiguration(); + } + catch (FileNotFoundException) + { + return new UserConfiguration(); + } + catch (Exception ex) + { + _logger.ErrorException("Error reading policy file: {0}", ex, path); + + return new UserConfiguration(); + } + } + + private readonly object _configSyncLock = new object(); + public Task UpdateConfiguration(string userId, UserConfiguration config) + { + var user = GetUserById(userId); + return UpdateConfiguration(user, config, true); + } + + private async Task UpdateConfiguration(User user, UserConfiguration config, bool fireEvent) + { + var path = GetConfigurationFilePath(user); + + // The xml serializer will output differently if the type is not exact + if (config.GetType() != typeof (UserConfiguration)) + { + var json = _jsonSerializer.SerializeToString(config); + config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json); + } + + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + lock (_configSyncLock) + { + _xmlSerializer.SerializeToFile(config, path); + user.Configuration = config; + } + + if (fireEvent) + { + EventHelper.FireEventIfNotNull(UserConfigurationUpdated, this, new GenericEventArgs<User> { Argument = user }, _logger); + } + } } } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 83fe992b6..e67bf10f7 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -1846,7 +1846,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv private bool IsLiveTvEnabled(User user) { - return user.Configuration.EnableLiveTvAccess && ActiveService != null; + return user.Policy.EnableLiveTvAccess && ActiveService != null; } public IEnumerable<User> GetEnabledUsers() @@ -1854,7 +1854,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv var service = ActiveService; return _userManager.Users - .Where(i => i.Configuration.EnableLiveTvAccess && service != null); + .Where(i => i.Policy.EnableLiveTvAccess && service != null); } /// <summary> diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json index 81f648728..4246a1ac0 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ar.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "\u0627\u0644\u062d\u0644\u0642\u0627\u062a", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json index d0dfd608b..1617535c2 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ca.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json index 9f2da7797..673dc37cd 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/cs.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Filmy", "TabSeries": "S\u00e9rie", "TabEpisodes": "Epizody", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json index 4bd7d3103..2adcf1f35 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/da.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Film", "TabSeries": "Serier", "TabEpisodes": "Episoder", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json index d8a8036b0..3ea1bcbf1 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/de.json @@ -396,6 +396,7 @@ "LabelYear": "Jahr:", "LabelDateOfBirth": "Geburtsatum:", "LabelBirthYear": "Geburtsjahr:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Todesdatum:", "HeaderRemoveMediaLocation": "Entferne Medienquelle", "MessageConfirmRemoveMediaLocation": "Bist du dir sicher diese Medienquelle entfernen zu wollen?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Medienquellen", "LabelFolderTypeValue": "Verzeichnistyp: {0}", "LabelPathSubstitutionHelp": "Optional: Die Pfadersetzung kann Serverpfade zu Netzwerkfreigaben umleiten, die von Endger\u00e4ten f\u00fcr die direkte Wiedergabe genutzt werden k\u00f6nnen.", - "FolderTypeMixed": "Filme & Serien gemischt", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Filme", "FolderTypeMusic": "Musik", "FolderTypeAdultVideos": "Videos f\u00fcr Erwachsene", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Heimvideos", "FolderTypeGames": "Spiele", "FolderTypeBooks": "B\u00fccher", - "FolderTypeTvShows": "TV Serien", + "FolderTypeTvShows": "TV", "TabMovies": "Filme", "TabSeries": "Serie", "TabEpisodes": "Episoden", @@ -642,7 +643,12 @@ "OptionLow": "Niedrig", "HeaderSettings": "Einstellungen", "OptionAutomaticallySyncNewContent": "Synchronisiere neue Inhalte automatisch", - "OptionAutomaticallySyncNewContentHelp": "Neu hinzugef\u00fcgte Inhalte zu diesen Verzeichnissen werden automatisch zum Ger\u00e4t synchronisiert.", + "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.", "OptionSyncUnwatchedVideosOnly": "Synchronisiere nur ungesehene Videos.", - "OptionSyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden synchronisiert. Videos werden entfernt sobald diese auf dem Ger\u00e4t angeschaut wurden." + "OptionSyncUnwatchedVideosOnlyHelp": "Nur ungesehene Video werden synchronisiert. Videos werden entfernt sobald diese auf dem Ger\u00e4t angeschaut wurden.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json index 20c9de1ef..cba4166bc 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/el.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "\u0395\u03c0\u03b5\u03b9\u03c3\u03cc\u03b4\u03b9\u03b1", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json index fec45e70c..04a669fe2 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_GB.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json index 369299be0..7a0b1e46a 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/en_US.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json index d2957340c..8e8904ff5 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Pel\u00edculas", "TabSeries": "Series", "TabEpisodes": "Episodios", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json index fda5b65b3..972fd07b6 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/es_MX.json @@ -396,6 +396,7 @@ "LabelYear": "A\u00f1o:", "LabelDateOfBirth": "Fecha de nacimiento:", "LabelBirthYear": "A\u00f1o de nacimiento:", + "LabelBirthDate": "Fecha de Nacimiento:", "LabelDeathDate": "Fecha de defunci\u00f3n:", "HeaderRemoveMediaLocation": "Eliminar Ubicaci\u00f3n de Medios", "MessageConfirmRemoveMediaLocation": "\u00bfEst\u00e1 seguro de querer eliminar esta ubicaci\u00f3n?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Ubicaciones de Medios", "LabelFolderTypeValue": "Tipo de carpeta: {0}", "LabelPathSubstitutionHelp": "Opcional: La sustituci\u00f3n de trayectoras puede mapear trayectorias del servidor a recursos de red comaprtidos que los clientes pueden acceder para reproducir de manera directa.", - "FolderTypeMixed": "Pel\u00edculas y TV mezclados", + "FolderTypeMixed": "Videos mezclados", "FolderTypeMovies": "Pel\u00edculas", "FolderTypeMusic": "M\u00fasica", "FolderTypeAdultVideos": "Videos para adultos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Videos caseros", "FolderTypeGames": "Juegos", "FolderTypeBooks": "Libros", - "FolderTypeTvShows": "Programas de TV", + "FolderTypeTvShows": "TV", "TabMovies": "Pel\u00edculas", "TabSeries": "Series", "TabEpisodes": "Episodios", @@ -642,7 +643,12 @@ "OptionLow": "Baja", "HeaderSettings": "Configuraci\u00f3n", "OptionAutomaticallySyncNewContent": "Sincronizar autom\u00e1ticamente nuevos contenidos", - "OptionAutomaticallySyncNewContentHelp": "Los contenidos nuevos que sean agregados a estas carpetas ser\u00e1n sincronizados autom\u00e1ticamente con el dispositivo.", + "OptionAutomaticallySyncNewContentHelp": "Los contenidos nuevos agregados a esta categor\u00eda ser\u00e1n sincronizados autom\u00e1ticamente con el dispositivo.", "OptionSyncUnwatchedVideosOnly": "Sincronizar \u00fanicamente videos no vistos", - "OptionSyncUnwatchedVideosOnlyHelp": "Solamente los videos a\u00fan no vistos ser\u00e1n sincronizados, se eliminar\u00e1n los videos del dispositivo conforme \u00e9stos sean vistos." + "OptionSyncUnwatchedVideosOnlyHelp": "Solamente los videos a\u00fan no vistos ser\u00e1n sincronizados, se eliminar\u00e1n los videos del dispositivo conforme \u00e9stos sean vistos.", + "LabelItemLimit": "L\u00edmite de \u00cdtems:", + "LabelItemLimitHelp": "Opcional. Establece un l\u00edmite en el n\u00famero de \u00edtems que ser\u00e1n sincronizados.", + "MessageBookPluginRequired": "Requiere instalaci\u00f3n del complemento Bookshelf", + "MessageGamePluginRequired": "Requiere instalaci\u00f3n del complemento de GameBrowser", + "MessageMixedContentHelp": "El contenido ser\u00e1 desplegado como una estructura de carpetas simples" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json index e9c6263e2..a5c584321 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fi.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json index d3c95bfa4..7a2f4ae78 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/fr.json @@ -396,6 +396,7 @@ "LabelYear": "Ann\u00e9e :", "LabelDateOfBirth": "Date de naissance :", "LabelBirthYear": "Ann\u00e9e de naissance :", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Date de d\u00e9c\u00e8s :", "HeaderRemoveMediaLocation": "Supprimer l'emplacement m\u00e9dia", "MessageConfirmRemoveMediaLocation": "Etes vous sur de vouloir supprimer cet emplacement?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Emplacement des M\u00e9dias", "LabelFolderTypeValue": "Type de r\u00e9pertoire: {0}", "LabelPathSubstitutionHelp": "Optionnel: La substitution de chemin peut rediriger les r\u00e9pertoires serveurs vers des partages r\u00e9seau afin que le client acc\u00e8de directement \u00e0 la lecture.", - "FolderTypeMixed": "Film et TV m\u00e9lang\u00e9s", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Films", "FolderTypeMusic": "Musique", "FolderTypeAdultVideos": "Vid\u00e9os Adultes", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Vid\u00e9os personnelles", "FolderTypeGames": "Jeux", "FolderTypeBooks": "Livres", - "FolderTypeTvShows": "S\u00e9ries TV", + "FolderTypeTvShows": "TV", "TabMovies": "Films", "TabSeries": "S\u00e9ries", "TabEpisodes": "\u00c9pisodes", @@ -642,7 +643,12 @@ "OptionLow": "Basse", "HeaderSettings": "Param\u00e8tres", "OptionAutomaticallySyncNewContent": "Synchroniser automatiquement le nouveau contenu", - "OptionAutomaticallySyncNewContentHelp": "Le nouveau contenu ajout\u00e9 \u00e0 ces r\u00e9pertoires sera automatiquement synchronis\u00e9 \u00e0 votre p\u00e9riph\u00e9rique.", + "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.", "OptionSyncUnwatchedVideosOnly": "Synchroniser seulement les vid\u00e9os non lus.", - "OptionSyncUnwatchedVideosOnlyHelp": "Seulement les vid\u00e9os non lus seront synchronis\u00e9es et seront supprim\u00e9es du p\u00e9riph\u00e9rique au fur et \u00e0 mesure qu'elles sont lus." + "OptionSyncUnwatchedVideosOnlyHelp": "Seulement les vid\u00e9os non lus seront synchronis\u00e9es et seront supprim\u00e9es du p\u00e9riph\u00e9rique au fur et \u00e0 mesure qu'elles sont lus.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json index 7d268200b..8aa10f97a 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/he.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "\u05e1\u05e8\u05d8\u05d9\u05dd", "TabSeries": "\u05e1\u05d3\u05e8\u05d5\u05ea", "TabEpisodes": "\u05e4\u05e8\u05e7\u05d9\u05dd", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json index ef186d800..724db6574 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/hr.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Filmovi", "TabSeries": "Series", "TabEpisodes": "Epizode", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json index 8e324b335..99349b8a8 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/it.json @@ -396,6 +396,7 @@ "LabelYear": "Anno:", "LabelDateOfBirth": "Data nascita:", "LabelBirthYear": "Anno nascita:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Anno morte:", "HeaderRemoveMediaLocation": "Rimuovi percorso media", "MessageConfirmRemoveMediaLocation": "Sei sicuro di voler rimuovere questa posizione?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Posizioni Media", "LabelFolderTypeValue": "Tipo cartella: {0}", "LabelPathSubstitutionHelp": "Opzionale: cambio Path pu\u00f2 mappare i percorsi del server a condivisioni di rete che i clienti possono accedere per la riproduzione diretta.", - "FolderTypeMixed": "Misto Film & Tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Film", "FolderTypeMusic": "Musica", "FolderTypeAdultVideos": "Video per adulti", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Video personali", "FolderTypeGames": "Giochi", "FolderTypeBooks": "Libri", - "FolderTypeTvShows": "Serie TV", + "FolderTypeTvShows": "TV", "TabMovies": "Film", "TabSeries": "Serie TV", "TabEpisodes": "Episodi", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/javascript.json index b90370246..b5c1ea0d3 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", @@ -402,6 +403,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -418,7 +420,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 movies & tv", + "FolderTypeMixed": "Mixed content", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -427,7 +429,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -650,9 +652,12 @@ "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:", - "LabelItemLimitHelp": "Optional. Set a limit to the number of items that will be synced." + "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" } diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json index 85cd90d11..1eb8a277a 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/kk.json @@ -396,6 +396,7 @@ "LabelYear": "\u0416\u044b\u043b\u044b:", "LabelDateOfBirth": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d\u0456:", "LabelBirthYear": "\u0422\u0443\u0493\u0430\u043d \u0436\u044b\u043b\u044b:", + "LabelBirthDate": "\u0422\u0443\u0493\u0430\u043d \u043a\u04af\u043d\u0456:", "LabelDeathDate": "\u04e8\u043b\u0433\u0435\u043d \u043a\u04af\u043d\u0456:", "HeaderRemoveMediaLocation": "\u0422\u0430\u0441\u0443\u0448\u044b\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u044b\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u0443", "MessageConfirmRemoveMediaLocation": "\u0428\u044b\u043d\u044b\u043c\u0435\u043d \u043e\u0441\u044b \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u0434\u044b \u0430\u043b\u0430\u0441\u0442\u0430\u0443 \u049b\u0430\u0436\u0435\u0442 \u043f\u0435?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "\u0422\u0430\u0441\u0443\u0448\u044b \u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440 \u043e\u0440\u043d\u0430\u043b\u0430\u0441\u0443\u043b\u0430\u0440\u044b", "LabelFolderTypeValue": "\u049a\u0430\u043b\u0442\u0430 \u0442\u04af\u0440\u0456: {0}", "LabelPathSubstitutionHelp": "\u049a\u0430\u043b\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430: \u0416\u043e\u043b \u0430\u043b\u043c\u0430\u0441\u0442\u044b\u0440\u0443 \u0430\u0440\u049b\u044b\u043b\u044b \u0441\u0435\u0440\u0432\u0435\u0440\u0434\u0435\u0433\u0456 \u0436\u043e\u043b\u0434\u0430\u0440\u0434\u044b \u0442\u0456\u043a\u0435\u043b\u0435\u0439 \u043e\u0439\u043d\u0430\u0442\u0443 \u04af\u0448\u0456\u043d \u043a\u043b\u0438\u0435\u043d\u0442\u0442\u0435\u0440 \u049b\u0430\u0442\u044b\u043d\u0430\u0441\u0430 \u0430\u043b\u0430\u0442\u044b\u043d \u0436\u0435\u043b\u0456\u043b\u0456\u043a \u049b\u043e\u0440 \u043a\u04e9\u0437\u0434\u0435\u0440\u0456\u043c\u0435\u043d \u0431\u0430\u0439\u043b\u0430\u043d\u044b\u0441\u0442\u044b\u0440\u0443\u044b \u043c\u04af\u043c\u043a\u0456\u043d.", - "FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 (\u043a\u0438\u043d\u043e \u0436\u04d9\u043d\u0435 \u0442\u0434)", + "FolderTypeMixed": "\u0410\u0440\u0430\u043b\u0430\u0441 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440", "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440", "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430", "FolderTypeAdultVideos": "\u0415\u0440\u0435\u0441\u0435\u043a\u0442\u0456\u043a \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "\u04ae\u0439 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0456", "FolderTypeGames": "\u041e\u0439\u044b\u043d\u0434\u0430\u0440", "FolderTypeBooks": "\u041a\u0456\u0442\u0430\u043f\u0442\u0430\u0440", - "FolderTypeTvShows": "\u0422\u0414 \u043a\u04e9\u0440\u0441\u0435\u0442\u0456\u043c\u0434\u0435\u0440\u0456", + "FolderTypeTvShows": "\u0422\u0414", "TabMovies": "\u0424\u0438\u043b\u044c\u043c\u0434\u0435\u0440", "TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b", "TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u0442\u0430\u0440", @@ -642,7 +643,12 @@ "OptionLow": "\u0422\u04e9\u043c\u0435\u043d", "HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043b\u0435\u0440", "OptionAutomaticallySyncNewContent": "\u0416\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d\u0434\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443", - "OptionAutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u049b\u0430\u043b\u0442\u0430\u043b\u0430\u0440\u0493\u0430 \u04af\u0441\u0442\u0435\u043b\u0456\u043d\u0433\u0435\u043d \u0436\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0434\u044b.", + "OptionAutomaticallySyncNewContentHelp": "\u041e\u0441\u044b \u0441\u0430\u043d\u0430\u0442\u049b\u0430 \u049b\u043e\u0441\u044b\u043b\u0493\u0430\u043d \u0436\u0430\u04a3\u0430 \u043c\u0430\u0437\u043c\u04b1\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0442\u044b \u0442\u04af\u0440\u0434\u0435 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u044b\u043d\u0430\u0434\u044b.", "OptionSyncUnwatchedVideosOnly": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u043a\u04e9\u0440\u0456\u043b\u043c\u0435\u0433\u0435\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440\u0434\u0456 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443", - "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u0440\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0434\u044b, \u0436\u04d9\u043d\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b." + "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u0435\u043a \u049b\u0430\u043d\u0430 \u049b\u0430\u0440\u0430\u0440\u043c\u0430\u0493\u0430\u043d \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u044b\u043d\u0430\u0434\u044b, \u0436\u04d9\u043d\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u0440 \u049b\u0430\u0440\u0430\u043b\u0493\u0430\u043d\u043d\u0430\u043d \u043a\u0435\u0439\u0456\u043d \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u0434\u0430\u043d \u0430\u043b\u0430\u0441\u0442\u0430\u043b\u0430\u0434\u044b.", + "LabelItemLimit": "\u042d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440 \u0448\u0435\u0433\u0456:", + "LabelItemLimitHelp": "\u049a\u0430\u043b\u0430\u0443 \u0431\u043e\u0439\u044b\u043d\u0448\u0430: \u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u043b\u0430\u0442\u044b\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0442\u0435\u0440 \u0441\u0430\u043d\u044b \u04af\u0448\u0456\u043d \u0448\u0435\u043a\u0442\u0456 \u043e\u0440\u043d\u0430\u0442\u044b\u04a3\u044b\u0437.", + "MessageBookPluginRequired": "Bookshelf \u043f\u043b\u0430\u0433\u0438\u043d\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443\u0434\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456", + "MessageGamePluginRequired": "GameBrowser \u043f\u043b\u0430\u0433\u0438\u043d\u0456\u043d \u043e\u0440\u043d\u0430\u0442\u0443\u0434\u044b \u049b\u0430\u0436\u0435\u0442 \u0435\u0442\u0435\u0434\u0456", + "MessageMixedContentHelp": "\u041c\u0430\u0437\u043c\u04b1\u043d \u0436\u0430\u043b\u043f\u044b \u049b\u0430\u043b\u0442\u0430 \u049b\u04b1\u0440\u044b\u043b\u044b\u043c\u044b \u0440\u0435\u0442\u0456\u043d\u0434\u0435 \u0431\u0435\u043d\u0435\u043b\u0435\u043d\u0435\u0434\u0456" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json index 89aefed9d..a231f4aa6 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ms.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Movies", "TabSeries": "Series", "TabEpisodes": "Episodes", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json index a5fd9bb9b..799a81081 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nb.json @@ -396,6 +396,7 @@ "LabelYear": "\u00c5r:", "LabelDateOfBirth": "F\u00f8dseldato:", "LabelBirthYear": "F\u00f8dsels\u00e5r:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "D\u00f8ds dato:", "HeaderRemoveMediaLocation": "Fjern Media Mappe", "MessageConfirmRemoveMediaLocation": "Er du sikker p\u00e5 at du vil slette dette stedet??", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Media Steder", "LabelFolderTypeValue": "Mappe type: {0}", "LabelPathSubstitutionHelp": "Valgfritt: Sti erstatter kan koble server stier til nettverkressurser som klienter har tilgang til for direkte avspilling.", - "FolderTypeMixed": "Mikset filmer & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Filmer", "FolderTypeMusic": "Musikk", "FolderTypeAdultVideos": "Voksen videoer", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Hjemme videoer", "FolderTypeGames": "Spill", "FolderTypeBooks": "B\u00f8ker", - "FolderTypeTvShows": "TV program", + "FolderTypeTvShows": "TV", "TabMovies": "Filmer", "TabSeries": "Serier", "TabEpisodes": "Episoder", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json index 53445c370..cf87f7590 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/nl.json @@ -396,6 +396,7 @@ "LabelYear": "Jaar:", "LabelDateOfBirth": "Geboortedatum:", "LabelBirthYear": "Geboorte jaar:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Overlijdens datum:", "HeaderRemoveMediaLocation": "Verwijder media locatie", "MessageConfirmRemoveMediaLocation": "Weet je zeker dat je deze locatie wilt verwijderen?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Media Locaties", "LabelFolderTypeValue": "Map type: {0}", "LabelPathSubstitutionHelp": "Optioneel: Pad vervanging kan server paden naar netwerk locaties verwijzen zodat clients direct kunnen afspelen.", - "FolderTypeMixed": "Gemixte films en TV", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Films", "FolderTypeMusic": "Muziek", "FolderTypeAdultVideos": "Adult video's", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Thuis video's", "FolderTypeGames": "Games", "FolderTypeBooks": "Boeken", - "FolderTypeTvShows": "TV programma's", + "FolderTypeTvShows": "TV", "TabMovies": "Films", "TabSeries": "Serie", "TabEpisodes": "Afleveringen", @@ -642,7 +643,12 @@ "OptionLow": "Laag", "HeaderSettings": "Instellingen", "OptionAutomaticallySyncNewContent": "Nieuwe inhoud automatisch synchroniseren", - "OptionAutomaticallySyncNewContentHelp": "Nieuwe inhoud in deze mappen zal automatisch gesynchroniseerd worden met het apparaat.", + "OptionAutomaticallySyncNewContentHelp": "New content added to this category will be automatically synced to the device.", "OptionSyncUnwatchedVideosOnly": "Synchroniseer alleen ongeziene video's", - "OptionSyncUnwatchedVideosOnlyHelp": "Alleen ongeziene video's zulle gesynchroniseerd worden en van het apparaat verwijderd worden als ze gezien zijn." + "OptionSyncUnwatchedVideosOnlyHelp": "Alleen ongeziene video's zulle gesynchroniseerd worden en van het apparaat verwijderd worden als ze gezien zijn.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json index 98a8b5947..d25d5bbbb 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pl.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Filmy", "TabSeries": "Series", "TabEpisodes": "Odcinki", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json index 492b402ca..cab1d3620 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_BR.json @@ -396,6 +396,7 @@ "LabelYear": "Ano:", "LabelDateOfBirth": "Data de nascimento:", "LabelBirthYear": "Ano de nascimento:", + "LabelBirthDate": "Data de nascimento:", "LabelDeathDate": "Data da morte:", "HeaderRemoveMediaLocation": "Remover Localiza\u00e7\u00e3o da M\u00eddia", "MessageConfirmRemoveMediaLocation": "Deseja realmente remover esta localiza\u00e7\u00e3o?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Localiza\u00e7\u00f5es de M\u00eddia", "LabelFolderTypeValue": "Tipo de pasta: {0}", "LabelPathSubstitutionHelp": "Opcional: Substitui\u00e7\u00e3o de caminho pode mapear caminhos do servidor para compartilhamentos de rede de forma a que os clientes possam acessar para reprodu\u00e7\u00e3o direta.", - "FolderTypeMixed": "Filmes & tv misturados", + "FolderTypeMixed": "V\u00eddeos misturados", "FolderTypeMovies": "Filmes", "FolderTypeMusic": "M\u00fasica", "FolderTypeAdultVideos": "V\u00eddeos adultos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "V\u00eddeos caseiros", "FolderTypeGames": "Jogos", "FolderTypeBooks": "Livros", - "FolderTypeTvShows": "S\u00e9ries de TV", + "FolderTypeTvShows": "TV", "TabMovies": "Filmes", "TabSeries": "S\u00e9ries", "TabEpisodes": "Epis\u00f3dios", @@ -642,7 +643,12 @@ "OptionLow": "Baixa", "HeaderSettings": "Ajustes", "OptionAutomaticallySyncNewContent": "Sincronizar novo conte\u00fado automaticamente", - "OptionAutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a estas pastas ser\u00e1 automaticamente sincronizado com o dispositivo.", + "OptionAutomaticallySyncNewContentHelp": "Novo conte\u00fado adicionado a esta categoria ser\u00e1 automaticamente sincronizado com o dispositivo.", "OptionSyncUnwatchedVideosOnly": "Sincronizar apenas v\u00eddeos n\u00e3o assistidos", - "OptionSyncUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o sincronizados, e os v\u00eddeos ser\u00e3o removidos do dispositivo assim que forem assistidos." + "OptionSyncUnwatchedVideosOnlyHelp": "Apenas v\u00eddeos n\u00e3o assistidos ser\u00e3o sincronizados, e os v\u00eddeos ser\u00e3o removidos do dispositivo assim que forem assistidos.", + "LabelItemLimit": "Limite de itens:", + "LabelItemLimitHelp": "Opcional. Defina o n\u00famero limite de itens que ser\u00e3o sincronizados.", + "MessageBookPluginRequired": "Requer a instala\u00e7\u00e3o do plugin Bookshelf", + "MessageGamePluginRequired": "Requer a instala\u00e7\u00e3o do plugin GameBrowser", + "MessageMixedContentHelp": "O conte\u00fado ser\u00e1 exibido como uma estrutura de pasta simples" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json index 5007ae444..30ddec80c 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/pt_PT.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Filmes", "TabSeries": "S\u00e9ries", "TabEpisodes": "Epis\u00f3dios", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json index 15e489fb3..f91bc38d1 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/ru.json @@ -396,6 +396,7 @@ "LabelYear": "\u0413\u043e\u0434:", "LabelDateOfBirth": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", "LabelBirthYear": "\u0413\u043e\u0434 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", + "LabelBirthDate": "\u0414\u0430\u0442\u0430 \u0440\u043e\u0436\u0434\u0435\u043d\u0438\u044f:", "LabelDeathDate": "\u0414\u0430\u0442\u0430 \u0441\u043c\u0435\u0440\u0442\u0438:", "HeaderRemoveMediaLocation": "\u0418\u0437\u044a\u044f\u0442\u0438\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445", "MessageConfirmRemoveMediaLocation": "\u0412\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u0438\u0437\u044a\u044f\u0442\u044c \u044d\u0442\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445", "LabelFolderTypeValue": "\u0422\u0438\u043f \u043f\u0430\u043f\u043a\u0438: {0}", "LabelPathSubstitutionHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e: \u041f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0443\u0442\u0435\u0439 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u044b\u0445 \u043f\u0443\u0442\u0435\u0439 \u0441\u043e \u0441\u0435\u0442\u0435\u0432\u044b\u043c\u0438 \u043e\u0431\u0449\u0438\u043c\u0438 \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0434\u043b\u044f \u043f\u0440\u044f\u043c\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f.", - "FolderTypeMixed": "\u0421\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0439 (\u0444\u0438\u043b\u044c\u043c\u044b \u0438 \u0422\u0412)", + "FolderTypeMixed": "\u0421\u043c\u0435\u0448\u0430\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b", "FolderTypeMovies": "\u0424\u0438\u043b\u044c\u043c\u044b", "FolderTypeMusic": "\u041c\u0443\u0437\u044b\u043a\u0430", "FolderTypeAdultVideos": "\u0412\u0437\u0440\u043e\u0441\u043b\u044b\u0435 \u0432\u0438\u0434\u0435\u043e", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "\u0414\u043e\u043c\u0430\u0448\u043d\u0438\u0435 \u0432\u0438\u0434\u0435\u043e", "FolderTypeGames": "\u0418\u0433\u0440\u044b", "FolderTypeBooks": "\u041a\u043d\u0438\u0433\u0438", - "FolderTypeTvShows": "\u0422\u0412 \u0446\u0438\u043a\u043b\u044b", + "FolderTypeTvShows": "\u0422\u0412", "TabMovies": "\u0424\u0438\u043b\u044c\u043c\u044b", "TabSeries": "\u0421\u0435\u0440\u0438\u0430\u043b\u044b", "TabEpisodes": "\u042d\u043f\u0438\u0437\u043e\u0434\u044b", @@ -641,8 +642,13 @@ "OptionMedium": "\u0421\u0440\u0435\u0434\u043d\u0435\u0435", "OptionLow": "\u041d\u0438\u0437\u043a\u043e\u0435", "HeaderSettings": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b", - "OptionAutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", - "OptionAutomaticallySyncNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0430\u043f\u043a\u0438, \u0431\u0443\u0434\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.", - "OptionSyncUnwatchedVideosOnly": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b.", - "OptionSyncUnwatchedVideosOnlyHelp": "\u0422\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u0430 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u044b\u043c\u0430\u0442\u044c\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430." + "OptionAutomaticallySyncNewContent": "\u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440-\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435", + "OptionAutomaticallySyncNewContentHelp": "\u041d\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u0434\u0430\u043d\u043d\u0443\u044e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044e, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c.", + "OptionSyncUnwatchedVideosOnly": "\u0421\u0438\u043d\u0445\u0440-\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b.", + "OptionSyncUnwatchedVideosOnlyHelp": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0435 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b, \u0430 \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b \u0438\u0437\u044b\u043c\u0430\u044e\u0442\u0441\u044f \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043f\u043e\u0441\u043b\u0435 \u0438\u0445 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430.", + "LabelItemLimit": "\u041f\u0440\u0435\u0434\u0435\u043b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:", + "LabelItemLimitHelp": "\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e. \u0417\u0430\u0434\u0430\u0442\u044c \u043f\u0440\u0435\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.", + "MessageBookPluginRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 Bookshelf", + "MessageGamePluginRequired": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 GameBrowser", + "MessageMixedContentHelp": "\u0421\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0430\u043f\u043e\u043a" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json index a0b86f576..f4ff295fd 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/sv.json @@ -396,6 +396,7 @@ "LabelYear": "\u00c5r:", "LabelDateOfBirth": "F\u00f6delsedatum:", "LabelBirthYear": "F\u00f6delse\u00e5r:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "D\u00f6d:", "HeaderRemoveMediaLocation": "Ta bort mediaplats", "MessageConfirmRemoveMediaLocation": "\u00c4r du s\u00e4ker p\u00e5 att du vill ta bort den h\u00e4r platsen?", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "Lagringsplatser f\u00f6r media", "LabelFolderTypeValue": "Typ av mapp: {0}", "LabelPathSubstitutionHelp": "Tillval: S\u00f6kv\u00e4gsutbyte betyder att en plats p\u00e5 servern kopplas till en lokal fils\u00f6kv\u00e4g p\u00e5 en klient. P\u00e5 s\u00e5 s\u00e4tt f\u00e5r klienten direkt tillg\u00e5ng till material p\u00e5 servern och kan spela upp det direkt via n\u00e4tverket.", - "FolderTypeMixed": "Blandat film & TV", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Filmer", "FolderTypeMusic": "Musik", "FolderTypeAdultVideos": "Inneh\u00e5ll f\u00f6r vuxna", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Hemvideor", "FolderTypeGames": "Spel", "FolderTypeBooks": "B\u00f6cker", - "FolderTypeTvShows": "TV-serier", + "FolderTypeTvShows": "TV", "TabMovies": "Filmer", "TabSeries": "Serie", "TabEpisodes": "Avsnitt", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json index e8ecf0de0..496a96c90 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/tr.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "Filmler", "TabSeries": "Seriler", "TabEpisodes": "B\u00f6l\u00fcmler", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json index e94761156..c8297ccd8 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/vi.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "C\u00e1c phim", "TabSeries": "Series", "TabEpisodes": "C\u00e1c t\u1eadp phim", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json index ad9a6c6a5..c4492bca1 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_CN.json @@ -396,6 +396,7 @@ "LabelYear": "\u5e74\uff1a", "LabelDateOfBirth": "\u51fa\u751f\u65e5\u671f\uff1a", "LabelBirthYear": "\u51fa\u751f\u5e74\u4efd\uff1a", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "\u53bb\u4e16\u65e5\u671f\uff1a", "HeaderRemoveMediaLocation": "\u79fb\u9664\u5a92\u4f53\u4f4d\u7f6e", "MessageConfirmRemoveMediaLocation": "\u4f60\u786e\u5b9a\u8981\u79fb\u9664\u6b64\u4f4d\u7f6e\uff1f", @@ -411,7 +412,7 @@ "HeaderMediaLocations": "\u5a92\u4f53\u4f4d\u7f6e", "LabelFolderTypeValue": "\u6587\u4ef6\u5939\u7c7b\u578b\uff1a {0}", "LabelPathSubstitutionHelp": "\u53ef\u9009\uff1a\u66ff\u4ee3\u8def\u5f84\u80fd\u628a\u670d\u52a1\u5668\u8def\u5f84\u6620\u5c04\u5230\u7f51\u7edc\u5171\u4eab\uff0c\u4ece\u800c\u4f7f\u5ba2\u6237\u7aef\u53ef\u4ee5\u76f4\u63a5\u64ad\u653e\u3002", - "FolderTypeMixed": "\u6df7\u5408\u7684\u7535\u5f71\u548c\u7535\u89c6", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "\u7535\u5f71", "FolderTypeMusic": "\u97f3\u4e50", "FolderTypeAdultVideos": "\u6210\u4eba\u89c6\u9891", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "\u5bb6\u5ead\u89c6\u9891", "FolderTypeGames": "\u6e38\u620f", "FolderTypeBooks": "\u4e66\u7c4d", - "FolderTypeTvShows": "\u7535\u89c6\u8282\u76ee", + "FolderTypeTvShows": "TV", "TabMovies": "\u7535\u5f71", "TabSeries": "\u7535\u89c6\u5267", "TabEpisodes": "\u5267\u96c6", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json index 706299704..c5d03dcfa 100644 --- a/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json +++ b/MediaBrowser.Server.Implementations/Localization/JavaScript/zh_TW.json @@ -396,6 +396,7 @@ "LabelYear": "Year:", "LabelDateOfBirth": "Date of birth:", "LabelBirthYear": "Birth year:", + "LabelBirthDate": "Birth date:", "LabelDeathDate": "Death date:", "HeaderRemoveMediaLocation": "Remove Media Location", "MessageConfirmRemoveMediaLocation": "Are you sure you wish to remove this location?", @@ -411,7 +412,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 movies & tv", + "FolderTypeMixed": "Mixed videos", "FolderTypeMovies": "Movies", "FolderTypeMusic": "Music", "FolderTypeAdultVideos": "Adult videos", @@ -420,7 +421,7 @@ "FolderTypeHomeVideos": "Home videos", "FolderTypeGames": "Games", "FolderTypeBooks": "Books", - "FolderTypeTvShows": "TV shows", + "FolderTypeTvShows": "TV", "TabMovies": "\u96fb\u5f71", "TabSeries": "\u96fb\u8996\u5287", "TabEpisodes": "\u55ae\u5143", @@ -642,7 +643,12 @@ "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." + "OptionSyncUnwatchedVideosOnlyHelp": "Only unwatched videos will be synced, and videos will be removed from the device as they are watched.", + "LabelItemLimit": "Item limit:", + "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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ar.json b/MediaBrowser.Server.Implementations/Localization/Server/ar.json index 97302a0ff..a1c357fa1 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/ar.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/ar.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u0627\u0639\u062f\u0627\u062f \u0645\u0643\u062a\u0628\u0629 \u0627\u0644\u0648\u0633\u0627\u0626\u0637", "ButtonAddMediaFolder": "\u0627\u0636\u0627\u0641\u0629 \u0645\u062c\u0644\u062f \u0644\u0644\u0648\u0633\u0627\u0626\u0637", "LabelFolderType": "\u0646\u0648\u0639 \u0627\u0644\u0645\u062c\u0644\u062f:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "\u0627\u0644\u0631\u062c\u0648\u0639 \u0627\u0644\u0649 wiki \u0644\u0645\u0643\u062a\u0628\u0629 \u0627\u0644\u0648\u0633\u0627\u0626\u0637", "LabelCountry": "\u0627\u0644\u0628\u0644\u062f:", "LabelLanguage": "\u0627\u0644\u0644\u063a\u0629:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ca.json b/MediaBrowser.Server.Implementations/Localization/Server/ca.json index 655cabcaf..8f57abfa2 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/ca.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/ca.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/cs.json b/MediaBrowser.Server.Implementations/Localization/Server/cs.json index 74aa0cd37..3b16a4d59 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/cs.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/cs.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Nastaven\u00ed Va\u0161i knihovny m\u00e9di\u00ed", "ButtonAddMediaFolder": "P\u0159idat slo\u017eku m\u00e9di\u00ed", "LabelFolderType": "Typ slo\u017eky:", - "MediaFolderHelpPluginRequired": "* Vy\u017eaduje pou\u017eit\u00ed pluginu, nap\u0159. GameBrowser nebo MB Bookshelf", "ReferToMediaLibraryWiki": "Pod\u00edvejte se na wiki knihovny m\u00e9di\u00ed.", "LabelCountry": "Zem\u011b:", "LabelLanguage": "Jazyk:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/da.json b/MediaBrowser.Server.Implementations/Localization/Server/da.json index db4c6d535..fe10e2d37 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/da.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/da.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Konfigurer dit medie bibliotek", "ButtonAddMediaFolder": "Tilf\u00f8j medie mappe", "LabelFolderType": "Mappe type:", - "MediaFolderHelpPluginRequired": "* Kr\u00e6ver brug af en tilf\u00f8jelse, fx GameBrowser eller MB Bookshelf.", "ReferToMediaLibraryWiki": "Der henvises til medie bibliotekets wiki.", "LabelCountry": "Land:", "LabelLanguage": "Sprog:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/de.json b/MediaBrowser.Server.Implementations/Localization/Server/de.json index c5e0715ff..295b95f4e 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/de.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/de.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Medienbibliothek einrichten", "ButtonAddMediaFolder": "Medienverzeichnis hinzuf\u00fcgen", "LabelFolderType": "Verzeichnistyp:", - "MediaFolderHelpPluginRequired": "* Ben\u00f6tigt ein Plugin, wie GameBrowser oder MB Bookshelf.", "ReferToMediaLibraryWiki": "Siehe die Medienbibliothek Wiki", "LabelCountry": "Land:", "LabelLanguage": "Sprache:", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "Begrenze auf ein eingebundenes Bild", "LabelEnableSingleImageInDidlLimitHelp": "Einige Ger\u00e4te zeigen m\u00f6glicherweise Darstellungsfehler wenn mehrere Bilder mit Didl eingebunden wurden.", "TabActivity": "Aktivit\u00e4t", - "TitleSync": "Synchronisation" + "TitleSync": "Synchronisation", + "OptionAllowSyncContent": "Allow syncing media to devices" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/el.json b/MediaBrowser.Server.Implementations/Localization/Server/el.json index 41239b912..e8083c945 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/el.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/el.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "\u03a0\u03c1\u03bf\u03c3\u03b8\u03ad\u03c3\u03c4\u03b5 \u03c4\u03bf \u03c6\u03ac\u03ba\u03b5\u03bb\u03bf \u03c4\u03bf\u03c5 Media", "LabelFolderType": "\u03a4\u03cd\u03c0\u03bf \u03c6\u03b1\u03ba\u03ad\u03bb\u03bf\u03c5 ", - "MediaFolderHelpPluginRequired": "\u0391\u03c0\u03b1\u03b9\u03c4\u03b5\u03af \u03c4\u03b7 \u03c7\u03c1\u03ae\u03c3\u03b7 \u03b5\u03bd\u03cc\u03c2 plugin.\u03c0.\u03c7. Gamebrowser \u03ae MB Bookshelf.", "ReferToMediaLibraryWiki": "\u0391\u03bd\u03b1\u03c4\u03c1\u03b5\u03be\u03c4\u03b5 \u03c3\u03c4\u03bf media \u03b2\u03b9\u03b2\u03bb\u03b9\u03bf\u03b8\u03ae\u03ba\u03b7 wiki", "LabelCountry": "T\u03b7 \u03c7\u03ce\u03c1\u03b1", "LabelLanguage": "\u03a4\u03b7 \u03b3\u03bb\u03ce\u03c3\u03c3\u03b1", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json index 9eeac0f85..6b3571d08 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/en_GB.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json index 9cb4fb6c5..3457f97c0 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/en_US.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/en_US.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es.json b/MediaBrowser.Server.Implementations/Localization/Server/es.json index a720a1510..007ff21f7 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/es.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/es.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configurar biblioteca de medios", "ButtonAddMediaFolder": "Agregar una carpeta de medios", "LabelFolderType": "Tipo de carpeta:", - "MediaFolderHelpPluginRequired": "* Requiere el uso de un plugin, por ejemplo GameBrowser o MB Bookshelf", "ReferToMediaLibraryWiki": "Consultar el wiki de la biblioteca de medios", "LabelCountry": "Pa\u00eds:", "LabelLanguage": "Idioma:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json index 7c532182b..8951e2fdf 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/es_MX.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configurar su biblioteca de medios", "ButtonAddMediaFolder": "Agregar carpeta de medios", "LabelFolderType": "Tipo de carpeta:", - "MediaFolderHelpPluginRequired": "* Requiere el uso de un complemento, p. ej. GameBrowser o MB Bookshelf.", "ReferToMediaLibraryWiki": "Consultar la wiki de la biblioteca de medios.", "LabelCountry": "Pa\u00eds:", "LabelLanguage": "Idioma:", @@ -232,10 +231,10 @@ "HeaderFeatureAccess": "Permisos de acceso", "OptionAllowMediaPlayback": "Permitir reproducci\u00f3n de medios", "OptionAllowBrowsingLiveTv": "Permitir acceder a TV en vivo", - "OptionAllowDeleteLibraryContent": "Allow deletion of library content", + "OptionAllowDeleteLibraryContent": "Permitir eliminar contenido de la biblioteca", "OptionAllowManageLiveTv": "Permitir administrar grabaciones de TV en vivo", - "OptionAllowRemoteControlOthers": "Allow remote control of other users", - "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices", + "OptionAllowRemoteControlOthers": "Permitir control remoto de otros usuarios", + "OptionAllowRemoteSharedDevices": "Permitir control remoto de dispositivos compartidos", "OptionAllowRemoteSharedDevicesHelp": "Los dispositivos dnla son considerados como compartidos hasta que alg\u00fan usuario comienza a controlarlo.", "HeaderRemoteControl": "Control Remoto", "OptionMissingTmdbId": "Falta Id de Tmdb", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "Limitar a una sola imagen incrustada.", "LabelEnableSingleImageInDidlLimitHelp": "Algunos dispositivos no renderisaran apropiadamente si hay m\u00faltiples im\u00e1genes incrustadas en el Didl", "TabActivity": "Actividad", - "TitleSync": "Sinc" + "TitleSync": "Sinc", + "OptionAllowSyncContent": "Permitir sincronizaci\u00f3n de medios con dispositivos" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fi.json b/MediaBrowser.Server.Implementations/Localization/Server/fi.json index c2c6c8612..f9d0f9a10 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/fi.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/fi.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Aseta sinun media kirjasto", "ButtonAddMediaFolder": "Lis\u00e4\u00e4 media kansio", "LabelFolderType": "Kansion tyyppi:", - "MediaFolderHelpPluginRequired": "* Vaatii lis\u00e4osan, kuten GameBrowser tai MB Bookshelf.", "ReferToMediaLibraryWiki": "Viittus media kirjaston wikiin.", "LabelCountry": "Maa:", "LabelLanguage": "Kieli:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/fr.json b/MediaBrowser.Server.Implementations/Localization/Server/fr.json index b3f6ead82..312b3c201 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/fr.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/fr.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configurer votre biblioth\u00e8que de m\u00e9dia", "ButtonAddMediaFolder": "Ajouter un r\u00e9pertoire de m\u00e9dia", "LabelFolderType": "Type de r\u00e9pertoire:", - "MediaFolderHelpPluginRequired": "* N\u00e9cessite l'utilisation d'un plugin, par exemple : \"GameBrowser\" ou \"MB BookShelf\".", "ReferToMediaLibraryWiki": "Se r\u00e9f\u00e9rer au wiki des biblioth\u00e8ques de m\u00e9dia", "LabelCountry": "Pays:", "LabelLanguage": "Langue:", @@ -232,10 +231,10 @@ "HeaderFeatureAccess": "Acc\u00e8s aux caract\u00e9ristiques", "OptionAllowMediaPlayback": "Autoriser la lecture du m\u00e9dia", "OptionAllowBrowsingLiveTv": "Autoriser la TV en direct", - "OptionAllowDeleteLibraryContent": "Allow deletion of library content", + "OptionAllowDeleteLibraryContent": "Autoriser la suppression de contenu dans la biblioth\u00e8que", "OptionAllowManageLiveTv": "Autoriser la gestion des enregistrements de la TV en direct", - "OptionAllowRemoteControlOthers": "Allow remote control of other users", - "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices", + "OptionAllowRemoteControlOthers": "Autoriser le contr\u00f4le \u00e0 distance d'autres utilisateurs", + "OptionAllowRemoteSharedDevices": "Autoriser le contr\u00f4le \u00e0 distance des disques partag\u00e9s", "OptionAllowRemoteSharedDevicesHelp": "Les p\u00e9riph\u00e9riques Dlna sont consid\u00e9r\u00e9s comme partag\u00e9s tant qu'un utilisateur ne commence pas \u00e0 le contr\u00f4ler.", "HeaderRemoteControl": "Contr\u00f4le \u00e0 distance", "OptionMissingTmdbId": "ID TMDb manquant", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "Limiter \u00e0 une seule image int\u00e9gr\u00e9e", "LabelEnableSingleImageInDidlLimitHelp": "Quelques p\u00e9riph\u00e9riques ne fourniront pas un rendu correct si plusieurs images sont int\u00e9gr\u00e9es dans Didl", "TabActivity": "Activit\u00e9", - "TitleSync": "Sync." + "TitleSync": "Sync.", + "OptionAllowSyncContent": "Allow syncing media to devices" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/he.json b/MediaBrowser.Server.Implementations/Localization/Server/he.json index cecde2022..e9dbb9c31 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/he.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/he.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u05d4\u05d2\u05d3\u05e8 \u05d0\u05ea \u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4 \u05e9\u05dc\u05da", "ButtonAddMediaFolder": "\u05d4\u05d5\u05e1\u05e3 \u05ea\u05d9\u05e7\u05d9\u05d9\u05ea \u05de\u05d3\u05d9\u05d4", "LabelFolderType": "\u05e1\u05d5\u05d2 \u05d4\u05ea\u05d9\u05e7\u05d9\u05d9\u05d4:", - "MediaFolderHelpPluginRequired": "* \u05de\u05e6\u05e8\u05d9\u05da \u05de\u05d4\u05de\u05e9\u05ea\u05de\u05e9 \u05ea\u05d5\u05e1\u05e3, \u05dc\u05d3\u05d5\u05d2\u05de\u05d0 GameBrowser \u05d0\u05d5 MB Bookshelf", "ReferToMediaLibraryWiki": "\u05e4\u05e0\u05d4 \u05dc\u05de\u05d9\u05d3\u05e2 \u05d0\u05d5\u05d3\u05d5\u05ea \u05e1\u05e4\u05e8\u05d9\u05d9\u05ea \u05d4\u05de\u05d3\u05d9\u05d4.", "LabelCountry": "\u05de\u05d3\u05d9\u05e0\u05d4:", "LabelLanguage": "\u05e9\u05e4\u05d4:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/hr.json b/MediaBrowser.Server.Implementations/Localization/Server/hr.json index f7589ff00..aee34ca29 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/hr.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/hr.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Postavi svoju medijsku biblioteku", "ButtonAddMediaFolder": "Dodaj mapu sa medijem", "LabelFolderType": "Tip mape:", - "MediaFolderHelpPluginRequired": "* Zahtjeva kori\u0161tenje dodatka, npr. GameBrowser ili MB Bookshelf.", "ReferToMediaLibraryWiki": "Informirajte se o medijskoj bibilioteci wiki", "LabelCountry": "Zemlja:", "LabelLanguage": "Jezik:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/it.json b/MediaBrowser.Server.Implementations/Localization/Server/it.json index 5daab33d8..316174a03 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/it.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/it.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configura la tua libreria", "ButtonAddMediaFolder": "Aggiungi cartella", "LabelFolderType": "Tipo cartella", - "MediaFolderHelpPluginRequired": "* Richiede l'uso di un plugin, ad esempio GameBrowser o MB Bookshelf.", "ReferToMediaLibraryWiki": "Fare riferimento alla wiki libreria multimediale.", "LabelCountry": "Nazione:", "LabelLanguage": "lingua:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/kk.json b/MediaBrowser.Server.Implementations/Localization/Server/kk.json index 2d9e4053d..65f2e19d2 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/kk.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/kk.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430\u043d\u044b \u043e\u0440\u043d\u0430\u0442\u0443 \u0436\u04d9\u043d\u0435 \u0442\u0435\u04a3\u0448\u0435\u0443", "ButtonAddMediaFolder": "\u0422\u0430\u0441\u0443\u0448\u044b \u049b\u0430\u043b\u0442\u0430\u0441\u044b\u043d \u04af\u0441\u0442\u0435\u0443", "LabelFolderType": "\u049a\u0430\u043b\u0442\u0430 \u0442\u04af\u0440\u0456:", - "MediaFolderHelpPluginRequired": "* \u041f\u043b\u0430\u0433\u0438\u043d\u0434\u0456 \u043f\u0430\u0439\u0434\u0430\u043b\u0430\u043d\u044b\u04a3\u044b\u0437, \u043c\u044b\u0441\u0430\u043b\u044b, GameBrowser, \u043d\u0435 MB Bookshelf.", "ReferToMediaLibraryWiki": "\u0422\u0430\u0441\u0443\u0448\u044b\u0445\u0430\u043d\u0430 \u0442\u0443\u0440\u0430\u043b\u044b \u0443\u0438\u043a\u0438 \u0456\u0448\u0456\u043d\u0435\u043d \u049b\u0430\u0440\u0430\u04a3\u044b\u0437.", "LabelCountry": "\u0415\u043b:", "LabelLanguage": "\u0422\u0456\u043b:", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "\u0416\u0430\u043b\u0493\u044b\u0437 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0433\u0435\u043d \u0441\u0443\u0440\u0435\u0442\u043a\u0435 \u0448\u0435\u043a\u0442\u0435\u0443", "LabelEnableSingleImageInDidlLimitHelp": "\u0415\u0433\u0435\u0440 \u0431\u0456\u0440\u043d\u0435\u0448\u0435 \u0441\u0443\u0440\u0435\u0442 Didl \u0456\u0448\u0456\u043d\u0435 \u043a\u0456\u0440\u0456\u0441\u0442\u0456\u0440\u0456\u043b\u0441\u0435, \u043a\u0435\u0439\u0431\u0456\u0440 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043b\u0430\u0440\u0434\u0430 \u0442\u0438\u0456\u0441\u0442\u0456 \u0442\u04af\u0440\u0434\u0435 \u0431\u0435\u0439\u043d\u0435\u043b\u0435\u043d\u0431\u0435\u0439\u0434\u0456.", "TabActivity": "\u04d8\u0440\u0435\u043a\u0435\u0442\u0442\u0435\u0440", - "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443" + "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443", + "OptionAllowSyncContent": "\u041c\u0435\u0434\u0438\u0430\u0434\u0435\u0440\u0435\u043a\u0442\u0435\u0440\u0434\u0456 \u049b\u04b1\u0440\u044b\u043b\u0493\u044b\u043c\u0435\u043d \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0434\u0430\u0443\u0493\u0430 \u0440\u04b1\u049b\u0441\u0430\u0442 \u0435\u0442\u0443" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ko.json b/MediaBrowser.Server.Implementations/Localization/Server/ko.json index 2a0bcc74f..f8d9ff218 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/ko.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/ko.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ms.json b/MediaBrowser.Server.Implementations/Localization/Server/ms.json index adbe36a92..af1a6eeb3 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/ms.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/ms.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Setup your media library", "ButtonAddMediaFolder": "Add media folder", "LabelFolderType": "Folder type:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nb.json b/MediaBrowser.Server.Implementations/Localization/Server/nb.json index a6a1fa3c4..b60c91829 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/nb.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/nb.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Konfigurer media-biblioteket", "ButtonAddMediaFolder": "Legg til media-mappe", "LabelFolderType": "Mappe typpe", - "MediaFolderHelpPluginRequired": "* Krever bruk av et programtillegg f.eks GameBrowser eller MB Bookshelf.", "ReferToMediaLibraryWiki": "Se i media-bibliotek wikien", "LabelCountry": "LAnd", "LabelLanguage": "Spr\u00e5k:", @@ -232,9 +231,9 @@ "HeaderFeatureAccess": "Funksjon Tilgang", "OptionAllowMediaPlayback": "Tillatt medieavspilling", "OptionAllowBrowsingLiveTv": "Tillat surfing av Live TV", - "OptionAllowDeleteLibraryContent": "Allow deletion of library content", + "OptionAllowDeleteLibraryContent": "Tillat sletting av bibliotek innhold", "OptionAllowManageLiveTv": "Tillat styring av Live TV opptak", - "OptionAllowRemoteControlOthers": "Allow remote control of other users", + "OptionAllowRemoteControlOthers": "Tillat fjernstyring av andre brukere", "OptionAllowRemoteSharedDevices": "Allow remote control of shared devices", "OptionAllowRemoteSharedDevicesHelp": "Dlna devices are considered shared until a user begins controlling it.", "HeaderRemoteControl": "Remote Control", @@ -459,7 +458,7 @@ "LinkApiDocumentation": "Api Dokumentasjon", "LabelFriendlyServerName": "Vennlig server navn:", "LabelFriendlyServerNameHelp": "Dette navnet vil bli brukt for \u00e5 identifisere denne serveren. Hvis feltet er tomt, vil maskinens navn bli brukt.", - "LabelPreferredDisplayLanguage": "Preferred display language:", + "LabelPreferredDisplayLanguage": "Foretrukket skjerm spr\u00e5k:", "LabelPreferredDisplayLanguageHelp": "Oversetting av Media Browser er ett p\u00e5g\u00e5ende prosjekt og er enda ikke fullstendig ferdig.", "LabelReadHowYouCanContribute": "Les mer om hvordan du kan bidra.", "HeaderNewCollection": "Ny Samling", @@ -1228,7 +1227,7 @@ "HeaderSignInWithConnect": "Sign in with Media Browser Connect", "HeaderGuests": "Gjester", "HeaderLocalUsers": "Lokale Brukere", - "HeaderPendingInvitations": "Pending Invitations", + "HeaderPendingInvitations": "Ventende invitasjoner", "TabParentalControl": "Foreldrekontroll", "HeaderAccessSchedule": "Access Schedule", "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/nl.json b/MediaBrowser.Server.Implementations/Localization/Server/nl.json index c4f65de2c..492ec7f8d 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/nl.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/nl.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Stel uw mediabibliotheek in", "ButtonAddMediaFolder": "Mediamap toevoegen", "LabelFolderType": "Maptype:", - "MediaFolderHelpPluginRequired": "* Hiervoor is het gebruik van een Plug-in vereist, bijvoorbeeld GameBrowser of MB Bookshelf.", "ReferToMediaLibraryWiki": "Raadpleeg de mediabibliotheek wiki.", "LabelCountry": "Land:", "LabelLanguage": "Taal:", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "Beperk tot \u00e9\u00e9n enkele ingesloten afbeelding", "LabelEnableSingleImageInDidlLimitHelp": "Sommige apparaten zullen niet goed weergeven als er meerdere afbeeldingen ingesloten zijn in Didl.", "TabActivity": "Activiteit", - "TitleSync": "Synchroniseer" + "TitleSync": "Synchroniseer", + "OptionAllowSyncContent": "Allow syncing media to devices" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pl.json b/MediaBrowser.Server.Implementations/Localization/Server/pl.json index a0d70f6c6..adf2df9a1 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/pl.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/pl.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Ustaw swoj\u0105 bibliotek\u0119", "ButtonAddMediaFolder": "Dodaj folder", "LabelFolderType": "Typ folderu:", - "MediaFolderHelpPluginRequired": "* Wymaga u\u017cycia wtyczki takiej jak GameBrowser lub MB Bookshelf.", "ReferToMediaLibraryWiki": "Odnie\u015b si\u0119 do wiki biblioteki.", "LabelCountry": "Kraj:", "LabelLanguage": "J\u0119zyk:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json index 134059faf..13b786371 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_BR.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configurar sua biblioteca de m\u00eddias", "ButtonAddMediaFolder": "Adicionar pasta de m\u00eddias", "LabelFolderType": "Tipo de pasta:", - "MediaFolderHelpPluginRequired": "* Requer o uso de um plugin, ex. GameBrowser ou MB Bookshelf.", "ReferToMediaLibraryWiki": "Consultar wiki da biblioteca de m\u00eddias", "LabelCountry": "Pa\u00eds:", "LabelLanguage": "Idioma:", @@ -1279,5 +1278,6 @@ "LabelEnableSingleImageInDidlLimit": "Limitar a uma imagem incorporada", "LabelEnableSingleImageInDidlLimitHelp": "Alguns dispositivos n\u00e3o interpretar\u00e3o apropriadamente se m\u00faltiplas imagens estiverem incorporadas dentro do Didl.", "TabActivity": "Atividade", - "TitleSync": "Sinc" + "TitleSync": "Sinc", + "OptionAllowSyncContent": "Permitir sincroniza\u00e7\u00e3o de m\u00eddia com os dispositivos" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json index 792a9eb0f..a3d0d9fc5 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/pt_PT.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Configurar biblioteca", "ButtonAddMediaFolder": "Adicionar pasta de media", "LabelFolderType": "Tipo de pasta", - "MediaFolderHelpPluginRequired": "* Requer o uso de uma extens\u00e3o, e.g. GameBrowser ou MB Bookshelf", "ReferToMediaLibraryWiki": "Consulte a wiki", "LabelCountry": "Pa\u00eds:", "LabelLanguage": "Idioma:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/ru.json b/MediaBrowser.Server.Implementations/Localization/Server/ru.json index e35d8a097..ccc506cc7 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/ru.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/ru.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438", "ButtonAddMediaFolder": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0435\u0434\u0438\u0430\u043f\u0430\u043f\u043a\u0443", "LabelFolderType": "\u0422\u0438\u043f \u043f\u0430\u043f\u043a\u0438:", - "MediaFolderHelpPluginRequired": "* \u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u043b\u0430\u0433\u0438\u043d, \u043d\u043f\u0440., GameBrowser \u0438\u043b\u0438 MB Bookshelf.", "ReferToMediaLibraryWiki": "\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0432\u0438\u043a\u0438 \u043f\u043e \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0435.", "LabelCountry": "\u0421\u0442\u0440\u0430\u043d\u0430:", "LabelLanguage": "\u042f\u0437\u044b\u043a:", @@ -225,17 +224,17 @@ "VisitMediaBrowserWebsiteLong": "\u041f\u043e\u0441\u0435\u0442\u0438\u0442\u0435 \u0441\u0430\u0439\u0442 Media Browser, \u0447\u0442\u043e\u0431\u044b \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u043c\u0438 \u043d\u043e\u0432\u043e\u0441\u0442\u044f\u043c\u0438 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043e\u0441\u0432\u0435\u0434\u043e\u043c\u043b\u0451\u043d\u043d\u043e\u0441\u0442\u044c \u043f\u043e \u0431\u043b\u043e\u0433\u0443 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.", "OptionHideUser": "\u0421\u043a\u0440\u044b\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441 \u044d\u043a\u0440\u0430\u043d\u043e\u0432 \u0432\u0445\u043e\u0434\u0430", "OptionDisableUser": "\u0417\u0430\u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f", - "OptionDisableUserHelp": "\u041f\u0440\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0437\u043a\u043e \u043e\u0431\u043e\u0440\u0432\u0430\u043d\u044b.", + "OptionDisableUserHelp": "\u041f\u0440\u0438 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438, \u0441\u0435\u0440\u0432\u0435\u0440 \u043d\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0435\u0442 \u043b\u044e\u0431\u044b\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0437\u043a\u043e \u043e\u0431\u043e\u0440\u0432\u0430\u043d\u044b.", "HeaderAdvancedControl": "\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435", "LabelName": "\u0418\u043c\u044f (\u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435):", - "OptionAllowUserToManageServer": "\u042d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c", + "OptionAllowUserToManageServer": "\u042d\u0442\u043e\u043c\u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0440\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c", "HeaderFeatureAccess": "\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438", "OptionAllowMediaPlayback": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445", "OptionAllowBrowsingLiveTv": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u0422\u0412-\u044d\u0444\u0438\u0440\u0430", - "OptionAllowDeleteLibraryContent": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438", + "OptionAllowDeleteLibraryContent": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f \u043c\u0435\u0434\u0438\u0430\u0442\u0435\u043a\u0438", "OptionAllowManageLiveTv": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u044f\u043c\u0438 \u0441 \u0422\u0412-\u044d\u0444\u0438\u0440\u0430", - "OptionAllowRemoteControlOthers": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438", - "OptionAllowRemoteSharedDevices": "\u041f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0433\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438", + "OptionAllowRemoteControlOthers": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c\u0438", + "OptionAllowRemoteSharedDevices": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0443\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0431\u0449\u0438\u043c\u0438 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438", "OptionAllowRemoteSharedDevicesHelp": "DLNA-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u043c\u0438, \u043f\u043e\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043c\u0438.", "HeaderRemoteControl": "\u0423\u0434\u0430\u043b\u0451\u043d\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435", "OptionMissingTmdbId": "\u041d\u0435\u0442 TMDb Id", @@ -258,7 +257,7 @@ "OptionRelease": "\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u043f\u0443\u0441\u043a", "OptionBeta": "\u0411\u0435\u0442\u0430-\u0432\u0435\u0440\u0441\u0438\u044f", "OptionDev": "\u0420\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c\u0430\u044f (\u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e)", - "LabelAllowServerAutoRestart": "\u0421\u0435\u0440\u0432\u0435\u0440\u0443 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439", + "LabelAllowServerAutoRestart": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439", "LabelAllowServerAutoRestartHelp": "\u0421\u0435\u0440\u0432\u0435\u0440 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0435\u0440\u0438\u043e\u0434\u044b \u043f\u0440\u043e\u0441\u0442\u043e\u044f, \u043a\u043e\u0433\u0434\u0430 \u043d\u0438\u043a\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043d\u0435 \u0430\u043a\u0442\u0438\u0432\u043d\u044b.", "LabelEnableDebugLogging": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0416\u0443\u0440\u043d\u0430\u043b\u0435", "LabelRunServerAtStartup": "\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0435\u0440\u0432\u0435\u0440 \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b", @@ -435,7 +434,7 @@ "OptionMaxQualityTranscoding": "\u041a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e", "OptionEnableDebugTranscodingLogging": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043e\u0442\u043b\u0430\u0434\u043e\u0447\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u043f\u0435\u0440\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438 \u0432 \u0416\u0443\u0440\u043d\u0430\u043b\u0435", "OptionEnableDebugTranscodingLoggingHelp": "\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0444\u0430\u0439\u043b\u044b \u0416\u0443\u0440\u043d\u0430\u043b\u0430 \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0451\u043c\u0430, \u0430 \u044d\u0442\u043e \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0441\u0438\u043b\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0443\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043d\u0435\u043f\u043e\u043b\u0430\u0434\u043e\u043a.", - "OptionUpscaling": "\u041a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0441\u043e\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e", + "OptionUpscaling": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0430\u043c \u0437\u0430\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e", "OptionUpscalingHelp": "\u0412 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445, \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0451\u0442 \u043a \u0443\u043b\u0443\u0447\u0448\u0435\u043d\u0438\u044e \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430 \u0432\u0438\u0434\u0435\u043e, \u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u0441\u044f \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u0430.", "EditCollectionItemsHelp": "\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0438\u043b\u0438 \u0438\u0437\u044b\u043c\u0438\u0442\u0435 \u043b\u044e\u0431\u044b\u0435 \u0444\u0438\u043b\u044c\u043c\u044b, \u0441\u0435\u0440\u0438\u0430\u043b\u044b, \u0430\u043b\u044c\u0431\u043e\u043c\u044b, \u043a\u043d\u0438\u0433\u0438 \u0438\u043b\u0438 \u0438\u0433\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0443\u0442\u0440\u0438 \u0434\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0438.", "HeaderAddTitles": "\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0439", @@ -944,7 +943,7 @@ "TabSort": "\u041f\u043e\u0440\u044f\u0434\u043e\u043a", "TabFilter": "\u0424\u0438\u043b\u044c\u0442\u0440\u044b", "ButtonView": "\u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c", - "LabelPageSize": "\u041c\u0430\u043a\u0441. \u0447\u0438\u0441\u043b\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:", + "LabelPageSize": "\u041f\u0440\u0435\u0434\u0435\u043b \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432:", "LabelPath": "\u041f\u0443\u0442\u044c:", "LabelView": "\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435:", "TabUsers": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438", @@ -1191,8 +1190,8 @@ "LabelLimitIntrosToUnwatchedContent": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u043d\u0435\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u043e\u043c\u0443 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044e", "LabelEnableIntroParentalControl": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435\u043c", "LabelEnableIntroParentalControlHelp": "\u0422\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u043d\u043e\u0439 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0435\u0439 \u0440\u0430\u0432\u043d\u043e\u0439 \u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435\u0439, \u0447\u0435\u043c \u043f\u0440\u043e\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0435.", - "LabelTheseFeaturesRequireSupporterHelpAndTrailers": "\u0414\u0430\u043d\u043d\u044b\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", - "OptionTrailersFromMyMoviesHelp": "\u041f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", + "LabelTheseFeaturesRequireSupporterHelpAndTrailers": "\u0414\u0430\u043d\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0442\u0440\u0435\u0431\u0443\u044e\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0447\u043b\u0435\u043d\u0441\u0442\u0432\u0430 \u0441\u043f\u043e\u043d\u0441\u043e\u0440\u0430 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u043b\u0430\u0433\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", + "OptionTrailersFromMyMoviesHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", "LabelCustomIntrosPath": "\u041f\u0443\u0442\u044c \u043a \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c \u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0430\u043c:", "LabelCustomIntrosPathHelp": "\u041f\u0430\u043f\u043a\u0430, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f \u0432\u0438\u0434\u0435\u043e\u0444\u0430\u0439\u043b\u044b. \u0412\u0438\u0434\u0435\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", "ValueSpecialEpisodeName": "\u0421\u043f\u0435\u0446\u044d\u043f\u0438\u0437\u043e\u0434 - {0}", @@ -1200,7 +1199,7 @@ "OptionUpcomingDvdMovies": "\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u043a \u043d\u043e\u0432\u044b\u043c \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c \u0444\u0438\u043b\u044c\u043c\u0430\u043c \u043d\u0430 DVD \u0438 BluRay", "OptionUpcomingStreamingMovies": "\u041e\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u043a \u043d\u043e\u0432\u044b\u043c \u0438 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u043c \u0444\u0438\u043b\u044c\u043c\u0430\u043c \u043d\u0430 Netflix", "LabelDisplayTrailersWithinMovieSuggestions": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u044b \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u043c\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432", - "LabelDisplayTrailersWithinMovieSuggestionsHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432", + "LabelDisplayTrailersWithinMovieSuggestionsHelp": "\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u0442\u0440\u0435\u0439\u043b\u0435\u0440\u043e\u0432.", "CinemaModeConfigurationHelp2": "\u041e\u0431\u043e\u0441\u043e\u0431\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b \u0432\u044b\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0441\u0432\u043e\u0438\u0445 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.", "LabelEnableCinemaMode": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0440\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430", "HeaderCinemaMode": "\u0420\u0435\u0436\u0438\u043c \u043a\u0438\u043d\u043e\u0442\u0435\u0430\u0442\u0440\u0430", @@ -1277,7 +1276,8 @@ "LabelBlockItemsWithTags": "\u0411\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u0442\u0435\u0433\u0430\u043c\u0438:", "LabelTag": "\u0422\u0435\u0433:", "LabelEnableSingleImageInDidlLimit": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0434\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u043d\u0435\u0434\u0440\u0451\u043d\u043d\u043e\u0433\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u0430", - "LabelEnableSingleImageInDidlLimitHelp": "\u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0435\u0441\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432\u043d\u0435\u0434\u0440\u044f\u044e\u0442\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 Didl.", + "LabelEnableSingleImageInDidlLimitHelp": "\u041d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u0445 \u043d\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e, \u0435\u0441\u043b\u0438 \u0432\u043d\u0435\u0434\u0440\u0435\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0438\u0441\u0443\u043d\u043a\u043e\u0432 \u0432\u043d\u0443\u0442\u0440\u0438 Didl.", "TabActivity": "\u0414\u0435\u0439\u0441\u0442\u0432\u0438\u044f", - "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f" + "TitleSync": "\u0421\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044f", + "OptionAllowSyncContent": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u044e \u043c\u0435\u0434\u0438\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/server.json b/MediaBrowser.Server.Implementations/Localization/Server/server.json index 09cd286b4..c0af13950 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/server.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/server.json @@ -37,10 +37,21 @@ "ButtonOk": "Ok", "ButtonCancel": "Cancel", "ButtonNew": "New", + "FolderTypeMixed": "Mixed content", + "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:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "Country:", "LabelLanguage": "Language:", @@ -1295,5 +1306,9 @@ "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", + "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/Localization/Server/sv.json b/MediaBrowser.Server.Implementations/Localization/Server/sv.json index b3831a097..3984619e5 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/sv.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/sv.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Konfigurera mediabiblioteket", "ButtonAddMediaFolder": "Skapa mediamapp", "LabelFolderType": "Typ av mapp:", - "MediaFolderHelpPluginRequired": "* Kr\u00e4ver att ett till\u00e4gg, t ex GameBrowser eller MB Bookshelf, \u00e4r installerat.", "ReferToMediaLibraryWiki": "Se avsnittet om mediabibliotek i v\u00e5r Wiki.", "LabelCountry": "Land:", "LabelLanguage": "Spr\u00e5k:", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/tr.json b/MediaBrowser.Server.Implementations/Localization/Server/tr.json index 51644f389..a37151337 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/tr.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/tr.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "Medya k\u00fct\u00fcphaneni kur", "ButtonAddMediaFolder": "Yeni Media Klas\u00f6r\u00fc", "LabelFolderType": "Klas\u00f6r T\u00fcr\u00fc:", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Refer to the media library wiki.", "LabelCountry": "\u00dclke", "LabelLanguage": "Dil", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/vi.json b/MediaBrowser.Server.Implementations/Localization/Server/vi.json index 93a725d19..8c27d0186 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/vi.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/vi.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "C\u00e0i \u0111\u1eb7t th\u01b0 vi\u1ec7n media c\u1ee7a b\u1ea1n", "ButtonAddMediaFolder": "Th\u00eam m\u1ed9t th\u01b0 m\u1ee5c media", "LabelFolderType": "Lo\u1ea1i th\u01b0 m\u1ee5c", - "MediaFolderHelpPluginRequired": "* Requires the use of a plugin, e.g. GameBrowser or MB Bookshelf.", "ReferToMediaLibraryWiki": "Tham kh\u1ea3o th\u01b0 vi\u1ec7n wiki media.", "LabelCountry": "Qu\u1ed1c gia:", "LabelLanguage": "Ng\u00f4n ng\u1eef", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json index bfc16efb8..c26ca2b53 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_CN.json @@ -1,5 +1,5 @@ { - "LabelExit": "\u79bb\u5f00", + "LabelExit": "\u9000\u51fa", "LabelVisitCommunity": "\u8bbf\u95ee\u793e\u533a", "LabelGithub": "Github", "LabelSwagger": "Swagger", @@ -7,30 +7,30 @@ "LabelApiDocumentation": "Api Documentation", "LabelDeveloperResources": "Developer Resources", "LabelBrowseLibrary": "\u6d4f\u89c8\u5a92\u4f53\u5e93", - "LabelConfigureMediaBrowser": "\u914d\u7f6eMedia Browser", + "LabelConfigureMediaBrowser": "\u914d\u7f6e Media Browser", "LabelOpenLibraryViewer": "\u6253\u5f00\u5a92\u4f53\u5e93\u6d4f\u89c8\u5668", "LabelRestartServer": "\u91cd\u542f\u670d\u52a1\u5668", "LabelShowLogWindow": "\u663e\u793a\u65e5\u5fd7\u7a97\u53e3", "LabelPrevious": "\u4e0a\u4e00\u4e2a", - "LabelFinish": "\u7ed3\u675f", + "LabelFinish": "\u5b8c\u6210", "LabelNext": "\u4e0b\u4e00\u4e2a", "LabelYoureDone": "\u5b8c\u6210\uff01", - "WelcomeToMediaBrowser": "\u6b22\u8fce\u8fdb\u5165Media Browser\uff01", + "WelcomeToMediaBrowser": "\u6b22\u8fce\u4f7f\u7528 Media Browser\uff01", "TitleMediaBrowser": "Media Browser", - "ThisWizardWillGuideYou": "\u8be5\u5411\u5bfc\u5c06\u6307\u5bfc\u4f60\u5b8c\u6210\u5b89\u88c5\u8fc7\u7a0b\u3002\u9996\u5148\uff0c\u8bf7\u9009\u62e9\u4f60\u7684\u8bed\u8a00\u3002", + "ThisWizardWillGuideYou": "\u8be5\u5411\u5bfc\u5c06\u6307\u5bfc\u4f60\u5b8c\u6210\u5b89\u88c5\u8fc7\u7a0b\u3002\u9996\u5148\uff0c\u8bf7\u9009\u62e9\u4f60\u7684\u9996\u9009\u8bed\u8a00\u3002", "TellUsAboutYourself": "\u8bf7\u4ecb\u7ecd\u4e00\u4e0b\u4f60\u81ea\u5df1", "LabelYourFirstName": "\u4f60\u7684\u540d\u5b57\uff1a", "MoreUsersCanBeAddedLater": "\u7a0d\u540e\u5728\u63a7\u5236\u53f0\u4e2d\u53ef\u4ee5\u6dfb\u52a0\u66f4\u591a\u7528\u6237\u3002", - "UserProfilesIntro": "Media Browser\u652f\u6301\u591a\u4e2a\u7528\u6237\u8bbe\u5b9a\uff0c\u80fd\u4f7f\u6bcf\u4e2a\u7528\u6237\u90fd\u62e5\u6709\u81ea\u5df1\u4e13\u5c5e\u7684\u663e\u793a\u8bbe\u7f6e\uff0c\u64ad\u653e\u72b6\u6001\u548c\u5bb6\u957f\u63a7\u5236\u8bbe\u7f6e\u3002", + "UserProfilesIntro": "Media Browser \u652f\u6301\u591a\u4e2a\u7528\u6237\u8bbe\u5b9a\uff0c\u80fd\u4f7f\u6bcf\u4e2a\u7528\u6237\u90fd\u62e5\u6709\u81ea\u5df1\u4e13\u5c5e\u7684\u663e\u793a\u8bbe\u7f6e\uff0c\u64ad\u653e\u72b6\u6001\u548c\u5bb6\u957f\u63a7\u5236\u8bbe\u7f6e\u3002", "LabelWindowsService": "Windows \u670d\u52a1", "AWindowsServiceHasBeenInstalled": "Windows \u670d\u52a1\u5b89\u88c5\u5b8c\u6210", - "WindowsServiceIntro1": "Media Browser\u670d\u52a1\u5668\u4f5c\u4e3a\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u901a\u5e38\u4ee5\u4e00\u4e2a\u6258\u76d8\u56fe\u6807\u8fd0\u884c\uff0c\u4f46\u5982\u679c\u4f60\u559c\u6b22\u5b83\u4f5c\u4e3a\u540e\u53f0\u670d\u52a1\u8fd0\u884c\uff0c\u5b83\u53ef\u4ee5\u4eceWindows\u63a7\u5236\u9762\u677f\u542f\u52a8\u3002", + "WindowsServiceIntro1": "Media Browser \u670d\u52a1\u5668\u901a\u5e38\u4ee5\u6258\u76d8\u56fe\u6807\u7684\u5f62\u5f0f\u4ee5\u684c\u9762\u5e94\u7528\u7a0b\u5e8f\u8fd0\u884c\uff0c\u4f46\u5982\u679c\u4f60\u559c\u6b22\u5b83\u4f5c\u4e3a\u540e\u53f0\u670d\u52a1\u8fd0\u884c\uff0c\u5b83\u53ef\u4ee5\u4ece Windows \u63a7\u5236\u9762\u677f\u542f\u52a8\u3002", "WindowsServiceIntro2": "\u5982\u679c\u4f7f\u7528Windows\u670d\u52a1\uff0c\u8bf7\u6ce8\u610f\uff0c\u5b83\u4e0d\u80fd\u540c\u65f6\u4e3a\u6258\u76d8\u56fe\u6807\u8fd0\u884c\uff0c\u6240\u4ee5\u4f60\u9700\u8981\u9000\u51fa\u6258\u76d8\u4ee5\u8fd0\u884c\u670d\u52a1\u3002\u8be5\u670d\u52a1\u8fd8\u5c06\u9700\u8981\u7ba1\u7406\u5458\u6743\u9650\uff0c\u8be5\u6743\u9650\u53ef\u4ee5\u901a\u8fc7\u63a7\u5236\u9762\u677f\u914d\u7f6e\u3002\u8bf7\u6ce8\u610f\uff0c\u6b64\u65f6\u670d\u52a1\u65e0\u6cd5\u81ea\u52a8\u66f4\u65b0\uff0c\u6240\u4ee5\u65b0\u7684\u7248\u672c\u5c06\u9700\u8981\u624b\u52a8\u66f4\u65b0\u3002", "WizardCompleted": "\u8fd9\u662f\u73b0\u5728\u6211\u4eec\u6240\u8981\u77e5\u9053\u7684\u3002Media Browser\u5df2\u7ecf\u5f00\u59cb\u6574\u5408\u4f60\u5a92\u4f53\u5e93\u4e2d\u7684\u4fe1\u606f\u3002\u4f60\u53ef\u4ee5\u7ee7\u7eed\u67e5\u770b\u6211\u4eec\u7684\u5176\u4ed6\u5e94\u7528\u7a0b\u5e8f\uff0c\u7136\u540e<b>\u5b8c\u6210<\/b>\u6765\u67e5\u770b <b>\u63a7\u5236\u53f0<\/b>.", "LabelConfigureSettings": "\u914d\u7f6e\u8bbe\u7f6e", - "LabelEnableVideoImageExtraction": "\u542f\u7528\u89c6\u9891\u56fe\u7247\u63d0\u53d6", + "LabelEnableVideoImageExtraction": "\u542f\u7528\u89c6\u9891\u622a\u56fe\u529f\u80fd", "VideoImageExtractionHelp": "\u5bf9\u4e8e\u8fd8\u6ca1\u6709\u56fe\u7247\uff0c\u4ee5\u53ca\u6211\u4eec\u65e0\u6cd5\u627e\u5230\u7f51\u7edc\u56fe\u7247\u7684\u89c6\u9891\u3002\u8fd9\u4f1a\u989d\u5916\u589e\u52a0\u4e00\u4e9b\u521d\u59cb\u5316\u5a92\u4f53\u5e93\u7684\u626b\u63cf\u65f6\u95f4\uff0c\u4f46\u4f1a\u4f7f\u5a92\u4f53\u4ecb\u7ecd\u754c\u9762\u66f4\u52a0\u8d4f\u5fc3\u60a6\u76ee\u3002", - "LabelEnableChapterImageExtractionForMovies": "\u63d0\u53d6\u7535\u5f71\u7ae0\u8282\u56fe\u7247", + "LabelEnableChapterImageExtractionForMovies": "\u622a\u53d6\u7535\u5f71\u7ae0\u8282\u56fe\u7247", "LabelChapterImageExtractionForMoviesHelp": "\u4ece\u7ae0\u8282\u4e2d\u63d0\u53d6\u7684\u56fe\u7247\u5c06\u5141\u8bb8\u5ba2\u6237\u7aef\u663e\u793a\u56fe\u5f62\u9009\u62e9\u83dc\u5355\u3002\u8fd9\u4e2a\u8fc7\u7a0b\u53ef\u80fd\u4f1a\u5f88\u6162\uff0c \u66f4\u591a\u7684\u5360\u7528CPU\u8d44\u6e90\uff0c\u5e76\u4e14\u4f1a\u9700\u8981\u51e0\u4e2aGB\u7684\u786c\u76d8\u7a7a\u95f4\u3002\u5b83\u88ab\u9ed8\u8ba4\u8bbe\u7f6e\u4e8e\u6bcf\u665a\u51cc\u66684\u70b9\u8fd0\u884c\uff0c\u867d\u7136\u8fd9\u53ef\u4ee5\u5728\u8ba1\u5212\u4efb\u52a1\u4e2d\u914d\u7f6e\uff0c\u4f46\u6211\u4eec\u4e0d\u5efa\u8bae\u5728\u9ad8\u5cf0\u4f7f\u7528\u65f6\u95f4\u8fd0\u884c\u8be5\u4efb\u52a1\u3002", "LabelEnableAutomaticPortMapping": "\u542f\u7528\u81ea\u52a8\u7aef\u53e3\u6620\u5c04", "LabelEnableAutomaticPortMappingHelp": "UPNP\u5141\u8bb8\u81ea\u52a8\u8def\u7531\u5668\u914d\u7f6e\uff0c\u4ece\u800c\u66f4\u65b9\u4fbf\u7684\u8fdb\u884c\u8fdc\u7a0b\u8bbf\u95ee\u3002\u4f46\u8fd9\u53ef\u80fd\u4e0d\u9002\u7528\u4e8e\u67d0\u4e9b\u578b\u53f7\u7684\u8def\u7531\u5668\u3002", @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u8bbe\u7f6e\u4f60\u7684\u5a92\u4f53\u5e93", "ButtonAddMediaFolder": "\u6dfb\u52a0\u5a92\u4f53\u6587\u4ef6\u5939", "LabelFolderType": "\u6587\u4ef6\u5939\u7c7b\u578b\uff1a", - "MediaFolderHelpPluginRequired": "* \u9700\u8981\u4f7f\u7528\u4e00\u4e2a\u63d2\u4ef6\uff0c\u4f8b\u5982\uff1aGameBrowser \u6216\u8005 MB Bookshelf\u3002", "ReferToMediaLibraryWiki": "\u8bf7\u53c2\u9605\u5a92\u4f53\u5e93\u7ef4\u57fa\u3002", "LabelCountry": "\u56fd\u5bb6\uff1a", "LabelLanguage": "\u8bed\u8a00\uff1a", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json index 8d87c6897..487f58dbb 100644 --- a/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json +++ b/MediaBrowser.Server.Implementations/Localization/Server/zh_TW.json @@ -40,7 +40,6 @@ "HeaderSetupLibrary": "\u8a2d\u7f6e\u4f60\u7684\u5a92\u9ad4\u5eab", "ButtonAddMediaFolder": "\u6dfb\u52a0\u5a92\u9ad4\u6587\u4ef6\u593e", "LabelFolderType": "\u5a92\u9ad4\u6587\u4ef6\u593e\u985e\u578b\uff1a", - "MediaFolderHelpPluginRequired": "*\u9700\u8981\u4f7f\u7528\u4e00\u500b\u63d2\u4ef6\uff0c\u4f8b\u5982GameBrowser\u6216MB Bookshelf\u3002", "ReferToMediaLibraryWiki": "\u53c3\u7167\u5a92\u9ad4\u5eab\u7ef4\u57fa", "LabelCountry": "\u570b\u5bb6\uff1a", "LabelLanguage": "\u8a9e\u8a00\uff1a", @@ -1279,5 +1278,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" }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index ed014fff7..4d21d2e94 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -51,7 +51,7 @@ </Reference> <Reference Include="MediaBrowser.Naming, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> - <HintPath>..\packages\MediaBrowser.Naming.1.0.0.18\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath> + <HintPath>..\packages\MediaBrowser.Naming.1.0.0.22\lib\portable-net45+sl4+wp71+win8+wpa81\MediaBrowser.Naming.dll</HintPath> </Reference> <Reference Include="Mono.Nat, Version=1.2.21.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> @@ -183,6 +183,7 @@ <Compile Include="Library\LocalTrailerPostScanTask.cs" /> <Compile Include="Library\MusicManager.cs" /> <Compile Include="Library\PathExtensions.cs" /> + <Compile Include="Library\Resolvers\SpecialFolderResolver.cs" /> <Compile Include="Library\Resolvers\BaseVideoResolver.cs" /> <Compile Include="Library\Resolvers\PhotoAlbumResolver.cs" /> <Compile Include="Library\Resolvers\PhotoResolver.cs" /> diff --git a/MediaBrowser.Server.Implementations/News/NewsService.cs b/MediaBrowser.Server.Implementations/News/NewsService.cs index 9eeadfab7..684363d01 100644 --- a/MediaBrowser.Server.Implementations/News/NewsService.cs +++ b/MediaBrowser.Server.Implementations/News/NewsService.cs @@ -26,6 +26,14 @@ namespace MediaBrowser.Server.Implementations.News { return GetProductNewsInternal(query); } + catch (DirectoryNotFoundException) + { + // No biggie + return new QueryResult<NewsItem> + { + Items = new NewsItem[] { } + }; + } catch (FileNotFoundException) { // No biggie diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 3f8b61a45..e74225887 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -78,7 +78,7 @@ namespace MediaBrowser.Server.Implementations.Notifications switch (request.SendToUserMode.Value) { case SendToUserType.Admins: - return _userManager.Users.Where(i => i.Configuration.IsAdministrator) + return _userManager.Users.Where(i => i.Policy.IsAdministrator) .Select(i => i.Id.ToString("N")); case SendToUserType.All: return _userManager.Users.Select(i => i.Id.ToString("N")); diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 664ec4038..6b15aaed7 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -4,6 +4,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.Sync; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; @@ -242,7 +243,7 @@ namespace MediaBrowser.Server.Implementations.Sync return true; } - return item.LocationType == LocationType.FileSystem || item is Season; + return item.LocationType == LocationType.FileSystem || item is Season || item is ILiveTvRecording; } private string GetDefaultName(BaseItem item) diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index 7825b9e9a..e65d4c66e 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -24,6 +24,7 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private IDbCommand _deleteJobCommand; + private IDbCommand _deleteJobItemsCommand; private IDbCommand _saveJobCommand; private IDbCommand _saveJobItemCommand; @@ -61,9 +62,13 @@ namespace MediaBrowser.Server.Implementations.Sync private void PrepareStatements() { _deleteJobCommand = _connection.CreateCommand(); - _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id; delete from SyncJobItems where JobId=@Id"; + _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id"; _deleteJobCommand.Parameters.Add(_deleteJobCommand, "@Id"); + _deleteJobItemsCommand = _connection.CreateCommand(); + _deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId"; + _deleteJobItemsCommand.Parameters.Add(_deleteJobItemsCommand, "@JobId"); + _saveJobCommand = _connection.CreateCommand(); _saveJobCommand.CommandText = "replace into SyncJobs (Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Quality, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)"; @@ -289,11 +294,13 @@ namespace MediaBrowser.Server.Implementations.Sync var index = 0; _deleteJobCommand.GetParameter(index++).Value = new Guid(id); - _deleteJobCommand.Transaction = transaction; - _deleteJobCommand.ExecuteNonQuery(); + _deleteJobItemsCommand.GetParameter(index++).Value = new Guid(id); + _deleteJobItemsCommand.Transaction = transaction; + _deleteJobItemsCommand.ExecuteNonQuery(); + transaction.Commit(); } catch (OperationCanceledException) diff --git a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs index df03ab6f7..47bab6e53 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs @@ -61,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Sync public bool IsHidden { - get { return true; } + get { return false; } } public bool IsEnabled diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index 0c79ba387..2fa4d1449 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?>
<packages>
- <package id="MediaBrowser.Naming" version="1.0.0.18" targetFramework="net45" />
+ <package id="MediaBrowser.Naming" version="1.0.0.21" targetFramework="net45" />
<package id="Mono.Nat" version="1.2.21.0" targetFramework="net45" />
<package id="morelinq" version="1.1.0" targetFramework="net45" />
</packages>
\ No newline at end of file diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index eca600b33..c2520ff6b 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -238,12 +238,12 @@ namespace MediaBrowser.Server.Startup.Common /// <param name="remotePackageName">Name of the remote package.</param> /// <param name="supportsNativeWebSocket">if set to <c>true</c> [supports native web socket].</param> /// <param name="nativeApp">The native application.</param> - public ApplicationHost(ServerApplicationPaths applicationPaths, - ILogManager logManager, - StartupOptions options, + public ApplicationHost(ServerApplicationPaths applicationPaths, + ILogManager logManager, + StartupOptions options, IFileSystem fileSystem, - string remotePackageName, - bool supportsNativeWebSocket, + string remotePackageName, + bool supportsNativeWebSocket, INativeApp nativeApp) : base(applicationPaths, logManager, fileSystem) { @@ -353,17 +353,18 @@ namespace MediaBrowser.Server.Startup.Common public override async Task Init(IProgress<double> progress) { - PerformVersionMigration(); + PerformPreInitMigrations(); await base.Init(progress).ConfigureAwait(false); + + PerformPostInitMigrations(); } - private void PerformVersionMigration() + private void PerformPreInitMigrations() { var migrations = new List<IVersionMigration> { new MigrateUserFolders(ApplicationPaths), - new PlaylistImages(ServerConfigurationManager), new RenameXbmcOptions(ServerConfigurationManager), new RenameXmlOptions(ServerConfigurationManager), new DeprecatePlugins(ApplicationPaths), @@ -376,6 +377,19 @@ namespace MediaBrowser.Server.Startup.Common } } + private void PerformPostInitMigrations() + { + var migrations = new List<IVersionMigration> + { + new MigrateTranscodingPath(ServerConfigurationManager) + }; + + foreach (var task in migrations) + { + task.Run(); + } + } + /// <summary> /// Registers resources that classes will depend on /// </summary> @@ -384,7 +398,7 @@ namespace MediaBrowser.Server.Startup.Common { await base.RegisterResources(progress).ConfigureAwait(false); - RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer)); + RegisterSingleInstance<IHttpResultFactory>(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer)); RegisterSingleInstance<IServerApplicationHost>(this); RegisterSingleInstance<IServerApplicationPaths>(ApplicationPaths); @@ -399,7 +413,7 @@ namespace MediaBrowser.Server.Startup.Common UserDataManager = new UserDataManager(LogManager); RegisterSingleInstance(UserDataManager); - UserRepository = await GetUserRepository().ConfigureAwait(false); + UserRepository = await GetUserRepository().ConfigureAwait(false); RegisterSingleInstance(UserRepository); DisplayPreferencesRepository = new SqliteDisplayPreferencesRepository(ApplicationPaths, JsonSerializer, LogManager); @@ -420,7 +434,7 @@ namespace MediaBrowser.Server.Startup.Common SyncRepository = await GetSyncRepository().ConfigureAwait(false); RegisterSingleInstance(SyncRepository); - UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this); + UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer); RegisterSingleInstance(UserManager); LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager); @@ -440,7 +454,7 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager)); - HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", WebApplicationName, "dashboard/index.html", _supportsNativeWebSocket); + HttpServer = ServerFactory.CreateServer(this, LogManager, "Media Browser", WebApplicationName, "dashboard/index.html", _supportsNativeWebSocket); RegisterSingleInstance(HttpServer, false); progress.Report(10); @@ -534,12 +548,12 @@ namespace MediaBrowser.Server.Startup.Common RegisterSingleInstance<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager)); RegisterSingleInstance<IAuthService>(new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager)); - RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer)); + RegisterSingleInstance<ISubtitleEncoder>(new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer)); await ConfigureDisplayPreferencesRepositories().ConfigureAwait(false); await ConfigureItemRepositories().ConfigureAwait(false); await ConfigureUserDataRepositories().ConfigureAwait(false); - await ConfigureNotificationsRepository().ConfigureAwait(false); + await ConfigureNotificationsRepository().ConfigureAwait(false); progress.Report(100); SetStaticProperties(); diff --git a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj index b133f78e7..38e07fde4 100644 --- a/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj +++ b/MediaBrowser.Server.Startup.Common/MediaBrowser.Server.Startup.Common.csproj @@ -66,8 +66,8 @@ <Compile Include="Migrations\DeleteDlnaProfiles.cs" /> <Compile Include="Migrations\DeprecatePlugins.cs" /> <Compile Include="Migrations\IVersionMigration.cs" /> + <Compile Include="Migrations\MigrateTranscodingPath.cs" /> <Compile Include="Migrations\MigrateUserFolders.cs" /> - <Compile Include="Migrations\PlaylistImages.cs" /> <Compile Include="Migrations\RenameXbmcOptions.cs" /> <Compile Include="Migrations\RenameXmlOptions.cs" /> <Compile Include="NativeEnvironment.cs" /> diff --git a/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs b/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs new file mode 100644 index 000000000..88f60841d --- /dev/null +++ b/MediaBrowser.Server.Startup.Common/Migrations/MigrateTranscodingPath.cs @@ -0,0 +1,30 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Model.Configuration; + +namespace MediaBrowser.Server.Startup.Common.Migrations +{ + public class MigrateTranscodingPath : IVersionMigration + { + private readonly IServerConfigurationManager _config; + + public MigrateTranscodingPath(IServerConfigurationManager config) + { + _config = config; + } + + public void Run() + { + if (!string.IsNullOrWhiteSpace(_config.Configuration.TranscodingTempPath)) + { + var newConfig = _config.GetConfiguration<EncodingOptions>("encoding"); + + newConfig.TranscodingTempPath = _config.Configuration.TranscodingTempPath; + _config.SaveConfiguration("encoding", newConfig); + + _config.Configuration.TranscodingTempPath = null; + _config.SaveConfiguration(); + } + } + } +} diff --git a/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs b/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs deleted file mode 100644 index f6ddf5847..000000000 --- a/MediaBrowser.Server.Startup.Common/Migrations/PlaylistImages.cs +++ /dev/null @@ -1,55 +0,0 @@ -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Entities; -using System.IO; -using System.Linq; - -namespace MediaBrowser.Server.Startup.Common.Migrations -{ - public class PlaylistImages : IVersionMigration - { - private readonly IServerConfigurationManager _config; - - public PlaylistImages(IServerConfigurationManager config) - { - _config = config; - } - - public void Run() - { - if (!_config.Configuration.PlaylistImagesDeleted) - { - DeletePlaylistImages(); - _config.Configuration.PlaylistImagesDeleted = true; - _config.SaveConfiguration(); - } - } - - private void DeletePlaylistImages() - { - try - { - var path = Path.Combine(_config.ApplicationPaths.DataPath, "playlists"); - - var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories) - .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i) ?? string.Empty)) - .ToList(); - - foreach (var file in files) - { - try - { - File.Delete(file); - } - catch (IOException) - { - - } - } - } - catch (IOException) - { - - } - } - } -} diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs index a955b57ea..be8ae2f81 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs @@ -42,9 +42,9 @@ namespace MediaBrowser.Server.Startup.Common.Migrations { for (var i = 0; i < options.Length; i++) { - if (string.Equals(options[i], "Media Browser Xml", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(options[i], "Media Browser Legacy Xml", StringComparison.OrdinalIgnoreCase)) { - options[i] = "Media Browser Legacy Xml"; + options[i] = "Media Browser Xml"; changed = true; } } diff --git a/MediaBrowser.Tests/MediaBrowser.Tests.csproj b/MediaBrowser.Tests/MediaBrowser.Tests.csproj index f93a2612a..e9cec61d6 100644 --- a/MediaBrowser.Tests/MediaBrowser.Tests.csproj +++ b/MediaBrowser.Tests/MediaBrowser.Tests.csproj @@ -53,7 +53,6 @@ <Compile Include="MediaEncoding\Subtitles\AssParserTests.cs" /> <Compile Include="MediaEncoding\Subtitles\SrtParserTests.cs" /> <Compile Include="MediaEncoding\Subtitles\VttWriterTest.cs" /> - <Compile Include="Resolvers\TvUtilTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <ItemGroup> diff --git a/MediaBrowser.Tests/Resolvers/TvUtilTests.cs b/MediaBrowser.Tests/Resolvers/TvUtilTests.cs deleted file mode 100644 index ec9356dad..000000000 --- a/MediaBrowser.Tests/Resolvers/TvUtilTests.cs +++ /dev/null @@ -1,246 +0,0 @@ -using MediaBrowser.Controller.Library; -using MediaBrowser.Server.Implementations.Library.Resolvers.TV; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace MediaBrowser.Tests.Resolvers -{ - [TestClass] - public class TvUtilTests - { - [TestMethod] - public void TestGetEpisodeNumberFromFile() - { - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\S02E03 blah.avi", true)); - - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\01x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01E02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01xE02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname 01x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01E02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\seriesname S01xE02 blah.avi", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02x03-04-15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03-E15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\02x03x04x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext", true)); - Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4", true)); - Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4", true)); - Assert.AreEqual(9, SeriesResolver.GetEpisodeNumberFromFile(@"Season 25\The Simpsons.S25E09.Steal this episode.mp4", true)); - Assert.AreEqual(8, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons.S25E08.Steal this episode.mp4", false)); - Assert.AreEqual(136, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\[HorribleSubs] Hunter X Hunter - 136 [720p].mkv",true)); - - //Four Digits seasons - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009E02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009xE02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname 2009x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009x02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009E02 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\seriesname S2009xE02 blah.avi", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03-04-15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03-E15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\2009x03x04x15 - Ep Name.ext", true)); - Assert.AreEqual(03, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext", true)); - Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4", true)); - Assert.AreEqual(23, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4", true)); - - //Without season number - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\02 - blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02 - blah 14 blah.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 1\02 - blah-02 a.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"Season 2\02.avi", true)); - - //Without seasons - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02 - Ep Name.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02-Ep Name.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\02.EpName.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02 - Ep Name.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons - 02 Ep Name.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons 5 - 02 - Ep Name.avi", true)); - Assert.AreEqual(02, SeriesResolver.GetEpisodeNumberFromFile(@"The Simpsons\The Simpsons 5 - 02 Ep Name.avi", true)); - } - - [TestMethod] - public void TestGetEndingEpisodeNumberFromFile() - { - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\4x01 20 Hours in America (1).mkv")); - - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\01x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01E02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01xE02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname 01x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01E02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\seriesname S01xE02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03 - 04 Ep Name.ext")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\My show name 02x03 - 04 Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02x03-04-15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03-E15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\02x03x04x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext")); - Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4")); - Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4")); - - - //Four Digits seasons - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009E02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009xE02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname 2009x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009x02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009E02 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\seriesname S2009xE02 blah.avi")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03-04-15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03-E15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\2009x03x04x15 - Ep Name.ext")); - Assert.AreEqual(15, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext")); - Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4")); - Assert.AreEqual(26, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4")); - - //Without season number - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02 - blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02 - blah 14 blah.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02 - blah-02 a.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02.avi")); - - Assert.AreEqual(3, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02-03 - blah.avi")); - Assert.AreEqual(4, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02-04 - blah 14 blah.avi")); - Assert.AreEqual(5, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 1\02-05 - blah-02 a.avi")); - Assert.AreEqual(4, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\02-04.avi")); - Assert.AreEqual(null, SeriesResolver.GetEndingEpisodeNumberFromFile(@"Season 2\[HorribleSubs] Hunter X Hunter - 136 [720p].mkv")); - - } - - [TestMethod] - public void TestGetSeasonNumberFromPath() { - - Assert.AreEqual(02, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"\Show\Season 02\S02E03 blah.avi")); - - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 02")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 1")); - - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Seinfeld\S02")); - - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Seinfeld\2")); - - //Four Digits seasons - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromPath(@"\Drive\Season 2009")); - } - - [TestMethod] - public void TestGetSeasonNumberFromEpisodeFile() - { - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\01x02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01x02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01E02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01xE02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname 01x02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01x02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01E02 blah.avi")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\seriesname S01xE02 blah.avi")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\Elementary - 02x03 - 02x04 - 02x15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\02x03 - 02x04 - 02x15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\02x03-04-15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2\Elementary - 02x03-04-15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03-E15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03-E15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\02x03x04x15 - Ep Name.ext")); - Assert.AreEqual(2, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 02\Elementary - 02x03x04x15 - Ep Name.ext")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\Elementary - S01E23-E24-E26 - The Woman.mp4")); - Assert.AreEqual(1, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 1\S01E23-E24-E26 - The Woman.mp4")); - - //Four Digits seasons - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009x02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009E02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009xE02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname 2009x02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009x02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009E02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\seriesname S2009xE02 blah.avi")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03 - 2009x04 - 2009x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03-04-15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03-04-15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03-E15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03-E15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03 - x04 - x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\2009x03x04x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - 2009x03x04x15 - Ep Name.ext")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\Elementary - S2009E23-E24-E26 - The Woman.mp4")); - Assert.AreEqual(2009, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 2009\S2009E23-E24-E26 - The Woman.mp4")); - Assert.AreEqual(25, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"Season 25\The Simpsons.S25E09.Steal this episode.mp4")); - Assert.AreEqual(25, SeriesResolver.GetSeasonNumberFromEpisodeFile(@"The Simpsons\The Simpsons.S25E09.Steal this episode.mp4")); - } - } -} diff --git a/MediaBrowser.WebDashboard/Api/PackageCreator.cs b/MediaBrowser.WebDashboard/Api/PackageCreator.cs index b3a1bf84a..d727dda6e 100644 --- a/MediaBrowser.WebDashboard/Api/PackageCreator.cs +++ b/MediaBrowser.WebDashboard/Api/PackageCreator.cs @@ -197,6 +197,8 @@ namespace MediaBrowser.WebDashboard.Api { "thirdparty/jquerymobile-1.4.5/jquery.mobile-1.4.5.min.css", "thirdparty/swipebox-master/css/swipebox.min.css" + versionString, + "thirdparty/fontawesome/css/font-awesome.min.css" + versionString, + "thirdparty/jstree3.0.8/themes/default/style.min.css", "css/all.css" + versionString }; @@ -219,7 +221,7 @@ namespace MediaBrowser.WebDashboard.Api var files = new[] { "scripts/all.js" + versionString, - "thirdparty/jstree1.0/jquery.jstree.min.js", + "thirdparty/jstree3.0.8/jstree.min.js", "thirdparty/swipebox-master/js/jquery.swipebox.min.js" + versionString }; diff --git a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj index d8e6561ab..dc552c518 100644 --- a/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj +++ b/MediaBrowser.WebDashboard/MediaBrowser.WebDashboard.csproj @@ -210,9 +210,6 @@ <Content Include="dashboard-ui\css\images\favicon.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\headersearch.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\ellipsis-v.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -228,9 +225,6 @@ <Content Include="dashboard-ui\css\images\items\folders\report.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\items\folders\settings.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\icons\audiocd.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -594,9 +588,6 @@ <Content Include="dashboard-ui\css\images\rotten.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\css\images\currentuserdefaultwhite.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\css\images\items\detail\person.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -963,625 +954,19 @@ <Content Include="dashboard-ui\thirdparty\cast_sender.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquery.unveil-custom.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\ajax-loader.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\action-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\action-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\alert-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\alert-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-d-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\arrow-u-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\audio-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\audio-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\back-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\back-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bars-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bars-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bullets-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\bullets-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\calendar-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\calendar-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\camera-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\camera-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-d-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-d-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-l-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-l-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-r-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-r-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-u-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\carat-u-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\check-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\check-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\clock-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\clock-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\cloud-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\cloud-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\comment-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\comment-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\delete-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\delete-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\edit-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\edit-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\eye-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\eye-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forbidden-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forbidden-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forward-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\forward-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\gear-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\gear-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\grid-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\grid-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\heart-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\heart-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\home-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\home-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\info-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\info-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\location-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\location-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\lock-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\lock-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\mail-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\mail-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\minus-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\minus-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\navigation-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\navigation-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\phone-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\phone-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\plus-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\plus-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\power-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\power-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\recycle-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\recycle-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\refresh-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\refresh-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\search-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\search-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\shop-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\shop-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\star-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\star-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\tag-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\tag-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\user-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\user-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\video-black.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-png\video-white.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\action-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\action-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\alert-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\alert-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-d-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-l-white.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-r-black.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\css\font-awesome.min.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-r-white.svg">
+ <Content Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.svg">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\arrow-u-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\audio-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\audio-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\back-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\back-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bars-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bars-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bullets-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\bullets-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\calendar-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\calendar-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\camera-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\camera-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-d-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-d-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-l-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-l-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-r-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-r-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-u-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\carat-u-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\check-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\check-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\clock-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\clock-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\cloud-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\cloud-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\comment-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\comment-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\delete-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\delete-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\edit-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\edit-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\eye-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\eye-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forbidden-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forbidden-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forward-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\forward-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\gear-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\gear-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\grid-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\grid-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\heart-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\heart-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\home-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\home-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\info-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\info-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\location-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\location-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\lock-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\lock-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\mail-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\mail-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\minus-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\minus-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\navigation-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\navigation-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\phone-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\phone-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\plus-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\plus-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\power-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\power-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\recycle-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\recycle-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\refresh-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\refresh-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\search-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\search-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\shop-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\shop-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\star-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\star-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\tag-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\tag-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\user-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\user-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\video-black.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\images\icons-svg\video-white.svg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.css">
+ <Content Include="dashboard-ui\thirdparty\jquery-2.1.1.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.js">
+ <Content Include="dashboard-ui\thirdparty\jquery.unveil-custom.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\images\ajax-loader.gif">
@@ -2193,15 +1578,48 @@ <Content Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.min.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\livetvsuggested.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\thirdparty\apiclient\md5.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\jstree.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\jstree.min.js">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\32px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\40px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\style.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\style.min.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default-dark\throbber.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\32px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\40px.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\style.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\style.min.css">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="dashboard-ui\thirdparty\jstree3.0.8\themes\default\throbber.gif">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="dashboard-ui\thirdparty\swipebox-master\css\swipebox.css">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2438,78 +1856,6 @@ <Content Include="dashboard-ui\scripts\tvstudios.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\jquery.jstree.js">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\bg.jpg">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\dot_for_ie.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\apple\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\dot_for_ie.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\classic\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\dots.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default-rtl\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\default\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\d.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\d.png">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\style.css">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="dashboard-ui\thirdparty\jstree1.0\themes\mb3\throbber.gif">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
<Content Include="dashboard-ui\tvgenres.html">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
@@ -2917,10 +2263,16 @@ <None Include="dashboard-ui\css\fonts\RobotoThin.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.3.min.map">
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.eot">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.ttf">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\fontawesome-webfont.woff">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
- <None Include="dashboard-ui\thirdparty\jquerymobile-1.4.4\jquery.mobile-1.4.4.min.map">
+ <None Include="dashboard-ui\thirdparty\fontawesome\fonts\FontAwesome.otf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="dashboard-ui\thirdparty\jquerymobile-1.4.5\jquery.mobile-1.4.5.min.map">
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 86e92530f..0f1d53ea6 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -257,6 +257,10 @@ namespace MediaBrowser.XbmcMetadata.Savers { } + catch (DirectoryNotFoundException) + { + + } writer.WriteEndElement(); diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 22c2fdc24..c081917fb 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -7,7 +7,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{F0E0E6 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8C5D6ABC-D277-407B-8061-3AA04251D539}" ProjectSection(SolutionItems) = preProject + Performance1.psess = Performance1.psess Performance19.psess = Performance19.psess + Performance2.psess = Performance2.psess EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget (2)", ".nuget (2)", "{E60FB157-87E2-4A41-8B04-27EA49B63B4D}" @@ -516,4 +518,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 3ecc9f9a9..7d2adb590 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.521</version> + <version>3.0.522</version> <title>MediaBrowser.Common.Internal</title> <authors>Luke</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.521" /> + <dependency id="MediaBrowser.Common" version="3.0.522" /> <dependency id="NLog" version="3.1.0.0" /> <dependency id="SimpleInjector" version="2.6.1" /> <dependency id="sharpcompress" version="0.10.2" /> diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index da3e29b2a..705b3444a 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common</id> - <version>3.0.521</version> + <version>3.0.522</version> <title>MediaBrowser.Common</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index b0fe2b2c4..5df3ccb03 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Model.Signed</id> - <version>3.0.521</version> + <version>3.0.522</version> <title>MediaBrowser.Model - Signed Edition</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 57d224fd4..9e463b7ab 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Server.Core</id> - <version>3.0.521</version> + <version>3.0.522</version> <title>Media Browser.Server.Core</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains core components required to build plugins for Media Browser Server.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.521" /> + <dependency id="MediaBrowser.Common" version="3.0.522" /> </dependencies> </metadata> <files> diff --git a/SharedVersion.cs b/SharedVersion.cs index d323dc7bc..ac09f77b3 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -//[assembly: AssemblyVersion("3.0.*")] -[assembly: AssemblyVersion("3.0.5464.40000")] +[assembly: AssemblyVersion("3.0.*")] +//[assembly: AssemblyVersion("3.0.5464.40000")] |
