From 9f191a3598f8d1cc6764169943186987be33a707 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 25 Mar 2015 19:13:15 -0400 Subject: sync fixes --- MediaBrowser.Server.Implementations/Sync/SyncManager.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'MediaBrowser.Server.Implementations/Sync/SyncManager.cs') diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index d489ac8d3f..2cf6c68539 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -646,6 +646,8 @@ namespace MediaBrowser.Server.Implementations.Sync SyncJobItemId = jobItem.Id, ServerId = _appHost.SystemId, UserId = job.UserId, + SyncJobName = job.Name, + SyncJobDateCreated = job.DateCreated, AdditionalFiles = jobItem.AdditionalFiles.Select(i => new ItemFileInfo { ImageType = i.ImageType, -- cgit v1.2.3 From 5474215141d92c4012f387d6d9ebe9116ca74abc Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 29 Mar 2015 18:38:32 -0400 Subject: sync updates --- MediaBrowser.Api/Playback/MediaInfoService.cs | 12 ++++++++---- .../Library/MediaSourceManager.cs | 14 +++++++++++++- MediaBrowser.Server.Implementations/Sync/MediaSync.cs | 8 ++++---- MediaBrowser.Server.Implementations/Sync/SyncManager.cs | 2 +- .../Sync/SyncedMediaSourceProvider.cs | 11 ++++++++--- 5 files changed, 34 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sync/SyncManager.cs') diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index c6678d1ed1..b833dd7350 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -119,12 +119,16 @@ namespace MediaBrowser.Api.Playback { var item = _libraryManager.GetItemById(request.ItemId); - SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate, request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex, request.SubtitleStreamIndex); + SetDeviceSpecificData(item, result.MediaSource, profile, authInfo, request.MaxStreamingBitrate, + request.StartTimeTicks ?? 0, result.MediaSource.Id, request.AudioStreamIndex, + request.SubtitleStreamIndex); } - - if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl)) + else { - result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId; + if (!string.IsNullOrWhiteSpace(result.MediaSource.TranscodingUrl)) + { + result.MediaSource.TranscodingUrl += "&LiveStreamId=" + result.MediaSource.LiveStreamId; + } } return ToOptimizedResult(result); diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 64b1f2c89a..e832142a90 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -316,7 +316,7 @@ namespace MediaBrowser.Server.Implementations.Library return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); } - private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _openStreams = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); public async Task OpenLiveStream(LiveStreamRequest request, bool enableAutoClose, CancellationToken cancellationToken) @@ -330,6 +330,11 @@ namespace MediaBrowser.Server.Implementations.Library var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(mediaSource.LiveStreamId)) + { + throw new InvalidOperationException(string.Format("{0} returned null LiveStreamId", provider.GetType().Name)); + } + SetKeyProperties(provider, mediaSource); var info = new LiveStreamInfo @@ -368,6 +373,13 @@ namespace MediaBrowser.Server.Implementations.Library public async Task GetLiveStream(string id, CancellationToken cancellationToken) { + if (string.IsNullOrWhiteSpace(id)) + { + throw new ArgumentNullException("id"); + } + + _logger.Debug("Getting live stream {0}", id); + await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index dd8ce82ef1..620143f175 100644 --- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs @@ -371,7 +371,7 @@ namespace MediaBrowser.Server.Implementations.Sync if (item.IsType("episode")) { - parts.Add("TV"); + //parts.Add("TV"); if (!string.IsNullOrWhiteSpace(item.SeriesName)) { parts.Add(item.SeriesName); @@ -379,12 +379,12 @@ namespace MediaBrowser.Server.Implementations.Sync } else if (item.IsVideo) { - parts.Add("Videos"); + //parts.Add("Videos"); parts.Add(item.Name); } else if (item.IsAudio) { - parts.Add("Music"); + //parts.Add("Music"); if (!string.IsNullOrWhiteSpace(item.AlbumArtist)) { @@ -398,7 +398,7 @@ namespace MediaBrowser.Server.Implementations.Sync } else if (string.Equals(item.MediaType, MediaType.Photo, StringComparison.OrdinalIgnoreCase)) { - parts.Add("Photos"); + //parts.Add("Photos"); if (!string.IsNullOrWhiteSpace(item.Album)) { diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 2cf6c68539..d1ebbd28e3 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -721,7 +721,7 @@ namespace MediaBrowser.Server.Implementations.Sync var jobItemResult = GetJobItems(new SyncJobItemQuery { TargetId = targetId, - Statuses = new SyncJobItemStatus[] + Statuses = new[] { SyncJobItemStatus.ReadyToTransfer } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs index 1c17b99936..d1ef523e14 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs @@ -92,6 +92,8 @@ namespace MediaBrowser.Server.Implementations.Sync keyList.Add(item.Id); mediaSource.OpenToken = string.Join("|", keyList.ToArray()); } + + list.Add(mediaSource); } public async Task OpenMediaSource(string openToken, CancellationToken cancellationToken) @@ -111,13 +113,16 @@ namespace MediaBrowser.Server.Implementations.Sync var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(localItem.LocalPath, target, cancellationToken).ConfigureAwait(false); var mediaSource = localItem.Item.MediaSources.First(); + mediaSource.LiveStreamId = Guid.NewGuid().ToString(); SetStaticMediaSourceInfo(localItem, mediaSource); foreach (var stream in mediaSource.MediaStreams) { - var dynamicStreamInfo = await requiresDynamicAccess.GetSyncedFileInfo(stream.ExternalId, target, cancellationToken).ConfigureAwait(false); - - stream.Path = dynamicStreamInfo.Path; + if (!string.IsNullOrWhiteSpace(stream.ExternalId)) + { + var dynamicStreamInfo = await requiresDynamicAccess.GetSyncedFileInfo(stream.ExternalId, target, cancellationToken).ConfigureAwait(false); + stream.Path = dynamicStreamInfo.Path; + } } mediaSource.Path = dynamicInfo.Path; -- cgit v1.2.3 From 7f537ad149e2dc4407229be7c2fcd2df34b8f288 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 29 Mar 2015 19:47:31 -0400 Subject: sync updates --- .../Library/MediaSourceManager.cs | 9 ++++++++- MediaBrowser.Server.Implementations/Sync/MediaSync.cs | 17 ++++++++++------- MediaBrowser.Server.Implementations/Sync/SyncManager.cs | 12 +++++++----- 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sync/SyncManager.cs') diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index e832142a90..c752fe48e9 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -430,7 +430,14 @@ namespace MediaBrowser.Server.Implementations.Library { var tuple = GetProvider(id); - await tuple.Item1.CloseMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false); + try + { + await tuple.Item1.CloseMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false); + } + catch (NotImplementedException) + { + + } LiveStreamInfo removed; if (_openStreams.TryRemove(id, out removed)) diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index 620143f175..ae8b228275 100644 --- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.Server.Implementations.Sync CancellationToken cancellationToken) { var serverId = _appHost.SystemId; + var serverName = _appHost.FriendlyName; await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); progress.Report(3); @@ -51,7 +52,7 @@ namespace MediaBrowser.Server.Implementations.Sync totalProgress += 1; progress.Report(totalProgress); }); - await GetNewMedia(provider, dataProvider, target, serverId, innerProgress, cancellationToken); + await GetNewMedia(provider, dataProvider, target, serverId, serverName, innerProgress, cancellationToken); // Do the data sync twice so the server knows what was removed from the device await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); @@ -93,6 +94,7 @@ namespace MediaBrowser.Server.Implementations.Sync ISyncDataProvider dataProvider, SyncTarget target, string serverId, + string serverName, IProgress progress, CancellationToken cancellationToken) { @@ -119,7 +121,7 @@ namespace MediaBrowser.Server.Implementations.Sync progress.Report(totalProgress); }); - await GetItem(provider, dataProvider, target, serverId, jobItem, innerProgress, cancellationToken).ConfigureAwait(false); + await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false); numComplete++; startingPercent = numComplete; @@ -133,6 +135,7 @@ namespace MediaBrowser.Server.Implementations.Sync ISyncDataProvider dataProvider, SyncTarget target, string serverId, + string serverName, SyncedItem jobItem, IProgress progress, CancellationToken cancellationToken) @@ -140,7 +143,7 @@ namespace MediaBrowser.Server.Implementations.Sync var libraryItem = jobItem.Item; var internalSyncJobItem = _syncManager.GetJobItem(jobItem.SyncJobItemId); - var localItem = CreateLocalItem(provider, jobItem, target, libraryItem, serverId, jobItem.OriginalFileName); + var localItem = CreateLocalItem(provider, jobItem, target, libraryItem, serverId, serverName, jobItem.OriginalFileName); await _syncManager.ReportSyncJobItemTransferBeginning(internalSyncJobItem.Id); @@ -326,9 +329,9 @@ namespace MediaBrowser.Server.Implementations.Sync } } - public LocalItem CreateLocalItem(IServerSyncProvider provider, SyncedItem syncedItem, SyncTarget target, BaseItemDto libraryItem, string serverId, string originalFileName) + public LocalItem CreateLocalItem(IServerSyncProvider provider, SyncedItem syncedItem, SyncTarget target, BaseItemDto libraryItem, string serverId, string serverName, string originalFileName) { - var path = GetDirectoryPath(provider, syncedItem, libraryItem, serverId); + var path = GetDirectoryPath(provider, syncedItem, libraryItem, serverId, serverName); path.Add(GetLocalFileName(provider, libraryItem, originalFileName)); var localPath = provider.GetFullPath(path, target); @@ -361,11 +364,11 @@ namespace MediaBrowser.Server.Implementations.Sync return name; } - private List GetDirectoryPath(IServerSyncProvider provider, SyncedItem syncedItem, BaseItemDto item, string serverId) + private List GetDirectoryPath(IServerSyncProvider provider, SyncedItem syncedItem, BaseItemDto item, string serverId, string serverName) { var parts = new List { - serverId, + serverName, GetSyncJobFolderName(syncedItem, provider) }; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index d1ebbd28e3..5e5a0d2fc7 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -676,14 +676,16 @@ namespace MediaBrowser.Server.Implementations.Sync syncedItem.Item.MediaSources = new List(); - // This will be null for items that are not audio/video - if (mediaSource == null) + syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); + + if (string.IsNullOrWhiteSpace(syncedItem.OriginalFileName)) { - syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); + syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); } - else + + // This will be null for items that are not audio/video + if (mediaSource != null) { - syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); syncedItem.Item.MediaSources.Add(mediaSource); } -- cgit v1.2.3 From 07de09f350ab5ba089a27d94cc10b1a8e6f0a700 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Mon, 30 Mar 2015 15:57:37 -0400 Subject: sync updates --- MediaBrowser.Api/ApiEntryPoint.cs | 2 +- MediaBrowser.Api/Playback/MediaInfoService.cs | 38 ++++++++- MediaBrowser.Dlna/Didl/DidlBuilder.cs | 7 +- MediaBrowser.Model/Dlna/StreamInfo.cs | 96 ++++++++-------------- MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs | 1 + MediaBrowser.Model/Entities/MediaStream.cs | 14 +++- .../Sync/CloudSyncProfile.cs | 5 ++ .../Sync/SyncJobProcessor.cs | 2 +- .../Sync/SyncManager.cs | 2 +- 9 files changed, 97 insertions(+), 70 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sync/SyncManager.cs') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 444977e352..08ac5671d5 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -296,7 +296,7 @@ namespace MediaBrowser.Api // TODO: Lower this hls timeout var timerDuration = job.Type == TranscodingJobType.Progressive ? 1000 : - 14400000; + 7200000; if (job.KillTimer == null) { diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index b833dd7350..6eba195453 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -272,6 +272,11 @@ namespace MediaBrowser.Api.Playback // Set this back to what it was mediaSource.SupportsDirectStream = supportsDirectStream; + + if (streamInfo != null) + { + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } } if (mediaSource.SupportsDirectStream) @@ -285,6 +290,11 @@ namespace MediaBrowser.Api.Playback { mediaSource.SupportsDirectStream = false; } + + if (streamInfo != null) + { + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } } if (mediaSource.SupportsTranscoding) @@ -297,10 +307,36 @@ namespace MediaBrowser.Api.Playback if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode) { streamInfo.StartPositionTicks = startTimeTicks; - mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).Substring(1); + mediaSource.TranscodingUrl = streamInfo.ToUrl("-", auth.Token).TrimStart('-'); mediaSource.TranscodingContainer = streamInfo.Container; mediaSource.TranscodingSubProtocol = streamInfo.SubProtocol; } + + if (streamInfo != null) + { + SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); + } + } + } + + private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string accessToken) + { + var profiles = info.GetSubtitleProfiles(false, "-", accessToken); + + foreach (var profile in profiles) + { + foreach (var stream in mediaSource.MediaStreams) + { + if (stream.Type == MediaStreamType.Subtitle && stream.Index == profile.Index) + { + stream.DeliveryMethod = profile.DeliveryMethod; + + if (profile.DeliveryMethod == SubtitleDeliveryMethod.External) + { + stream.DeliveryUrl = profile.Url.TrimStart('-'); + } + } + } } } diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs index 7f696f300b..b364414d10 100644 --- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs +++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs @@ -167,9 +167,12 @@ namespace MediaBrowser.Dlna.Didl AddVideoResource(container, video, deviceId, filter, contentFeature, streamInfo); } - foreach (var subtitle in streamInfo.GetExternalSubtitles(_serverAddress, _accessToken, false)) + foreach (var subtitle in streamInfo.GetSubtitleProfiles(false, _serverAddress, _accessToken)) { - AddSubtitleElement(container, subtitle); + if (subtitle.DeliveryMethod == SubtitleDeliveryMethod.External) + { + AddSubtitleElement(container, subtitle); + } } } diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index feee2d765c..9bfa684be4 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -51,7 +51,7 @@ namespace MediaBrowser.Model.Dlna public int? MaxVideoBitDepth { get; set; } public int? MaxRefFrames { get; set; } - + public float? MaxFramerate { get; set; } public DeviceProfile DeviceProfile { get; set; } @@ -81,7 +81,8 @@ namespace MediaBrowser.Model.Dlna public bool IsDirectStream { - get { + get + { return PlayMethod == PlayMethod.DirectStream || PlayMethod == PlayMethod.DirectPlay; } @@ -175,7 +176,7 @@ namespace MediaBrowser.Model.Dlna { list.Add(pair.Value); } - + return string.Format("Params={0}", string.Join(";", list.ToArray())); } @@ -199,7 +200,7 @@ namespace MediaBrowser.Model.Dlna list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxHeight.Value) : string.Empty)); list.Add(new NameValuePair("StartTimeTicks", StringHelper.ToStringCultureInvariant(item.StartPositionTicks))); list.Add(new NameValuePair("Level", item.VideoLevel.HasValue ? StringHelper.ToStringCultureInvariant(item.VideoLevel.Value) : string.Empty)); - + list.Add(new NameValuePair("ClientTime", item.IsDirectStream ? string.Empty : DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture))); list.Add(new NameValuePair("MaxRefFrames", item.MaxRefFrames.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxRefFrames.Value) : string.Empty)); list.Add(new NameValuePair("MaxVideoBitDepth", item.MaxVideoBitDepth.HasValue ? StringHelper.ToStringCultureInvariant(item.MaxVideoBitDepth.Value) : string.Empty)); @@ -216,53 +217,25 @@ namespace MediaBrowser.Model.Dlna return list; } - public List GetExternalSubtitles(bool includeSelectedTrackOnly) + public List GetExternalSubtitles(bool includeSelectedTrackOnly, string baseUrl, string accessToken) { - List list = new List(); + List list = GetSubtitleProfiles(includeSelectedTrackOnly, baseUrl, accessToken); + List newList = new List(); // First add the selected track - if (SubtitleStreamIndex.HasValue) + foreach (SubtitleStreamInfo stream in list) { - foreach (MediaStream stream in MediaSource.MediaStreams) - { - if (stream.Type == MediaStreamType.Subtitle && stream.Index == SubtitleStreamIndex.Value) - { - SubtitleStreamInfo info = GetSubtitleStreamInfo(stream); - - if (info != null) - { - list.Add(info); - } - } - } - } - - if (!includeSelectedTrackOnly) - { - foreach (MediaStream stream in MediaSource.MediaStreams) + if (stream.DeliveryMethod == SubtitleDeliveryMethod.External) { - if (stream.Type == MediaStreamType.Subtitle && (!SubtitleStreamIndex.HasValue || stream.Index != SubtitleStreamIndex.Value)) - { - SubtitleStreamInfo info = GetSubtitleStreamInfo(stream); - - if (info != null) - { - list.Add(info); - } - } + newList.Add(stream); } } - return list; + return newList; } - public List GetExternalSubtitles(string baseUrl, string accessToken, bool includeSelectedTrackOnly) + public List GetSubtitleProfiles(bool includeSelectedTrackOnly, string baseUrl, string accessToken) { - if (string.IsNullOrEmpty(baseUrl)) - { - throw new ArgumentNullException(baseUrl); - } - List list = new List(); // HLS will preserve timestamps so we can just grab the full subtitle stream @@ -279,10 +252,7 @@ namespace MediaBrowser.Model.Dlna { SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks); - if (info != null) - { - list.Add(info); - } + list.Add(info); } } } @@ -295,14 +265,11 @@ namespace MediaBrowser.Model.Dlna { SubtitleStreamInfo info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks); - if (info != null) - { - list.Add(info); - } + list.Add(info); } } } - + return list; } @@ -310,15 +277,22 @@ namespace MediaBrowser.Model.Dlna { SubtitleStreamInfo info = GetSubtitleStreamInfo(stream); - if (info != null) + if (info.DeliveryMethod == SubtitleDeliveryMethod.External) { - info.Url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", - baseUrl, - ItemId, - MediaSourceId, - StringHelper.ToStringCultureInvariant(stream.Index), - StringHelper.ToStringCultureInvariant(startPositionTicks), - SubtitleFormat); + if (MediaSource.Protocol == MediaProtocol.Http) + { + info.Url = stream.Path; + } + else if (!string.IsNullOrEmpty(baseUrl)) + { + info.Url = string.Format("{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}", + baseUrl, + ItemId, + MediaSourceId, + StringHelper.ToStringCultureInvariant(stream.Index), + StringHelper.ToStringCultureInvariant(startPositionTicks), + SubtitleFormat); + } } return info; @@ -328,18 +302,14 @@ namespace MediaBrowser.Model.Dlna { SubtitleProfile subtitleProfile = StreamBuilder.GetSubtitleProfile(stream, DeviceProfile.SubtitleProfiles, Context); - if (subtitleProfile.Method != SubtitleDeliveryMethod.External) - { - return null; - } - return new SubtitleStreamInfo { IsForced = stream.IsForced, Language = stream.Language, Name = stream.Language ?? "Unknown", Format = SubtitleFormat, - Index = stream.Index + Index = stream.Index, + DeliveryMethod = subtitleProfile.Method }; } diff --git a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs index a7a8da3ba2..602858ccc9 100644 --- a/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs +++ b/MediaBrowser.Model/Dlna/SubtitleStreamInfo.cs @@ -8,5 +8,6 @@ namespace MediaBrowser.Model.Dlna public bool IsForced { get; set; } public string Format { get; set; } public int Index { get; set; } + public SubtitleDeliveryMethod DeliveryMethod { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index fa075490a5..760829ebff 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -1,4 +1,5 @@ -using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Dlna; +using MediaBrowser.Model.Extensions; using System.Diagnostics; namespace MediaBrowser.Model.Entities @@ -135,6 +136,17 @@ namespace MediaBrowser.Model.Entities /// true if this instance is external; otherwise, false. public bool IsExternal { get; set; } + /// + /// Gets or sets the method. + /// + /// The method. + public SubtitleDeliveryMethod? DeliveryMethod { get; set; } + /// + /// Gets or sets the delivery URL. + /// + /// The delivery URL. + public string DeliveryUrl { get; set; } + public bool IsTextSubtitleStream { get diff --git a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs index c3e8cf9444..43fb10df00 100644 --- a/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs +++ b/MediaBrowser.Server.Implementations/Sync/CloudSyncProfile.cs @@ -227,6 +227,11 @@ namespace MediaBrowser.Server.Implementations.Sync { Format = "srt", Method = SubtitleDeliveryMethod.External + }, + new SubtitleProfile + { + Format = "vtt", + Method = SubtitleDeliveryMethod.External } }; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs index b73e0e85f2..7eb015ae7c 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncJobProcessor.cs @@ -495,7 +495,7 @@ namespace MediaBrowser.Server.Implementations.Sync // No sense creating external subs if we're already burning one into the video var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ? new List() : - streamInfo.GetExternalSubtitles(false); + streamInfo.GetExternalSubtitles(false, null, null); // Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 5e5a0d2fc7..3acc79088d 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -677,7 +677,6 @@ namespace MediaBrowser.Server.Implementations.Sync syncedItem.Item.MediaSources = new List(); syncedItem.OriginalFileName = Path.GetFileName(libraryItem.Path); - if (string.IsNullOrWhiteSpace(syncedItem.OriginalFileName)) { syncedItem.OriginalFileName = Path.GetFileName(mediaSource.Path); @@ -686,6 +685,7 @@ namespace MediaBrowser.Server.Implementations.Sync // This will be null for items that are not audio/video if (mediaSource != null) { + syncedItem.OriginalFileName = Path.ChangeExtension(syncedItem.OriginalFileName, Path.GetExtension(mediaSource.Path)); syncedItem.Item.MediaSources.Add(mediaSource); } -- cgit v1.2.3 From 5965afecde2536c0a2ec566fd6afdb21add8aa50 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 31 Mar 2015 14:50:08 -0400 Subject: live tv fix --- MediaBrowser.Api/Playback/MediaInfoService.cs | 23 ------ MediaBrowser.Api/Playback/TranscodingThrottler.cs | 2 +- .../HttpClientManager/HttpClientManager.cs | 32 +++++--- MediaBrowser.Controller/LiveTv/LiveTvProgram.cs | 6 ++ MediaBrowser.Controller/Sync/ISyncDataProvider.cs | 16 ++++ MediaBrowser.Model/ApiClient/IApiClient.cs | 5 +- .../MediaInfo/PlaybackInfoRequest.cs | 16 ++++ MediaBrowser.Model/Sync/LocalItem.cs | 5 ++ MediaBrowser.Model/Sync/SyncDataRequest.cs | 1 + .../Channels/ChannelImageProvider.cs | 1 - .../Library/MediaSourceManager.cs | 10 +-- .../LiveTv/LiveTvDtoService.cs | 2 +- .../LiveTv/LiveTvManager.cs | 6 +- .../Sync/MediaSync.cs | 11 +-- .../Sync/SyncManager.cs | 95 +++++++++++++++++++++- .../Sync/TargetDataProvider.cs | 30 ++++++- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- 20 files changed, 207 insertions(+), 66 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Sync/SyncManager.cs') diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 0930c00024..ca735f0684 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -39,29 +39,6 @@ namespace MediaBrowser.Api.Playback [Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")] public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn { - [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string Id { get; set; } - - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string UserId { get; set; } - - [ApiMember(Name = "MaxStreamingBitrate", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] - public int? MaxStreamingBitrate { get; set; } - - [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] - public long? StartTimeTicks { get; set; } - - [ApiMember(Name = "AudioStreamIndex", Description = "Optional. The index of the audio stream to use. If omitted the first audio stream will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] - public int? AudioStreamIndex { get; set; } - - [ApiMember(Name = "SubtitleStreamIndex", Description = "Optional. The index of the subtitle stream to use. If omitted no subtitles will be used.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "POST")] - public int? SubtitleStreamIndex { get; set; } - - [ApiMember(Name = "MediaSourceId", Description = "The media version id, if playing an alternate version", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string MediaSourceId { get; set; } - - [ApiMember(Name = "LiveStreamId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string LiveStreamId { get; set; } } [Route("/LiveStreams/Open", "POST", Summary = "Opens a media source")] diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs index ff79bb48f4..58cfa086e3 100644 --- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs +++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback var options = GetOptions(); - if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) + if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) { PauseTranscoding(); } diff --git a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs index b925649fce..94c91c55aa 100644 --- a/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs +++ b/MediaBrowser.Common.Implementations/HttpClientManager/HttpClientManager.cs @@ -107,30 +107,40 @@ namespace MediaBrowser.Common.Implementations.HttpClientManager private WebRequest GetRequest(HttpRequestOptions options, string method, bool enableHttpCompression) { - var request = (HttpWebRequest)WebRequest.Create(options.Url); + var request = WebRequest.Create(options.Url); + var httpWebRequest = request as HttpWebRequest; - AddRequestHeaders(request, options); + if (httpWebRequest != null) + { + AddRequestHeaders(httpWebRequest, options); - request.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None; + httpWebRequest.AutomaticDecompression = enableHttpCompression ? DecompressionMethods.Deflate : DecompressionMethods.None; + } request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache); - if (options.EnableKeepAlive) + if (httpWebRequest != null) { - request.KeepAlive = true; + if (options.EnableKeepAlive) + { + httpWebRequest.KeepAlive = true; + } } request.Method = method; request.Timeout = options.TimeoutMs; - if (!string.IsNullOrEmpty(options.Host)) + if (httpWebRequest != null) { - request.Host = options.Host; - } + if (!string.IsNullOrEmpty(options.Host)) + { + httpWebRequest.Host = options.Host; + } - if (!string.IsNullOrEmpty(options.Referer)) - { - request.Referer = options.Referer; + if (!string.IsNullOrEmpty(options.Referer)) + { + httpWebRequest.Referer = options.Referer; + } } //request.ServicePoint.BindIPEndPointDelegate = BindIPEndPointCallback; diff --git a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs index 0b07d8b6d1..0609df4c6b 100644 --- a/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs +++ b/MediaBrowser.Controller/LiveTv/LiveTvProgram.cs @@ -34,6 +34,12 @@ namespace MediaBrowser.Controller.LiveTv /// The channel identifier. public string ExternalChannelId { get; set; } + /// + /// Gets or sets the original air date. + /// + /// The original air date. + public DateTime? OriginalAirDate { get; set; } + /// /// Gets or sets the type of the channel. /// diff --git a/MediaBrowser.Controller/Sync/ISyncDataProvider.cs b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs index f84748b971..04101fd465 100644 --- a/MediaBrowser.Controller/Sync/ISyncDataProvider.cs +++ b/MediaBrowser.Controller/Sync/ISyncDataProvider.cs @@ -14,6 +14,14 @@ namespace MediaBrowser.Controller.Sync /// Task<List<System.String>>. Task> GetServerItemIds(SyncTarget target, string serverId); + /// + /// Gets the synchronize job item ids. + /// + /// The target. + /// The server identifier. + /// Task<List<System.String>>. + Task> GetSyncJobItemIds(SyncTarget target, string serverId); + /// /// Adds the or update. /// @@ -46,5 +54,13 @@ namespace MediaBrowser.Controller.Sync /// The item identifier. /// Task<LocalItem>. Task> GetCachedItems(SyncTarget target, string serverId, string itemId); + /// + /// Gets the cached items by synchronize job item identifier. + /// + /// The target. + /// The server identifier. + /// The synchronize job item identifier. + /// Task<List<LocalItem>>. + Task> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId); } } diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 58af016150..9675de38b0 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -248,10 +248,9 @@ namespace MediaBrowser.Model.ApiClient /// /// Gets the playback information. /// - /// The item identifier. - /// The user identifier. + /// The request. /// Task<LiveMediaInfoResult>. - Task GetPlaybackInfo(string itemId, string userId); + Task GetPlaybackInfo(PlaybackInfoRequest request); /// /// Gets the users async. diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs index ffd4995ad9..124739073a 100644 --- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs +++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs @@ -4,6 +4,22 @@ namespace MediaBrowser.Model.MediaInfo { public class PlaybackInfoRequest { + public string Id { get; set; } + + public string UserId { get; set; } + + public int? MaxStreamingBitrate { get; set; } + + public long? StartTimeTicks { get; set; } + + public int? AudioStreamIndex { get; set; } + + public int? SubtitleStreamIndex { get; set; } + + public string MediaSourceId { get; set; } + + public string LiveStreamId { get; set; } + public DeviceProfile DeviceProfile { get; set; } } } diff --git a/MediaBrowser.Model/Sync/LocalItem.cs b/MediaBrowser.Model/Sync/LocalItem.cs index 37f605a590..dbbecaf057 100644 --- a/MediaBrowser.Model/Sync/LocalItem.cs +++ b/MediaBrowser.Model/Sync/LocalItem.cs @@ -31,6 +31,11 @@ namespace MediaBrowser.Model.Sync /// The item identifier. public string ItemId { get; set; } /// + /// Gets or sets the synchronize job item identifier. + /// + /// The synchronize job item identifier. + public string SyncJobItemId { get; set; } + /// /// Gets or sets the user ids with access. /// /// The user ids with access. diff --git a/MediaBrowser.Model/Sync/SyncDataRequest.cs b/MediaBrowser.Model/Sync/SyncDataRequest.cs index dc33239a04..0df4de86d1 100644 --- a/MediaBrowser.Model/Sync/SyncDataRequest.cs +++ b/MediaBrowser.Model/Sync/SyncDataRequest.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Model.Sync { public List LocalItemIds { get; set; } public List OfflineUserIds { get; set; } + public List SyncJobItemIds { get; set; } public string TargetId { get; set; } diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelImageProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelImageProvider.cs index 5c033e6bdc..f13c71c6df 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelImageProvider.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelImageProvider.cs @@ -2,7 +2,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using System; using System.Collections.Generic; using System.Linq; using System.Threading; diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 66eeb61f72..4fab95263f 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -129,6 +129,11 @@ namespace MediaBrowser.Server.Implementations.Library return list; } + public Task> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken) + { + return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken); + } + public async Task> GetPlayackMediaSources(string id, string userId, bool enablePathSubstitution, CancellationToken cancellationToken) { var item = _libraryManager.GetItemById(id); @@ -225,11 +230,6 @@ namespace MediaBrowser.Server.Implementations.Library } } - public Task> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken) - { - return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken); - } - public MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution) { return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs index 7f4440fbce..401cf87657 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvDtoService.cs @@ -373,7 +373,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv StartDate = item.StartDate, OfficialRating = item.OfficialRating, IsHD = item.IsHD, - OriginalAirDate = item.PremiereDate, + OriginalAirDate = item.OriginalAirDate, Audio = item.Audio, CommunityRating = GetClientCommunityRating(item.CommunityRating), IsRepeat = item.IsRepeat, diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index f676918593..a39781d6a3 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -589,13 +589,15 @@ namespace MediaBrowser.Server.Implementations.LiveTv item.Name = info.Name; item.OfficialRating = info.OfficialRating; item.Overview = info.Overview; - item.PremiereDate = info.OriginalAirDate; + item.OriginalAirDate = info.OriginalAirDate; item.ProviderImagePath = info.ImagePath; item.ProviderImageUrl = info.ImageUrl; item.RunTimeTicks = (info.EndDate - info.StartDate).Ticks; item.StartDate = info.StartDate; - item.ProductionYear = info.ProductionYear; + item.ProductionYear = info.ProductionYear; + item.PremiereDate = item.PremiereDate ?? info.OriginalAirDate; + await item.UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false); return item; diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index e7333939e3..5bc8b80887 100644 --- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs @@ -67,12 +67,12 @@ namespace MediaBrowser.Server.Implementations.Sync SyncTarget target, CancellationToken cancellationToken) { - var localIds = await dataProvider.GetServerItemIds(target, serverId).ConfigureAwait(false); + var jobItemIds = await dataProvider.GetSyncJobItemIds(target, serverId).ConfigureAwait(false); var result = await _syncManager.SyncData(new SyncDataRequest { TargetId = target.Id, - LocalItemIds = localIds + SyncJobItemIds = jobItemIds }).ConfigureAwait(false); @@ -285,11 +285,11 @@ namespace MediaBrowser.Server.Implementations.Sync private async Task RemoveItem(IServerSyncProvider provider, ISyncDataProvider dataProvider, string serverId, - string itemId, + string syncJobItemId, SyncTarget target, CancellationToken cancellationToken) { - var localItems = await dataProvider.GetCachedItems(target, serverId, itemId); + var localItems = await dataProvider.GetCachedItemsBySyncJobItemId(target, serverId, syncJobItemId); foreach (var localItem in localItems) { @@ -350,7 +350,8 @@ namespace MediaBrowser.Server.Implementations.Sync ItemId = libraryItem.Id, ServerId = serverId, LocalPath = localPath, - Id = GetLocalId(syncedItem.SyncJobItemId, libraryItem.Id) + Id = GetLocalId(syncedItem.SyncJobItemId, libraryItem.Id), + SyncJobItemId = syncedItem.SyncJobItemId }; } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs index 3acc79088d..102218979c 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncManager.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncManager.cs @@ -3,6 +3,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Events; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; +using MediaBrowser.Controller; using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; @@ -42,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly ILogger _logger; private readonly IUserManager _userManager; private readonly Func _dtoService; - private readonly IApplicationHost _appHost; + private readonly IServerApplicationHost _appHost; private readonly ITVSeriesManager _tvSeriesManager; private readonly Func _mediaEncoder; private readonly IFileSystem _fileSystem; @@ -60,7 +61,7 @@ namespace MediaBrowser.Server.Implementations.Sync public event EventHandler> SyncJobItemUpdated; public event EventHandler> SyncJobItemCreated; - 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, IUserDataManager userDataManager, Func mediaSourceManager, IJsonSerializer json) + public SyncManager(ILibraryManager libraryManager, ISyncRepository repo, IImageProcessor imageProcessor, ILogger logger, IUserManager userManager, Func dtoService, IServerApplicationHost appHost, ITVSeriesManager tvSeriesManager, Func mediaEncoder, IFileSystem fileSystem, Func subtitleEncoder, IConfigurationManager config, IUserDataManager userDataManager, Func mediaSourceManager, IJsonSerializer json) { _libraryManager = libraryManager; _repo = repo; @@ -94,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Sync public ISyncDataProvider GetDataProvider(IServerSyncProvider provider, SyncTarget target) { - return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost.SystemId, _logger, _json, _fileSystem, _config.CommonApplicationPaths)); + return _dataProviders.GetOrAdd(target.Id, key => new TargetDataProvider(provider, target, _appHost, _logger, _json, _fileSystem, _config.CommonApplicationPaths)); } public async Task CreateJob(SyncJobRequest request) @@ -737,10 +738,15 @@ namespace MediaBrowser.Server.Implementations.Sync public async Task SyncData(SyncDataRequest request) { + if (request.SyncJobItemIds != null) + { + return await SyncDataUsingSyncJobItemIds(request).ConfigureAwait(false); + } + var jobItemResult = GetJobItems(new SyncJobItemQuery { TargetId = request.TargetId, - Statuses = new SyncJobItemStatus[] { SyncJobItemStatus.Synced } + Statuses = new[] { SyncJobItemStatus.Synced } }); var response = new SyncDataResponse(); @@ -816,6 +822,87 @@ namespace MediaBrowser.Server.Implementations.Sync return response; } + private async Task SyncDataUsingSyncJobItemIds(SyncDataRequest request) + { + var jobItemResult = GetJobItems(new SyncJobItemQuery + { + TargetId = request.TargetId, + Statuses = new[] { SyncJobItemStatus.Synced } + }); + + var response = new SyncDataResponse(); + + foreach (var jobItem in jobItemResult.Items) + { + if (request.SyncJobItemIds.Contains(jobItem.Id, StringComparer.OrdinalIgnoreCase)) + { + var job = _repo.GetJob(jobItem.JobId); + var user = _userManager.GetUserById(job.UserId); + + if (jobItem.IsMarkedForRemoval) + { + // Tell the device to remove it since it has been marked for removal + response.ItemIdsToRemove.Add(jobItem.Id); + } + else if (user == null) + { + // Tell the device to remove it since the user is gone now + response.ItemIdsToRemove.Add(jobItem.Id); + } + else if (job.UnwatchedOnly) + { + var libraryItem = _libraryManager.GetItemById(jobItem.ItemId); + + if (IsLibraryItemAvailable(libraryItem)) + { + if (libraryItem.IsPlayed(user) && libraryItem is Video) + { + // Tell the device to remove it since it has been played + response.ItemIdsToRemove.Add(jobItem.Id); + } + } + else + { + // Tell the device to remove it since it's no longer available + response.ItemIdsToRemove.Add(jobItem.Id); + } + } + } + else + { + // Content is no longer on the device + jobItem.Status = SyncJobItemStatus.RemovedFromDevice; + await UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); + } + } + + // Now check each item that's on the device + foreach (var syncJobItemId in request.SyncJobItemIds) + { + // See if it's already marked for removal + if (response.ItemIdsToRemove.Contains(syncJobItemId, StringComparer.OrdinalIgnoreCase)) + { + continue; + } + + // If there isn't a sync job for this item, mark it for removal + if (!jobItemResult.Items.Any(i => string.Equals(syncJobItemId, i.Id, StringComparison.OrdinalIgnoreCase))) + { + response.ItemIdsToRemove.Add(syncJobItemId); + } + } + + response.ItemIdsToRemove = response.ItemIdsToRemove.Distinct(StringComparer.OrdinalIgnoreCase).ToList(); + + var itemsOnDevice = request.LocalItemIds + .Except(response.ItemIdsToRemove) + .ToList(); + + SetUserAccess(request, response, itemsOnDevice); + + return response; + } + private void SetUserAccess(SyncDataRequest request, SyncDataResponse response, List itemIds) { var users = request.OfflineUserIds diff --git a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs index ca9d96c12f..dea8688482 100644 --- a/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs +++ b/MediaBrowser.Server.Implementations/Sync/TargetDataProvider.cs @@ -1,6 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; +using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -26,11 +27,11 @@ namespace MediaBrowser.Server.Implementations.Sync private readonly IJsonSerializer _json; private readonly IFileSystem _fileSystem; private readonly IApplicationPaths _appPaths; - private readonly string _serverId; + private readonly IServerApplicationHost _appHost; private readonly SemaphoreSlim _cacheFileLock = new SemaphoreSlim(1, 1); - public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, string serverId, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths) + public TargetDataProvider(IServerSyncProvider provider, SyncTarget target, IServerApplicationHost appHost, ILogger logger, IJsonSerializer json, IFileSystem fileSystem, IApplicationPaths appPaths) { _logger = logger; _json = json; @@ -38,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Sync _target = target; _fileSystem = fileSystem; _appPaths = appPaths; - _serverId = serverId; + _appHost = appHost; } private string GetCachePath() @@ -50,13 +51,21 @@ namespace MediaBrowser.Server.Implementations.Sync { var parts = new List { - _serverId, + _appHost.FriendlyName, "data.json" }; + parts = parts.Select(i => GetValidFilename(_provider, i)).ToList(); + return _provider.GetFullPath(parts, _target); } + private string GetValidFilename(IServerSyncProvider provider, string filename) + { + // We can always add this method to the sync provider if it's really needed + return _fileSystem.GetValidFilename(filename); + } + private async Task CacheData(Stream stream) { var cachePath = GetCachePath(); @@ -167,6 +176,11 @@ namespace MediaBrowser.Server.Implementations.Sync return GetData(items => items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase)).Select(i => i.ItemId).ToList()); } + public Task> GetSyncJobItemIds(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()); + } + public Task AddOrUpdate(SyncTarget target, LocalItem item) { return UpdateData(items => @@ -239,5 +253,13 @@ namespace MediaBrowser.Server.Implementations.Sync return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.ItemId, itemId, StringComparison.OrdinalIgnoreCase)) .ToList(); } + + public async Task> GetCachedItemsBySyncJobItemId(SyncTarget target, string serverId, string syncJobItemId) + { + var items = await GetCachedData().ConfigureAwait(false); + + return items.Where(i => string.Equals(i.ServerId, serverId, StringComparison.OrdinalIgnoreCase) && string.Equals(i.SyncJobItemId, syncJobItemId, StringComparison.OrdinalIgnoreCase)) + .ToList(); + } } } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index 40da3899c5..c5acc0a42d 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.609 + 3.0.611 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption. Copyright © Emby 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 7aa9d30551..1b29b02729 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.609 + 3.0.611 MediaBrowser.Common Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 8d65ec4315..6ee79dd8c9 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.609 + 3.0.611 MediaBrowser.Model - Signed Edition Emby Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 9a5264da95..c8b062f3f3 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.609 + 3.0.611 Media Browser.Server.Core Emby Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Emby Server. Copyright © Emby 2013 - + -- cgit v1.2.3