diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index a9b43090a2..ef415ec57c 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Configuration; -using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Session; using System; @@ -89,7 +88,7 @@ namespace MediaBrowser.Api /// private void DeleteEncodedMediaCache() { - var path = Path.Combine(_config.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower()); + var path = _config.ApplicationPaths.TranscodingTempPath; foreach (var file in Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) .ToList()) diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index 2a0c5e01f3..84dd0c1e8d 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -119,7 +119,7 @@ namespace MediaBrowser.Api.Playback /// System.String. private string GetOutputFilePath(StreamState state) { - var folder = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower()); + var folder = ServerConfigurationManager.ApplicationPaths.TranscodingTempPath; var outputFileExtension = GetOutputFileExtension(state); diff --git a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs index 14045b3a56..9f80fcd0ad 100644 --- a/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs +++ b/MediaBrowser.Api/Playback/Hls/HlsSegmentService.cs @@ -1,10 +1,6 @@ using MediaBrowser.Controller; -using MediaBrowser.Model.Dlna; using ServiceStack; -using System; using System.IO; -using System.Linq; -using System.Threading.Tasks; namespace MediaBrowser.Api.Playback.Hls { @@ -66,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls { var file = request.PlaylistId + Path.GetExtension(Request.PathInfo); - file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file); + file = Path.Combine(_appPaths.TranscodingTempPath, file); return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } @@ -85,7 +81,7 @@ namespace MediaBrowser.Api.Playback.Hls { var file = request.SegmentId + Path.GetExtension(Request.PathInfo); - file = Path.Combine(_appPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file); + file = Path.Combine(_appPaths.TranscodingTempPath, file); return ResultFactory.GetStaticFileResult(Request, file, FileShare.ReadWrite); } diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs index d786b51b3a..de845c88d8 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Dlna; using MediaBrowser.Model.IO; using ServiceStack; using System; @@ -71,7 +70,7 @@ namespace MediaBrowser.Api.Playback.Hls { var file = request.SegmentId + Path.GetExtension(Request.PathInfo); - file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, EncodingContext.Streaming.ToString().ToLower(), file); + file = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, file); return ResultFactory.GetStaticFileResult(Request, file); } diff --git a/MediaBrowser.Api/Sync/SyncService.cs b/MediaBrowser.Api/Sync/SyncService.cs index a7467c12f1..8d5ec824f8 100644 --- a/MediaBrowser.Api/Sync/SyncService.cs +++ b/MediaBrowser.Api/Sync/SyncService.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Sync; -using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Sync; using MediaBrowser.Model.Users; @@ -85,6 +84,16 @@ namespace MediaBrowser.Api.Sync public string Id { get; set; } } + [Route("/Sync/JobItems/{Id}/AdditionalFiles", "GET", Summary = "Gets a sync job item file")] + public class GetSyncJobItemAdditionalFile + { + [ApiMember(Name = "Id", Description = "Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + + [ApiMember(Name = "Name", Description = "Name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")] + public string Name { get; set; } + } + [Route("/Sync/OfflineActions", "POST", Summary = "Reports an action that occurred while offline.")] public class ReportOfflineActions : List, IReturnVoid { @@ -243,5 +252,24 @@ namespace MediaBrowser.Api.Sync Task.WaitAll(task); } + + public object Get(GetSyncJobItemAdditionalFile request) + { + var jobItem = _syncManager.GetJobItem(request.Id); + + if (jobItem.Status != SyncJobItemStatus.Transferring) + { + throw new ArgumentException("The job item is not yet ready for transfer."); + } + + var file = jobItem.AdditionalFiles.FirstOrDefault(i => string.Equals(i.Name, request.Name, StringComparison.OrdinalIgnoreCase)); + + if (file == null) + { + throw new ArgumentException("Sync job additional file not found."); + } + + return ToStaticFileResult(file.Path); + } } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index d1a9b386cc..76eb9fceb0 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using MediaBrowser.Common; +using MediaBrowser.Common; using MediaBrowser.Model.System; using System; +using System.Collections.Generic; namespace MediaBrowser.Controller { diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index a988c2f974..ad9ab90a03 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Controller.MediaEncoding public class EncodingJobOptions { public string OutputContainer { get; set; } + public string OutputDirectory { get; set; } public long? StartTimeTicks { get; set; } public int? Width { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index 4db4cd4277..4dc522f05c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -280,13 +280,14 @@ namespace MediaBrowser.MediaEncoding.Encoder private string GetOutputFilePath(EncodingJob state) { - var folder = ConfigurationManager.ApplicationPaths.TranscodingTempPath; + var folder = string.IsNullOrWhiteSpace(state.Options.OutputDirectory) ? + ConfigurationManager.ApplicationPaths.TranscodingTempPath : + state.Options.OutputDirectory; var outputFileExtension = GetOutputFileExtension(state); - var context = state.Options.Context; var filename = state.Id + (outputFileExtension ?? string.Empty).ToLower(); - return Path.Combine(folder, context.ToString().ToLower(), filename); + return Path.Combine(folder, filename); } protected virtual string GetOutputFileExtension(EncodingJob state) diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index c49e3e303f..de60a3e834 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -1094,6 +1094,9 @@ Sync\SyncOptions.cs + + Sync\SyncParameter.cs + Sync\SyncQuality.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index d8a29e8da4..1cc1aac094 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -1053,6 +1053,9 @@ Sync\SyncOptions.cs + + Sync\SyncParameter.cs + Sync\SyncQuality.cs diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index bcba9230ff..e8535278bb 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -1413,6 +1413,15 @@ namespace MediaBrowser.Model.ApiClient /// Task<Stream>. Task GetSyncJobItemFile(string id, CancellationToken cancellationToken); + /// + /// Gets the synchronize job item additional file. + /// + /// The identifier. + /// The name. + /// The cancellation token. + /// Task<Stream>. + Task GetSyncJobItemAdditionalFile(string id, string name, CancellationToken cancellationToken); + /// /// Opens the web socket. /// diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 22eb0cf6ce..acd2658a8c 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -212,7 +212,8 @@ namespace MediaBrowser.Model.Dlna IsForced = stream.IsForced, Language = stream.Language, Name = stream.Language ?? "Unknown", - Format = SubtitleFormat + Format = SubtitleFormat, + Index = stream.Index }); } diff --git a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs index 1600408d60..a7a8da3ba2 100644 --- a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs +++ b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs @@ -7,5 +7,6 @@ namespace MediaBrowser.Model.Dlna public string Name { get; set; } public bool IsForced { get; set; } public string Format { get; set; } + public int Index { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 2a1b0b6593..599e4a9021 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -385,6 +385,7 @@ + diff --git a/MediaBrowser.Model/Sync/ItemFIleInfo.cs b/MediaBrowser.Model/Sync/ItemFIleInfo.cs index b110af6b5a..e023572fd2 100644 --- a/MediaBrowser.Model/Sync/ItemFIleInfo.cs +++ b/MediaBrowser.Model/Sync/ItemFIleInfo.cs @@ -23,6 +23,11 @@ namespace MediaBrowser.Model.Sync /// Gets or sets the type of the image. /// /// The type of the image. - public ImageType ImageType { get; set; } + public ImageType? ImageType { get; set; } + /// + /// Gets or sets the index. + /// + /// The index. + public int Index { get; set; } } } diff --git a/MediaBrowser.Model/Sync/SyncDialogOptions.cs b/MediaBrowser.Model/Sync/SyncDialogOptions.cs index 0154b16ec1..304e10ccc4 100644 --- a/MediaBrowser.Model/Sync/SyncDialogOptions.cs +++ b/MediaBrowser.Model/Sync/SyncDialogOptions.cs @@ -13,12 +13,12 @@ namespace MediaBrowser.Model.Sync /// Gets or sets the options. /// /// The options. - public List Options { get; set; } + public List Options { get; set; } public SyncDialogOptions() { Targets = new List(); - Options = new List(); + Options = new List(); } } } diff --git a/MediaBrowser.Model/Sync/SyncHelper.cs b/MediaBrowser.Model/Sync/SyncHelper.cs index c2a446fbe6..34a5ba9954 100644 --- a/MediaBrowser.Model/Sync/SyncHelper.cs +++ b/MediaBrowser.Model/Sync/SyncHelper.cs @@ -5,13 +5,13 @@ namespace MediaBrowser.Model.Sync { public static class SyncHelper { - public static List GetSyncOptions(List items) + public static List GetSyncOptions(List items) { - List options = new List(); + List options = new List(); if (items.Count > 1) { - options.Add(SyncOptions.Name); + options.Add(SyncJobOption.Name); } foreach (BaseItemDto item in items) @@ -20,23 +20,23 @@ namespace MediaBrowser.Model.Sync { if (item.IsVideo) { - options.Add(SyncOptions.Quality); + options.Add(SyncJobOption.Quality); if (items.Count > 1) { - options.Add(SyncOptions.UnwatchedOnly); + options.Add(SyncJobOption.UnwatchedOnly); } break; } if (item.IsFolder && !item.IsMusicGenre && !item.IsArtist && !item.IsType("musicalbum") && !item.IsGameGenre) { - options.Add(SyncOptions.Quality); - options.Add(SyncOptions.UnwatchedOnly); + options.Add(SyncJobOption.Quality); + options.Add(SyncJobOption.UnwatchedOnly); break; } if (item.IsGenre) { - options.Add(SyncOptions.SyncNewContent); - options.Add(SyncOptions.ItemLimit); + options.Add(SyncJobOption.SyncNewContent); + options.Add(SyncJobOption.ItemLimit); break; } } @@ -48,8 +48,8 @@ namespace MediaBrowser.Model.Sync { if (item.IsFolder || item.IsGameGenre || item.IsMusicGenre || item.IsGenre || item.IsArtist || item.IsStudio || item.IsPerson) { - options.Add(SyncOptions.SyncNewContent); - options.Add(SyncOptions.ItemLimit); + options.Add(SyncJobOption.SyncNewContent); + options.Add(SyncJobOption.ItemLimit); break; } } @@ -58,15 +58,15 @@ namespace MediaBrowser.Model.Sync return options; } - public static List GetSyncOptions(SyncCategory category) + public static List GetSyncOptions(SyncCategory category) { - List options = new List(); + List options = new List(); - options.Add(SyncOptions.Name); - options.Add(SyncOptions.Quality); - options.Add(SyncOptions.UnwatchedOnly); - options.Add(SyncOptions.SyncNewContent); - options.Add(SyncOptions.ItemLimit); + options.Add(SyncJobOption.Name); + options.Add(SyncJobOption.Quality); + options.Add(SyncJobOption.UnwatchedOnly); + options.Add(SyncJobOption.SyncNewContent); + options.Add(SyncJobOption.ItemLimit); return options; } diff --git a/MediaBrowser.Model/Sync/SyncJobItem.cs b/MediaBrowser.Model/Sync/SyncJobItem.cs index 3d06943aa3..943014c0d2 100644 --- a/MediaBrowser.Model/Sync/SyncJobItem.cs +++ b/MediaBrowser.Model/Sync/SyncJobItem.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using MediaBrowser.Model.Dto; namespace MediaBrowser.Model.Sync { @@ -27,12 +29,18 @@ namespace MediaBrowser.Model.Sync /// /// The name of the item. public string ItemName { get; set; } - + /// /// Gets or sets the media source identifier. /// /// The media source identifier. public string MediaSourceId { get; set; } + + /// + /// Gets or sets the media source. + /// + /// The media source. + public MediaSourceInfo MediaSource { get; set; } /// /// Gets or sets the target identifier. @@ -74,9 +82,15 @@ namespace MediaBrowser.Model.Sync /// The primary image tag. public string PrimaryImageTag { get; set; } /// - /// Gets or sets a value indicating whether [requires conversion]. + /// Gets or sets the temporary path. /// - /// true if [requires conversion]; otherwise, false. - public bool RequiresConversion { get; set; } + /// The temporary path. + public string TemporaryPath { get; set; } + public List AdditionalFiles { get; set; } + + public SyncJobItem() + { + AdditionalFiles = new List(); + } } } diff --git a/MediaBrowser.Model/Sync/SyncOptions.cs b/MediaBrowser.Model/Sync/SyncOptions.cs index d4a7461f3a..294f7bcef7 100644 --- a/MediaBrowser.Model/Sync/SyncOptions.cs +++ b/MediaBrowser.Model/Sync/SyncOptions.cs @@ -1,12 +1,8 @@  namespace MediaBrowser.Model.Sync { - public enum SyncOptions + public class SyncOptions { - Name = 0, - Quality = 1, - UnwatchedOnly = 2, - SyncNewContent = 3, - ItemLimit = 4 + public string TemporaryPath { get; set; } } } diff --git a/MediaBrowser.Model/Sync/SyncParameter.cs b/MediaBrowser.Model/Sync/SyncParameter.cs new file mode 100644 index 0000000000..def4ab3e3f --- /dev/null +++ b/MediaBrowser.Model/Sync/SyncParameter.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Model.Sync +{ + public enum SyncJobOption + { + Name = 0, + Quality = 1, + UnwatchedOnly = 2, + SyncNewContent = 3, + ItemLimit = 4 + } +} diff --git a/MediaBrowser.Model/Sync/SyncedItem.cs b/MediaBrowser.Model/Sync/SyncedItem.cs index 784a12bc94..2063506b16 100644 --- a/MediaBrowser.Model/Sync/SyncedItem.cs +++ b/MediaBrowser.Model/Sync/SyncedItem.cs @@ -1,4 +1,5 @@ using MediaBrowser.Model.Dto; +using System.Collections.Generic; namespace MediaBrowser.Model.Sync { @@ -34,5 +35,15 @@ namespace MediaBrowser.Model.Sync /// /// The user identifier. public string UserId { get; set; } + /// + /// Gets or sets the additional files. + /// + /// The additional files. + public List AdditionalFiles { get; set; } + + public SyncedItem() + { + AdditionalFiles = new List(); + } } } diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 433b766570..b4f277fbdf 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -300,6 +300,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Session/SessionManager.cs b/MediaBrowser.Server.Implementations/Session/SessionManager.cs index 8bf39fd6b9..7112c2357d 100644 --- a/MediaBrowser.Server.Implementations/Session/SessionManager.cs +++ b/MediaBrowser.Server.Implementations/Session/SessionManager.cs @@ -307,21 +307,21 @@ namespace MediaBrowser.Server.Implementations.Session /// The library item. private void UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem) { - var runtimeTicks = libraryItem == null ? null : libraryItem.RunTimeTicks; - if (string.IsNullOrWhiteSpace(info.MediaSourceId)) { info.MediaSourceId = info.ItemId; } - if (!string.Equals(info.ItemId, info.MediaSourceId) && - !string.IsNullOrWhiteSpace(info.MediaSourceId)) + if (!string.IsNullOrWhiteSpace(info.ItemId) && info.Item == null && libraryItem != null) { - runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks; - } + var runtimeTicks = libraryItem.RunTimeTicks; + + if (!string.Equals(info.ItemId, info.MediaSourceId) && + !string.IsNullOrWhiteSpace(info.MediaSourceId)) + { + runtimeTicks = _libraryManager.GetItemById(new Guid(info.MediaSourceId)).RunTimeTicks; + } - if (!string.IsNullOrWhiteSpace(info.ItemId) && libraryItem != null) - { var current = session.NowPlayingItem; if (current == null || !string.Equals(current.Id, info.ItemId, StringComparison.OrdinalIgnoreCase)) @@ -711,7 +711,7 @@ namespace MediaBrowser.Server.Implementations.Session info.MediaSourceId = info.ItemId; } - if (!string.IsNullOrWhiteSpace(info.ItemId) && libraryItem != null) + if (!string.IsNullOrWhiteSpace(info.ItemId) && info.Item == null && libraryItem != null) { var current = session.NowPlayingItem; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncConfig.cs b/MediaBrowser.Server.Implementations/Sync/SyncConfig.cs new file mode 100644 index 0000000000..52c7743307 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Sync/SyncConfig.cs @@ -0,0 +1,29 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Sync; +using System.Collections.Generic; + +namespace MediaBrowser.Server.Implementations.Sync +{ + public class SyncConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + return new List + { + new ConfigurationStore + { + ConfigurationType = typeof(SyncOptions), + Key = "sync" + } + }; + } + } + + public static class SyncExtensions + { + public static SyncOptions GetSyncOptions(this IConfigurationManager config) + { + return config.GetConfiguration("sync"); + } + } +} diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index 8053a30360..02c5aedd57 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -1,4 +1,7 @@ -using MediaBrowser.Common.Progress; +using System.Globalization; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.Progress; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; @@ -16,6 +19,7 @@ using MediaBrowser.Model.Sync; using MoreLinq; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -32,8 +36,10 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly ITVSeriesManager _tvSeriesManager; private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; + private readonly IConfigurationManager _config; + private readonly IFileSystem _fileSystem; - public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder) + public SyncJobProcessor(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem) { _libraryManager = libraryManager; _syncRepo = syncRepo; @@ -43,6 +49,8 @@ namespace MediaBrowser.Server.Implementations.Sync _tvSeriesManager = tvSeriesManager; _mediaEncoder = mediaEncoder; _subtitleEncoder = subtitleEncoder; + _config = config; + _fileSystem = fileSystem; } public async Task EnsureJobItems(SyncJob job) @@ -329,6 +337,13 @@ namespace MediaBrowser.Server.Implementations.Sync }); await SyncJobItems(result.Items, true, progress, cancellationToken).ConfigureAwait(false); + + CleanDeadSyncFiles(); + } + + private void CleanDeadSyncFiles() + { + // TODO } public async Task SyncJobItems(SyncJobItem[] items, bool enableConversion, IProgress progress, CancellationToken cancellationToken) @@ -416,24 +431,36 @@ namespace MediaBrowser.Server.Implementations.Sync var streamInfo = new StreamBuilder().BuildVideoItem(options); var mediaSource = streamInfo.MediaSource; + var externalSubs = streamInfo.GetExternalSubtitles("dummy", false); + var hasExternalSubs = externalSubs.Count > 0; + + var requiresConversion = streamInfo.PlayMethod == PlayMethod.Transcode || hasExternalSubs; + + if (requiresConversion && !enableConversion) + { + return; + } jobItem.MediaSourceId = streamInfo.MediaSourceId; + jobItem.TemporaryPath = GetTemporaryPath(jobItem); + + if (requiresConversion) + { + jobItem.Status = SyncJobItemStatus.Converting; + } if (streamInfo.PlayMethod == PlayMethod.Transcode) { - if (!enableConversion) - { - return; - } - - jobItem.Status = SyncJobItemStatus.Converting; - jobItem.RequiresConversion = true; + // Save the job item now since conversion could take a while await _syncRepo.Update(jobItem).ConfigureAwait(false); try { - jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, profile), progress, - cancellationToken); + jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, profile) + { + OutputDirectory = jobItem.TemporaryPath + + }, progress, cancellationToken); } catch (OperationCanceledException) { @@ -445,18 +472,16 @@ namespace MediaBrowser.Server.Implementations.Sync _logger.ErrorException("Error during sync transcoding", ex); } - await ConvertSubtitles(jobItem, streamInfo, cancellationToken).ConfigureAwait(false); - if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncRepo.Update(jobItem).ConfigureAwait(false); return; } + + jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, true).ConfigureAwait(false); } else { - jobItem.RequiresConversion = false; - if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; @@ -469,6 +494,16 @@ namespace MediaBrowser.Server.Implementations.Sync { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } + + jobItem.MediaSource = mediaSource; + } + + if (hasExternalSubs) + { + // Save the job item now since conversion could take a while + await _syncRepo.Update(jobItem).ConfigureAwait(false); + + await ConvertSubtitles(jobItem, externalSubs, streamInfo, cancellationToken).ConfigureAwait(false); } jobItem.Progress = 50; @@ -476,18 +511,72 @@ namespace MediaBrowser.Server.Implementations.Sync await _syncRepo.Update(jobItem).ConfigureAwait(false); } - private async Task ConvertSubtitles(SyncJobItem jobItem, StreamInfo streamInfo, CancellationToken cancellationToken) + private async Task ConvertSubtitles(SyncJobItem jobItem, + IEnumerable subtitles, + StreamInfo streamInfo, + CancellationToken cancellationToken) { - if (streamInfo.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External || !streamInfo.SubtitleStreamIndex.HasValue) + var files = new List(); + + var mediaStreams = jobItem.MediaSource.MediaStreams + .Where(i => i.Type != MediaStreamType.Subtitle || !i.IsExternal) + .ToList(); + + var startingIndex = mediaStreams.Count == 0 ? + 0 : + (mediaStreams.Select(i => i.Index).Max() + 1); + + foreach (var subtitle in subtitles) { - // Nothing to do - return; + var fileInfo = await ConvertSubtitles(jobItem.TemporaryPath, streamInfo, subtitle, cancellationToken).ConfigureAwait(false); + + // Reset this to a value that will be based on the output media + fileInfo.Index = startingIndex; + files.Add(fileInfo); + + mediaStreams.Add(new MediaStream + { + Index = startingIndex, + Codec = subtitle.Format, + IsForced = subtitle.IsForced, + IsExternal = true, + Language = subtitle.Language, + Path = fileInfo.Path + }); + + startingIndex++; } - //using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, streamInfo.SubtitleStreamIndex.Value, streamInfo.SubtitleFormat, 0, null, cancellationToken).ConfigureAwait(false)) - //{ + jobItem.AdditionalFiles.AddRange(files); - //} + jobItem.MediaSource.MediaStreams = mediaStreams; + } + + private async Task ConvertSubtitles(string temporaryPath, StreamInfo streamInfo, SubtitleStreamInfo subtitleStreamInfo, CancellationToken cancellationToken) + { + var subtitleStreamIndex = subtitleStreamInfo.Index; + + var filename = Guid.NewGuid() + "." + subtitleStreamInfo.Format.ToLower(); + + var path = Path.Combine(temporaryPath, filename); + + Directory.CreateDirectory(Path.GetDirectoryName(path)); + + using (var stream = await _subtitleEncoder.GetSubtitles(streamInfo.ItemId, streamInfo.MediaSourceId, subtitleStreamIndex, subtitleStreamInfo.Format, 0, null, cancellationToken).ConfigureAwait(false)) + { + using (var fs = _fileSystem.GetFileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, true)) + { + await stream.CopyToAsync(fs, StreamDefaults.DefaultCopyToBufferSize, cancellationToken).ConfigureAwait(false); + } + } + + return new ItemFileInfo + { + Name = Path.GetFileName(path), + Path = path, + Type = ItemFileType.Subtitles, + Index = subtitleStreamIndex + }; } private async Task Sync(SyncJobItem jobItem, Audio item, User user, DeviceProfile profile, bool enableConversion, IProgress progress, CancellationToken cancellationToken) @@ -505,6 +594,7 @@ namespace MediaBrowser.Server.Implementations.Sync var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; + jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (streamInfo.PlayMethod == PlayMethod.Transcode) { @@ -514,12 +604,15 @@ namespace MediaBrowser.Server.Implementations.Sync } jobItem.Status = SyncJobItemStatus.Converting; - jobItem.RequiresConversion = true; await _syncRepo.Update(jobItem).ConfigureAwait(false); try { - jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile), progress, cancellationToken); + jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, profile) + { + OutputDirectory = jobItem.TemporaryPath + + }, progress, cancellationToken); } catch (OperationCanceledException) { @@ -536,11 +629,11 @@ namespace MediaBrowser.Server.Implementations.Sync await _syncRepo.Update(jobItem).ConfigureAwait(false); return; } + + jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, false).ConfigureAwait(false); } else { - jobItem.RequiresConversion = false; - if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; @@ -553,6 +646,8 @@ namespace MediaBrowser.Server.Implementations.Sync { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } + + jobItem.MediaSource = mediaSource; } jobItem.Progress = 50; @@ -583,5 +678,65 @@ namespace MediaBrowser.Server.Implementations.Sync // TODO: Download return mediaSource.Path; } + + private string GetTemporaryPath(SyncJobItem jobItem) + { + var basePath = _config.GetSyncOptions().TemporaryPath; + + if (string.IsNullOrWhiteSpace(basePath)) + { + basePath = Path.Combine(_config.CommonApplicationPaths.ProgramDataPath, "sync"); + } + + return Path.Combine(basePath, jobItem.JobId, jobItem.Id); + } + + private async Task GetEncodedMediaSource(string path, User user, bool isVideo) + { + var item = _libraryManager.ResolvePath(new FileInfo(path)); + + await item.RefreshMetadata(CancellationToken.None).ConfigureAwait(false); + + var hasMediaSources = item as IHasMediaSources; + + var mediaSources = hasMediaSources.GetMediaSources(false).ToList(); + + var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference) + ? new string[] { } + : new[] { user.Configuration.AudioLanguagePreference }; + + var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference) + ? new List { } + : new List { user.Configuration.SubtitleLanguagePreference }; + + foreach (var source in mediaSources) + { + if (isVideo) + { + source.DefaultAudioStreamIndex = + MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack); + + var defaultAudioIndex = source.DefaultAudioStreamIndex; + var audioLangage = defaultAudioIndex == null + ? null + : source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault(); + + source.DefaultAudioStreamIndex = + MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams, preferredSubs, user.Configuration.SubtitleMode, audioLangage); + } + else + { + var audio = source.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio); + + if (audio != null) + { + source.DefaultAudioStreamIndex = audio.Index; + } + + } + } + + return mediaSources.FirstOrDefault(); + } } } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index bc6446d4e7..b8d884cee5 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Channels; @@ -13,6 +14,7 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Sync; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; @@ -41,10 +43,11 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly Func _mediaEncoder; private readonly IFileSystem _fileSystem; private readonly Func _subtitleEncoder; + private readonly IConfigurationManager _config; private ISyncProvider[] _providers = { }; - public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func mediaEncoder, IFileSystem fileSystem, Func subtitleEncoder) + public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func dtoService, IApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func mediaEncoder, IFileSystem fileSystem, Func subtitleEncoder, IConfigurationManager config) { _libraryManager = libraryManager; _repo = repo; @@ -57,6 +60,7 @@ namespace MediaBrowser.Server.Implementations.Sync _mediaEncoder = mediaEncoder; _fileSystem = fileSystem; _subtitleEncoder = subtitleEncoder; + _config = config; } public void AddParts(IEnumerable providers) @@ -66,7 +70,7 @@ namespace MediaBrowser.Server.Implementations.Sync public async Task CreateJob(SyncJobRequest request) { - var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder()); + var processor = GetSyncJobProcessor(); var user = _userManager.GetUserById(request.UserId); @@ -129,7 +133,7 @@ namespace MediaBrowser.Server.Implementations.Sync await _repo.Create(job).ConfigureAwait(false); await processor.EnsureJobItems(job).ConfigureAwait(false); - + // If it already has a converting status then is must have been aborted during conversion var jobItemsResult = _repo.GetJobItems(new SyncJobItemQuery { @@ -180,7 +184,7 @@ namespace MediaBrowser.Server.Implementations.Sync if (item == null) { - var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder()); + var processor = GetSyncJobProcessor(); var user = _userManager.GetUserById(job.UserId); @@ -408,11 +412,14 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.Status = SyncJobItemStatus.Synced; jobItem.Progress = 100; - if (jobItem.RequiresConversion) + if (!string.IsNullOrWhiteSpace(jobItem.TemporaryPath)) { try { - _fileSystem.DeleteFile(jobItem.OutputPath); + _fileSystem.DeleteDirectory(jobItem.TemporaryPath, true); + } + catch (DirectoryNotFoundException) + { } catch (Exception ex) { @@ -422,11 +429,16 @@ namespace MediaBrowser.Server.Implementations.Sync await _repo.Update(jobItem).ConfigureAwait(false); - var processor = new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder()); + var processor = GetSyncJobProcessor(); await processor.UpdateJobStatus(jobItem.JobId).ConfigureAwait(false); } + private SyncJobProcessor GetSyncJobProcessor() + { + return new SyncJobProcessor(_libraryManager, _repo, this, _logger, _userManager, _tvSeriesManager, _mediaEncoder(), _subtitleEncoder(), _config, _fileSystem); + } + public SyncJobItem GetJobItem(string id) { return _repo.GetJobItem(id); @@ -455,7 +467,15 @@ namespace MediaBrowser.Server.Implementations.Sync SyncJobId = jobItem.JobId, SyncJobItemId = jobItem.Id, ServerId = _appHost.SystemId, - UserId = job.UserId + UserId = job.UserId, + AdditionalFiles = jobItem.AdditionalFiles.Select(i => new ItemFileInfo + { + ImageType = i.ImageType, + Name = i.Name, + Type = i.Type, + Index = i.Index + + }).ToList() }; var dtoOptions = new DtoOptions(); @@ -472,14 +492,11 @@ namespace MediaBrowser.Server.Implementations.Sync syncedItem.Item = _dtoService().GetBaseItemDto(libraryItem, dtoOptions); - // TODO: this should be the media source of the transcoded output - syncedItem.Item.MediaSources = syncedItem.Item.MediaSources - .Where(i => string.Equals(i.Id, jobItem.MediaSourceId)) - .ToList(); - var mediaSource = syncedItem.Item.MediaSources .FirstOrDefault(i => string.Equals(i.Id, jobItem.MediaSourceId)); + syncedItem.Item.MediaSources = new List(); + // This will be null for items that are not audio/video if (mediaSource == null) { @@ -488,6 +505,7 @@ namespace MediaBrowser.Server.Implementations.Sync else { syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); + syncedItem.Item.MediaSources.Add(mediaSource); } return syncedItem; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index 151860d84c..ae91437104 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -1,7 +1,9 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; +using MediaBrowser.Model.Dto; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Sync; using MediaBrowser.Server.Implementations.Persistence; using System; @@ -28,15 +30,18 @@ namespace MediaBrowser.Server.Implementations.Sync private IDbCommand _saveJobCommand; private IDbCommand _saveJobItemCommand; - public SyncRepository(ILogger logger, IServerApplicationPaths appPaths) + private readonly IJsonSerializer _json; + + public SyncRepository(ILogger logger, IServerApplicationPaths appPaths, IJsonSerializer json) { _logger = logger; _appPaths = appPaths; + _json = json; } public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "sync11.db"); + var dbFile = Path.Combine(_appPaths.DataPath, "sync12.db"); _connection = await SqliteExtensions.ConnectToDb(dbFile, _logger).ConfigureAwait(false); @@ -45,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.Sync "create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Quality TEXT NOT NULL, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)", "create index if not exists idx_SyncJobs on SyncJobs(Id)", - "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, ItemName TEXT, MediaSourceId TEXT, JobId TEXT, RequiresConversion BIT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT)", + "create table if not exists SyncJobItems (Id GUID PRIMARY KEY, ItemId TEXT, ItemName TEXT, MediaSourceId TEXT, JobId TEXT, TemporaryPath TEXT, OutputPath TEXT, Status TEXT, TargetId TEXT, DateCreated DateTime, Progress FLOAT, AdditionalFiles TEXT, MediaSource TEXT)", "create index if not exists idx_SyncJobItems on SyncJobs(Id)", //pragmas @@ -90,23 +95,25 @@ namespace MediaBrowser.Server.Implementations.Sync _saveJobCommand.Parameters.Add(_saveJobCommand, "@ItemCount"); _saveJobItemCommand = _connection.CreateCommand(); - _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, RequiresConversion, OutputPath, Status, TargetId, DateCreated, Progress) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @RequiresConversion, @OutputPath, @Status, @TargetId, @DateCreated, @Progress)"; + _saveJobItemCommand.CommandText = "replace into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource)"; _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@Id"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@ItemId"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@ItemName"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@MediaSourceId"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@JobId"); - _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@RequiresConversion"); + _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@TemporaryPath"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@OutputPath"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@Status"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@TargetId"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@DateCreated"); _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@Progress"); + _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@AdditionalFiles"); + _saveJobItemCommand.Parameters.Add(_saveJobItemCommand, "@MediaSource"); } private const string BaseJobSelectText = "select Id, TargetId, Name, Quality, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs"; - private const string BaseJobItemSelectText = "select Id, ItemId, ItemName, MediaSourceId, JobId, RequiresConversion, OutputPath, Status, TargetId, DateCreated, Progress from SyncJobItems"; + private const string BaseJobItemSelectText = "select Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource from SyncJobItems"; public SyncJob GetJob(string id) { @@ -557,12 +564,14 @@ namespace MediaBrowser.Server.Implementations.Sync _saveJobItemCommand.GetParameter(index++).Value = jobItem.ItemName; _saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSourceId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.JobId; - _saveJobItemCommand.GetParameter(index++).Value = jobItem.RequiresConversion; + _saveJobItemCommand.GetParameter(index++).Value = jobItem.TemporaryPath; _saveJobItemCommand.GetParameter(index++).Value = jobItem.OutputPath; _saveJobItemCommand.GetParameter(index++).Value = jobItem.Status.ToString(); _saveJobItemCommand.GetParameter(index++).Value = jobItem.TargetId; _saveJobItemCommand.GetParameter(index++).Value = jobItem.DateCreated; _saveJobItemCommand.GetParameter(index++).Value = jobItem.Progress; + _saveJobItemCommand.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles); + _saveJobItemCommand.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource); _saveJobItemCommand.Transaction = transaction; @@ -620,8 +629,11 @@ namespace MediaBrowser.Server.Implementations.Sync } info.JobId = reader.GetString(4); - info.RequiresConversion = reader.GetBoolean(5); + if (!reader.IsDBNull(5)) + { + info.TemporaryPath = reader.GetString(5); + } if (!reader.IsDBNull(6)) { info.OutputPath = reader.GetString(6); @@ -641,6 +653,26 @@ namespace MediaBrowser.Server.Implementations.Sync info.Progress = reader.GetDouble(10); } + if (!reader.IsDBNull(11)) + { + var json = reader.GetString(11); + + if (!string.IsNullOrWhiteSpace(json)) + { + info.AdditionalFiles = _json.DeserializeFromString>(json); + } + } + + if (!reader.IsDBNull(12)) + { + var json = reader.GetString(12); + + if (!string.IsNullOrWhiteSpace(json)) + { + info.MediaSource = _json.DeserializeFromString(json); + } + } + return info; } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs index 88b761a7da..4edebb60f1 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncScheduledTask.cs @@ -1,4 +1,6 @@ -using MediaBrowser.Common.ScheduledTasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; +using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Sync; @@ -21,8 +23,10 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly ITVSeriesManager _tvSeriesManager; private readonly IMediaEncoder _mediaEncoder; private readonly ISubtitleEncoder _subtitleEncoder; + private readonly IConfigurationManager _config; + private readonly IFileSystem _fileSystem; - public SyncScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder) + public SyncScheduledTask(ILibraryManager libraryManager, ISyncRepository syncRepo, ISyncManager syncManager, ILogger logger, IUserManager userManager, ITVSeriesManager tvSeriesManager, IMediaEncoder mediaEncoder, ISubtitleEncoder subtitleEncoder, IConfigurationManager config, IFileSystem fileSystem) { _libraryManager = libraryManager; _syncRepo = syncRepo; @@ -32,6 +36,8 @@ namespace MediaBrowser.Server.Implementations.Sync _tvSeriesManager = tvSeriesManager; _mediaEncoder = mediaEncoder; _subtitleEncoder = subtitleEncoder; + _config = config; + _fileSystem = fileSystem; } public string Name @@ -54,7 +60,7 @@ namespace MediaBrowser.Server.Implementations.Sync public Task Execute(CancellationToken cancellationToken, IProgress progress) { - return new SyncJobProcessor(_libraryManager, _syncRepo, _syncManager, _logger, _userManager, _tvSeriesManager, _mediaEncoder, _subtitleEncoder).Sync(progress, + return new SyncJobProcessor(_libraryManager, _syncRepo, _syncManager, _logger, _userManager, _tvSeriesManager, _mediaEncoder, _subtitleEncoder, _config, _fileSystem).Sync(progress, cancellationToken); } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 65d3b009f9..f7ff5eef15 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -483,7 +483,7 @@ namespace MediaBrowser.Server.Startup.Common TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager); RegisterSingleInstance(TVSeriesManager); - SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder); + SyncManager = new SyncManager(LibraryManager, SyncRepository, ImageProcessor, LogManager.GetLogger("SyncManager"), UserManager, () => DtoService, this, TVSeriesManager, () => MediaEncoder, FileSystemManager, () => SubtitleEncoder, ServerConfigurationManager); RegisterSingleInstance(SyncManager); DtoService = new DtoService(Logger, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this); @@ -663,7 +663,7 @@ namespace MediaBrowser.Server.Startup.Common private async Task GetSyncRepository() { - var repo = new SyncRepository(LogManager.GetLogger("SyncRepository"), ServerConfigurationManager.ApplicationPaths); + var repo = new SyncRepository(LogManager.GetLogger("SyncRepository"), ServerConfigurationManager.ApplicationPaths, JsonSerializer); await repo.Initialize().ConfigureAwait(false); diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index b2e8ce2072..2f875f536d 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.541 + 3.0.543 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 06fbc750fb..7224a73cb8 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.541 + 3.0.543 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index c11f886c15..f5a3a3de0f 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.541 + 3.0.543 MediaBrowser.Model - Signed Edition Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index d183c9931a..e3cbe9d040 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.541 + 3.0.543 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - +