diff options
| author | Luke <luke.pulverenti@gmail.com> | 2015-04-14 00:43:41 -0400 |
|---|---|---|
| committer | Luke <luke.pulverenti@gmail.com> | 2015-04-14 00:43:41 -0400 |
| commit | 935de313d58c7a7ba792345c16cfd1c1aad09a78 (patch) | |
| tree | 2e9334986de5864b00d4901f031b5de6a970305e /MediaBrowser.Server.Implementations/Sync | |
| parent | 71a4f2761e784513ae2f3dda03aa549903808ebb (diff) | |
| parent | bd253399c2f1913c544c93fd6927dee37f8add2f (diff) | |
Merge pull request #1079 from MediaBrowser/dev
3.0.5582.0
Diffstat (limited to 'MediaBrowser.Server.Implementations/Sync')
9 files changed, 227 insertions, 102 deletions
diff --git a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs index 99d7582333..7b1fa4dec2 100644 --- a/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/AppSyncProvider.cs @@ -44,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Sync public string Name { - get { return "App Sync"; } + get { return "Mobile Sync"; } } public IEnumerable<SyncTarget> GetAllSyncTargets() diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs index 73400f8345..f881a2055c 100644 --- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs +++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs @@ -195,17 +195,39 @@ namespace MediaBrowser.Server.Implementations.Sync } }; - var maxAudioChannels = supportsAc3 || supportsDca ? "5" : "2"; codecProfiles.Add(new CodecProfile { Type = CodecType.VideoAudio, + Codec = "ac3", Conditions = new[] { new ProfileCondition { Condition = ProfileConditionType.LessThanEqual, Property = ProfileConditionValue.AudioChannels, - Value = maxAudioChannels, + Value = "5", + IsRequired = true + }, + new ProfileCondition + { + Condition = ProfileConditionType.Equals, + Property = ProfileConditionValue.IsSecondaryAudio, + Value = "false", + IsRequired = false + } + } + }); + codecProfiles.Add(new CodecProfile + { + Type = CodecType.VideoAudio, + Codec = "ac3", + Conditions = new[] + { + new ProfileCondition + { + Condition = ProfileConditionType.LessThanEqual, + Property = ProfileConditionValue.AudioChannels, + Value = "2", IsRequired = true }, new ProfileCondition diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index 26413c033e..1a8b55a257 100644 --- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs @@ -1,7 +1,8 @@ -using System.Globalization; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.IO; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; +using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -10,12 +11,14 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Sync; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; +using Patterns.IO; namespace MediaBrowser.Server.Implementations.Sync { @@ -25,13 +28,18 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IServerApplicationHost _appHost; private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private readonly IConfigurationManager _config; - public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost, IFileSystem fileSystem) + public const string PathSeparatorString = "/"; + public const char PathSeparatorChar = '/'; + + public MediaSync(ILogger logger, ISyncManager syncManager, IServerApplicationHost appHost, IFileSystem fileSystem, IConfigurationManager config) { _logger = logger; _syncManager = syncManager; _appHost = appHost; _fileSystem = fileSystem; + _config = config; } public async Task Sync(IServerSyncProvider provider, @@ -67,7 +75,24 @@ namespace MediaBrowser.Server.Implementations.Sync SyncTarget target, CancellationToken cancellationToken) { - var jobItemIds = await dataProvider.GetSyncJobItemIds(target, serverId).ConfigureAwait(false); + var localItems = await dataProvider.GetLocalItems(target, serverId).ConfigureAwait(false); + var remoteFiles = await provider.GetFiles(new FileQuery(), target, cancellationToken).ConfigureAwait(false); + var remoteIds = remoteFiles.Items.Select(i => i.Id).ToList(); + + var jobItemIds = new List<string>(); + + foreach (var localItem in localItems) + { + // TODO: Remove this after a while + if (string.IsNullOrWhiteSpace(localItem.FileId)) + { + jobItemIds.Add(localItem.SyncJobItemId); + } + else if (remoteIds.Contains(localItem.FileId, StringComparer.OrdinalIgnoreCase)) + { + jobItemIds.Add(localItem.SyncJobItemId); + } + } var result = await _syncManager.SyncData(new SyncDataRequest { @@ -152,12 +177,14 @@ namespace MediaBrowser.Server.Implementations.Sync var transferSuccess = false; Exception transferException = null; + var options = _config.GetSyncOptions(); + try { var fileTransferProgress = new ActionableProgress<double>(); fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92)); - var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath, target, fileTransferProgress, cancellationToken).ConfigureAwait(false); + var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath.Split(PathSeparatorChar), target, options, fileTransferProgress, cancellationToken).ConfigureAwait(false); if (localItem.Item.MediaSources != null) { @@ -171,6 +198,8 @@ namespace MediaBrowser.Server.Implementations.Sync } } + localItem.FileId = sendFileResult.Id; + // Create db record await dataProvider.AddOrUpdate(target, localItem).ConfigureAwait(false); @@ -179,7 +208,7 @@ namespace MediaBrowser.Server.Implementations.Sync var mediaSource = localItem.Item.MediaSources.FirstOrDefault(); if (mediaSource != null) { - await SendSubtitles(localItem, mediaSource, provider, dataProvider, target, cancellationToken).ConfigureAwait(false); + await SendSubtitles(localItem, mediaSource, provider, dataProvider, target, options, cancellationToken).ConfigureAwait(false); } } @@ -207,7 +236,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - private async Task SendSubtitles(LocalItem localItem, MediaSourceInfo mediaSource, IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, CancellationToken cancellationToken) + private async Task SendSubtitles(LocalItem localItem, MediaSourceInfo mediaSource, IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, SyncOptions options, CancellationToken cancellationToken) { var failedSubtitles = new List<MediaStream>(); var requiresSave = false; @@ -219,13 +248,13 @@ namespace MediaBrowser.Server.Implementations.Sync try { var remotePath = GetRemoteSubtitlePath(localItem, mediaStream, provider, target); - var sendFileResult = await SendFile(provider, mediaStream.Path, remotePath, target, new Progress<double>(), cancellationToken).ConfigureAwait(false); + var sendFileResult = await SendFile(provider, mediaStream.Path, remotePath, target, options, new Progress<double>(), cancellationToken).ConfigureAwait(false); // This is the path that will be used when talking to the provider - mediaStream.ExternalId = remotePath; + mediaStream.ExternalId = sendFileResult.Id; // Keep track of all additional files for cleanup later. - localItem.AdditionalFiles.Add(remotePath); + localItem.AdditionalFiles.Add(sendFileResult.Id); // This is the public path clients will use mediaStream.Path = sendFileResult.Path; @@ -250,17 +279,15 @@ namespace MediaBrowser.Server.Implementations.Sync } } - private string GetRemoteSubtitlePath(LocalItem item, MediaStream stream, IServerSyncProvider provider, SyncTarget target) + private string[] GetRemoteSubtitlePath(LocalItem item, MediaStream stream, IServerSyncProvider provider, SyncTarget target) { - var path = item.LocalPath; - var filename = GetSubtitleSaveFileName(item, stream.Language, stream.IsForced) + "." + stream.Codec.ToLower(); - var parentPath = provider.GetParentDirectoryPath(path, target); - - path = Path.Combine(parentPath, filename); + var pathParts = item.LocalPath.Split(PathSeparatorChar); + var list = pathParts.Take(pathParts.Length - 1).ToList(); + list.Add(filename); - return path; + return list.ToArray(); } private string GetSubtitleSaveFileName(LocalItem item, string language, bool isForced) @@ -294,12 +321,16 @@ namespace MediaBrowser.Server.Implementations.Sync foreach (var localItem in localItems) { var files = localItem.AdditionalFiles.ToList(); - files.Insert(0, localItem.LocalPath); + + // TODO: Remove this. Have to check it for now since this is a new property + if (!string.IsNullOrWhiteSpace(localItem.FileId)) + { + files.Insert(0, localItem.FileId); + } foreach (var file in files) { _logger.Debug("Removing {0} from {1}.", file, target.Name); - await provider.DeleteFile(file, target, cancellationToken).ConfigureAwait(false); } @@ -307,12 +338,19 @@ namespace MediaBrowser.Server.Implementations.Sync } } - private async Task<SyncedFileInfo> SendFile(IServerSyncProvider provider, string inputPath, string remotePath, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken) + private async Task<SyncedFileInfo> SendFile(IServerSyncProvider provider, string inputPath, string[] pathParts, SyncTarget target, SyncOptions options, IProgress<double> progress, CancellationToken cancellationToken) { - _logger.Debug("Sending {0} to {1}. Remote path: {2}", inputPath, provider.Name, remotePath); - using (var stream = _fileSystem.GetFileStream(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) + _logger.Debug("Sending {0} to {1}. Remote path: {2}", inputPath, provider.Name, string.Join("/", pathParts)); + using (var fileStream = _fileSystem.GetFileStream(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read, true)) { - return await provider.SendFile(stream, remotePath, target, progress, cancellationToken).ConfigureAwait(false); + Stream stream = fileStream; + + if (options.UploadSpeedLimitBytes > 0 && provider is IRemoteSyncProvider) + { + stream = new ThrottledStream(stream, options.UploadSpeedLimitBytes); + } + + return await provider.SendFile(stream, pathParts, target, progress, cancellationToken).ConfigureAwait(false); } } @@ -336,7 +374,7 @@ namespace MediaBrowser.Server.Implementations.Sync var path = GetDirectoryPath(provider, job, syncedItem, libraryItem, serverName); path.Add(GetLocalFileName(provider, libraryItem, originalFileName)); - var localPath = provider.GetFullPath(path, target); + var localPath = string.Join(PathSeparatorString, path.ToArray()); foreach (var mediaSource in libraryItem.MediaSources) { diff --git a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs index a8bc24c2a1..6f09e96f0f 100644 --- a/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MultiProviderSync.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; @@ -18,13 +19,15 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IServerApplicationHost _appHost; private readonly ILogger _logger; private readonly IFileSystem _fileSystem; + private readonly IConfigurationManager _config; - public MultiProviderSync(SyncManager syncManager, IServerApplicationHost appHost, ILogger logger, IFileSystem fileSystem) + public MultiProviderSync(SyncManager syncManager, IServerApplicationHost appHost, ILogger logger, IFileSystem fileSystem, IConfigurationManager config) { _syncManager = syncManager; _appHost = appHost; _logger = logger; _fileSystem = fileSystem; + _config = config; } public async Task Sync(IEnumerable<IServerSyncProvider> providers, IProgress<double> progress, CancellationToken cancellationToken) @@ -56,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.Sync var dataProvider = _syncManager.GetDataProvider(target.Item1, target.Item2); - await new MediaSync(_logger, _syncManager, _appHost, _fileSystem) + await new MediaSync(_logger, _syncManager, _appHost, _fileSystem, _config) .Sync(target.Item1, dataProvider, target.Item2, innerProgress, cancellationToken) .ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs index 148602bd42..9477a23f19 100644 --- a/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs +++ b/MediaBrowser.Server.Implementations/Sync/ServerSyncScheduledTask.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Common.IO; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.IO; using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; @@ -17,13 +18,15 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly ILogger _logger; private readonly IFileSystem _fileSystem; private readonly IServerApplicationHost _appHost; + private readonly IConfigurationManager _config; - public ServerSyncScheduledTask(ISyncManager syncManager, ILogger logger, IFileSystem fileSystem, IServerApplicationHost appHost) + public ServerSyncScheduledTask(ISyncManager syncManager, ILogger logger, IFileSystem fileSystem, IServerApplicationHost appHost, IConfigurationManager config) { _syncManager = syncManager; _logger = logger; _fileSystem = fileSystem; _appHost = appHost; + _config = config; } public string Name @@ -46,7 +49,7 @@ namespace MediaBrowser.Server.Implementations.Sync public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { - return new MultiProviderSync((SyncManager)_syncManager, _appHost, _logger, _fileSystem) + return new MultiProviderSync((SyncManager)_syncManager, _appHost, _logger, _fileSystem, _config) .Sync(ServerSyncProviders, progress, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index 185c3464ea..fd4092974e 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -456,17 +456,18 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.Progress = 0; + var syncOptions = _config.GetSyncOptions(); var user = _userManager.GetUserById(job.UserId); var video = item as Video; if (video != null) { - await Sync(jobItem, job, video, user, enableConversion, progress, cancellationToken).ConfigureAwait(false); + await Sync(jobItem, job, video, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Audio) { - await Sync(jobItem, job, (Audio)item, user, enableConversion, progress, cancellationToken).ConfigureAwait(false); + await Sync(jobItem, job, (Audio)item, user, enableConversion, syncOptions, progress, cancellationToken).ConfigureAwait(false); } else if (item is Photo) @@ -480,7 +481,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken) + private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetVideoOptions(jobItem, job); var conversionOptions = new VideoOptions @@ -493,7 +494,7 @@ namespace MediaBrowser.Server.Implementations.Sync conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); - var streamInfo = new StreamBuilder().BuildVideoItem(conversionOptions); + var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions); var mediaSource = streamInfo.MediaSource; // No sense creating external subs if we're already burning one into the video @@ -542,7 +543,9 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { - OutputDirectory = jobItem.TemporaryPath + OutputDirectory = jobItem.TemporaryPath, + CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit, + ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding }, innerProgress, cancellationToken); } @@ -677,7 +680,7 @@ namespace MediaBrowser.Server.Implementations.Sync private const int DatabaseProgressUpdateIntervalSeconds = 2; - private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken) + private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetAudioOptions(jobItem, job); var conversionOptions = new AudioOptions @@ -690,7 +693,7 @@ namespace MediaBrowser.Server.Implementations.Sync conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); - var streamInfo = new StreamBuilder().BuildAudioItem(conversionOptions); + var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; @@ -725,7 +728,8 @@ namespace MediaBrowser.Server.Implementations.Sync jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { - OutputDirectory = jobItem.TemporaryPath + OutputDirectory = jobItem.TemporaryPath, + CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit }, innerProgress, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index a39a2b1cdd..6f0310e3c3 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -512,12 +512,7 @@ namespace MediaBrowser.Server.Implementations.Sync var video = item as Video; if (video != null) { - if (video.VideoType == VideoType.Iso) - { - return false; - } - - if (video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.HdDvd) + if (video.VideoType == VideoType.Iso || video.VideoType == VideoType.BluRay || video.VideoType == VideoType.Dvd || video.VideoType == VideoType.HdDvd) { return false; } @@ -552,7 +547,7 @@ namespace MediaBrowser.Server.Implementations.Sync } } - if (item is LiveTvChannel || item is IChannelItem || item is ILiveTvRecording) + if (item is LiveTvChannel || item is IChannelItem) { return false; } @@ -566,7 +561,7 @@ namespace MediaBrowser.Server.Implementations.Sync return true; } - return item.LocationType == LocationType.FileSystem || item is Season || item is ILiveTvRecording; + return item.LocationType == LocationType.FileSystem || item is Season; } private string GetDefaultName(BaseItem item) @@ -755,6 +750,9 @@ namespace MediaBrowser.Server.Implementations.Sync foreach (var jobItem in jobItemResult.Items) { + var requiresSaving = false; + var removeFromDevice = false; + if (request.LocalItemIds.Contains(jobItem.ItemId, StringComparer.OrdinalIgnoreCase)) { var job = _repo.GetJob(jobItem.JobId); @@ -764,13 +762,13 @@ namespace MediaBrowser.Server.Implementations.Sync { // Tell the device to remove it since it has been marked for removal _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.ItemId); - response.ItemIdsToRemove.Add(jobItem.ItemId); + removeFromDevice = true; } else if (user == null) { // Tell the device to remove it since the user is gone now _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.ItemId); - response.ItemIdsToRemove.Add(jobItem.ItemId); + removeFromDevice = true; } else if (job.UnwatchedOnly) { @@ -782,23 +780,41 @@ namespace MediaBrowser.Server.Implementations.Sync { // Tell the device to remove it since it has been played _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.ItemId); - response.ItemIdsToRemove.Add(jobItem.ItemId); + removeFromDevice = true; } } else { // Tell the device to remove it since it's no longer available _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.ItemId); - response.ItemIdsToRemove.Add(jobItem.ItemId); + removeFromDevice = true; } } } else { - _logger.Debug("Setting status to RemovedFromDevice for {0} because it is no longer on the device.", jobItem.ItemId); - // Content is no longer on the device - jobItem.Status = SyncJobItemStatus.RemovedFromDevice; + if (jobItem.IsMarkedForRemoval) + { + jobItem.Status = SyncJobItemStatus.RemovedFromDevice; + } + else + { + _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.ItemId); + jobItem.Status = SyncJobItemStatus.Queued; + } + requiresSaving = true; + } + + if (removeFromDevice) + { + response.ItemIdsToRemove.Add(jobItem.ItemId); + jobItem.IsMarkedForRemoval = true; + requiresSaving = true; + } + + if (requiresSaving) + { await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); } } @@ -842,6 +858,9 @@ namespace MediaBrowser.Server.Implementations.Sync foreach (var jobItem in jobItemResult.Items) { + var requiresSaving = false; + var removeFromDevice = false; + if (request.SyncJobItemIds.Contains(jobItem.Id, StringComparer.OrdinalIgnoreCase)) { var job = _repo.GetJob(jobItem.JobId); @@ -851,13 +870,13 @@ namespace MediaBrowser.Server.Implementations.Sync { // Tell the device to remove it since it has been marked for removal _logger.Debug("Adding ItemIdsToRemove {0} because IsMarkedForRemoval is set.", jobItem.Id); - response.ItemIdsToRemove.Add(jobItem.Id); + removeFromDevice = true; } else if (user == null) { // Tell the device to remove it since the user is gone now _logger.Debug("Adding ItemIdsToRemove {0} because the user is no longer valid.", jobItem.Id); - response.ItemIdsToRemove.Add(jobItem.Id); + removeFromDevice = true; } else if (job.UnwatchedOnly) { @@ -869,23 +888,41 @@ namespace MediaBrowser.Server.Implementations.Sync { // Tell the device to remove it since it has been played _logger.Debug("Adding ItemIdsToRemove {0} because it has been marked played.", jobItem.Id); - response.ItemIdsToRemove.Add(jobItem.Id); + removeFromDevice = true; } } else { // Tell the device to remove it since it's no longer available _logger.Debug("Adding ItemIdsToRemove {0} because it is no longer available.", jobItem.Id); - response.ItemIdsToRemove.Add(jobItem.Id); + removeFromDevice = true; } } } else { - _logger.Debug("Setting status to RemovedFromDevice for {0} because it is no longer on the device.", jobItem.Id); - // Content is no longer on the device - jobItem.Status = SyncJobItemStatus.RemovedFromDevice; + if (jobItem.IsMarkedForRemoval) + { + jobItem.Status = SyncJobItemStatus.RemovedFromDevice; + } + else + { + _logger.Debug("Setting status to Queued for {0} because it is no longer on the device.", jobItem.Id); + jobItem.Status = SyncJobItemStatus.Queued; + } + requiresSaving = true; + } + + if (removeFromDevice) + { + response.ItemIdsToRemove.Add(jobItem.Id); + jobItem.IsMarkedForRemoval = true; + requiresSaving = true; + } + + if (requiresSaving) + { await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); } } @@ -1168,13 +1205,18 @@ namespace MediaBrowser.Server.Implementations.Sync public IEnumerable<SyncQualityOption> GetQualityOptions(string targetId) { + return GetQualityOptions(targetId, null); + } + + public IEnumerable<SyncQualityOption> GetQualityOptions(string targetId, User user) + { foreach (var provider in _providers) { foreach (var target in GetSyncTargets(provider)) { if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase)) { - return GetQualityOptions(provider, target); + return GetQualityOptions(provider, target, user); } } } @@ -1182,12 +1224,19 @@ namespace MediaBrowser.Server.Implementations.Sync return new List<SyncQualityOption>(); } - private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target) + private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target, User user) { var hasQuality = provider as IHasSyncQuality; if (hasQuality != null) { - return hasQuality.GetQualityOptions(target); + var options = hasQuality.GetQualityOptions(target); + + if (user != null && !user.Policy.EnableSyncTranscoding) + { + options = options.Where(i => i.IsOriginalQuality); + } + + return options; } // Default options for providers that don't override @@ -1217,7 +1266,7 @@ namespace MediaBrowser.Server.Implementations.Sync }; } - public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId) + public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId, User user) { foreach (var provider in _providers) { @@ -1225,7 +1274,7 @@ namespace MediaBrowser.Server.Implementations.Sync { if (string.Equals(target.Id, targetId, StringComparison.OrdinalIgnoreCase)) { - return GetProfileOptions(provider, target); + return GetProfileOptions(provider, target, user); } } } @@ -1233,7 +1282,12 @@ namespace MediaBrowser.Server.Implementations.Sync return new List<SyncProfileOption>(); } - private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target) + public IEnumerable<SyncProfileOption> GetProfileOptions(string targetId) + { + return GetProfileOptions(targetId, null); + } + + private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target, User user) { var hasQuality = provider as IHasSyncQuality; if (hasQuality != null) @@ -1251,20 +1305,23 @@ namespace MediaBrowser.Server.Implementations.Sync EnableQualityOptions = false }); - list.Add(new SyncProfileOption + if (user == null || user.Policy.EnableSyncTranscoding) { - Name = "Baseline", - Id = "baseline", - Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio." - }); + list.Add(new SyncProfileOption + { + Name = "Baseline", + Id = "baseline", + Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio." + }); - list.Add(new SyncProfileOption - { - Name = "General", - Id = "general", - Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.", - IsDefault = true - }); + list.Add(new SyncProfileOption + { + Name = "General", + Id = "general", + Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.", + IsDefault = true + }); + } return list; } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs index 40d40d415e..f7f3207410 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs @@ -109,8 +109,13 @@ namespace MediaBrowser.Server.Implementations.Sync var dataProvider = _syncManager.GetDataProvider(provider, target); var localItem = await dataProvider.Get(target, openKeys[2]).ConfigureAwait(false); + var fileId = localItem.FileId; + if (string.IsNullOrWhiteSpace(fileId)) + { + } + var requiresDynamicAccess = (IHasDynamicAccess)provider; - var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(localItem.LocalPath, target, cancellationToken).ConfigureAwait(false); + var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(fileId, target, cancellationToken).ConfigureAwait(false); var mediaSource = localItem.Item.MediaSources.First(); mediaSource.LiveStreamId = Guid.NewGuid().ToString(); diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs index 3323ae1488..dc95ee316d 100644 --- a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs @@ -1,5 +1,4 @@ using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; @@ -12,6 +11,7 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Patterns.IO; namespace MediaBrowser.Server.Implementations.Sync { @@ -29,8 +29,6 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IApplicationPaths _appPaths; private readonly IServerApplicationHost _appHost; - private readonly SemaphoreSlim _cacheFileLock = new SemaphoreSlim(1, 1); - public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths) { _logger = logger; @@ -42,7 +40,7 @@ namespace MediaBrowser.Server.Implementations.Sync _appHost = appHost; } - private string GetRemotePath() + private string[] GetRemotePath() { var parts = new List<string> { @@ -52,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.Sync parts = parts.Select(i => GetValidFilename(_provider, i)).ToList(); - return _provider.GetFullPath(parts, _target); + return parts.ToArray(); } private string GetValidFilename(IServerSyncProvider provider, string filename) @@ -65,22 +63,22 @@ namespace MediaBrowser.Server.Implementations.Sync { if (_items == null) { - try + _logger.Debug("Getting {0} from {1}", string.Join(MediaSync.PathSeparatorString, GetRemotePath().ToArray()), _provider.Name); + + var fileResult = await _provider.GetFiles(new FileQuery { - var path = GetRemotePath(); + FullPath = GetRemotePath().ToArray() - _logger.Debug("Getting {0} from {1}", path, _provider.Name); + }, _target, cancellationToken).ConfigureAwait(false); - using (var stream = await _provider.GetFile(path, _target, new Progress<double>(), cancellationToken)) + if (fileResult.Items.Length > 0) + { + using (var stream = await _provider.GetFile(fileResult.Items[0].Id, _target, new Progress<double>(), cancellationToken)) { _items = _json.DeserializeFromStream<List<LocalItem>>(stream); } } - catch (FileNotFoundException) - { - _items = new List<LocalItem>(); - } - catch (DirectoryNotFoundException) + else { _items = new List<LocalItem>(); } @@ -133,14 +131,9 @@ namespace MediaBrowser.Server.Implementations.Sync } } - public Task<List<string>> GetServerItemIds(SyncTarget target, string serverId) - { - return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.ItemId).ToList()); - } - - public Task<List<string>> GetSyncJobItemIds(SyncTarget target, string serverId) + public Task<List<LocalItem>> GetLocalItems(SyncTarget target, string serverId) { - return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.SyncJobItemId).Where(i => !string.IsNullOrWhiteSpace(i)).ToList()); + return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).ToList()); } public Task AddOrUpdate(SyncTarget target, LocalItem item) |
