aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Server.Implementations')
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs14
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs43
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs47
-rw-r--r--MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs148
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs9
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs77
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj2
-rw-r--r--MediaBrowser.Server.Implementations/Sync/MediaSync.cs1
-rw-r--r--MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs74
9 files changed, 339 insertions, 76 deletions
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
index e0b616605..980c3f31b 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelDownloadScheduledTask.cs
@@ -169,7 +169,7 @@ namespace MediaBrowser.Server.Implementations.Channels
foreach (var item in result.Items)
{
- var channelItem = (IChannelItem)item;
+ var channelItem = (IChannelMediaItem)item;
var channelFeatures = _manager.GetChannelFeatures(channelItem.ChannelId);
@@ -179,7 +179,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
try
{
- await DownloadChannelItem(item, options, cancellationToken, path);
+ await DownloadChannelItem(channelItem, options, cancellationToken, path);
}
catch (OperationCanceledException)
{
@@ -210,13 +210,13 @@ namespace MediaBrowser.Server.Implementations.Channels
return channelOptions.DownloadSizeLimit;
}
- private async Task DownloadChannelItem(BaseItem item,
+ private async Task DownloadChannelItem(IChannelMediaItem item,
ChannelOptions channelOptions,
CancellationToken cancellationToken,
string path)
{
var itemId = item.Id.ToString("N");
- var sources = await _manager.GetChannelItemMediaSources(itemId, false, cancellationToken)
+ var sources = await _manager.GetStaticMediaSources(item, true, cancellationToken)
.ConfigureAwait(false);
var cachedVersions = sources.Where(i => i.Protocol == MediaProtocol.File).ToList();
@@ -237,11 +237,9 @@ namespace MediaBrowser.Server.Implementations.Channels
}
}
- var channelItem = (IChannelMediaItem)item;
+ var destination = Path.Combine(path, item.ChannelId, itemId);
- var destination = Path.Combine(path, channelItem.ChannelId, itemId);
-
- await _manager.DownloadChannelItem(channelItem, destination, new Progress<double>(), cancellationToken)
+ await _manager.DownloadChannelItem(item, destination, new Progress<double>(), cancellationToken)
.ConfigureAwait(false);
await RefreshMediaSourceItem(destination, cancellationToken).ConfigureAwait(false);
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs
new file mode 100644
index 000000000..6a7163bb3
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs
@@ -0,0 +1,43 @@
+using MediaBrowser.Controller.Channels;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Model.Dto;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Channels
+{
+ public class ChannelDynamicMediaSourceProvider : IMediaSourceProvider
+ {
+ private readonly ChannelManager _channelManager;
+
+ public ChannelDynamicMediaSourceProvider(IChannelManager channelManager)
+ {
+ _channelManager = (ChannelManager)channelManager;
+ }
+
+ public Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
+ {
+ var channelItem = item as IChannelMediaItem;
+
+ if (channelItem != null)
+ {
+ return _channelManager.GetDynamicMediaSources(channelItem, cancellationToken);
+ }
+
+ return Task.FromResult<IEnumerable<MediaSourceInfo>>(new List<MediaSourceInfo>());
+ }
+
+ public Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Task CloseMediaSource(string closeKey, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index f0f30229e..e22bf2e7f 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -241,10 +241,25 @@ namespace MediaBrowser.Server.Implementations.Channels
return item;
}
- public async Task<IEnumerable<MediaSourceInfo>> GetChannelItemMediaSources(string id, bool includeDynamicSources, CancellationToken cancellationToken)
+ public async Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(IChannelMediaItem item, bool includeCachedVersions, CancellationToken cancellationToken)
{
- var item = (IChannelMediaItem)_libraryManager.GetItemById(id);
+ IEnumerable<ChannelMediaInfo> results = item.ChannelMediaSources;
+ var sources = SortMediaInfoResults(results)
+ .Select(i => GetMediaSource(item, i))
+ .ToList();
+
+ if (includeCachedVersions)
+ {
+ var cachedVersions = GetCachedChannelItemMediaSources(item);
+ sources.InsertRange(0, cachedVersions);
+ }
+
+ return sources.Where(IsValidMediaSource);
+ }
+
+ public async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IChannelMediaItem item, CancellationToken cancellationToken)
+ {
var channel = GetChannel(item.ChannelId);
var channelPlugin = GetChannelProvider(channel);
@@ -252,24 +267,25 @@ namespace MediaBrowser.Server.Implementations.Channels
IEnumerable<ChannelMediaInfo> results;
- if (requiresCallback != null && includeDynamicSources)
+ if (requiresCallback != null)
{
results = await GetChannelItemMediaSourcesInternal(requiresCallback, item.ExternalId, cancellationToken)
- .ConfigureAwait(false);
+ .ConfigureAwait(false);
}
else
{
- results = item.ChannelMediaSources;
+ results = new List<ChannelMediaInfo>();
}
- var sources = SortMediaInfoResults(results).Select(i => GetMediaSource(item, i))
+ var list = SortMediaInfoResults(results)
+ .Select(i => GetMediaSource(item, i))
+ .Where(IsValidMediaSource)
.ToList();
var cachedVersions = GetCachedChannelItemMediaSources(item);
+ list.InsertRange(0, cachedVersions);
- sources.InsertRange(0, cachedVersions);
-
- return sources.Where(IsValidMediaSource);
+ return list;
}
private readonly ConcurrentDictionary<string, Tuple<DateTime, List<ChannelMediaInfo>>> _channelItemMediaInfo =
@@ -297,14 +313,7 @@ namespace MediaBrowser.Server.Implementations.Channels
return list;
}
- public IEnumerable<MediaSourceInfo> GetCachedChannelItemMediaSources(string id)
- {
- var item = (IChannelMediaItem)_libraryManager.GetItemById(id);
-
- return GetCachedChannelItemMediaSources(item);
- }
-
- public IEnumerable<MediaSourceInfo> GetCachedChannelItemMediaSources(IChannelMediaItem item)
+ private IEnumerable<MediaSourceInfo> GetCachedChannelItemMediaSources(IChannelMediaItem item)
{
var filenamePrefix = item.Id.ToString("N");
var parentPath = Path.Combine(ChannelDownloadPath, item.ChannelId);
@@ -339,7 +348,6 @@ namespace MediaBrowser.Server.Implementations.Channels
if (source != null)
{
- source.Type = MediaSourceType.Cache;
return new[] { source };
}
}
@@ -1408,8 +1416,7 @@ namespace MediaBrowser.Server.Implementations.Channels
public async Task DownloadChannelItem(IChannelMediaItem item, string destination,
IProgress<double> progress, CancellationToken cancellationToken)
{
- var itemId = item.Id.ToString("N");
- var sources = await GetChannelItemMediaSources(itemId, true, cancellationToken)
+ var sources = await GetDynamicMediaSources(item, cancellationToken)
.ConfigureAwait(false);
var list = sources.Where(i => i.Protocol == MediaProtocol.Http).ToList();
diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
index 39219b541..40cf240d7 100644
--- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller.Channels;
+using System.Collections.Concurrent;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
@@ -13,25 +14,24 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Server.Implementations.LiveTv;
namespace MediaBrowser.Server.Implementations.Library
{
- public class MediaSourceManager : IMediaSourceManager
+ public class MediaSourceManager : IMediaSourceManager, IDisposable
{
private readonly IItemRepository _itemRepo;
private readonly IUserManager _userManager;
private readonly ILibraryManager _libraryManager;
- private readonly IChannelManager _channelManager;
private IMediaSourceProvider[] _providers;
private readonly ILogger _logger;
- public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, IChannelManager channelManager, ILogger logger)
+ public MediaSourceManager(IItemRepository itemRepo, IUserManager userManager, ILibraryManager libraryManager, ILogger logger)
{
_itemRepo = itemRepo;
_userManager = userManager;
_libraryManager = libraryManager;
- _channelManager = channelManager;
_logger = logger;
}
@@ -133,24 +133,15 @@ namespace MediaBrowser.Server.Implementations.Library
IEnumerable<MediaSourceInfo> mediaSources;
var hasMediaSources = (IHasMediaSources)item;
- var channelItem = item as IChannelMediaItem;
- if (channelItem != null)
+ if (string.IsNullOrWhiteSpace(userId))
{
- mediaSources = await _channelManager.GetChannelItemMediaSources(id, true, cancellationToken)
- .ConfigureAwait(false);
+ mediaSources = hasMediaSources.GetMediaSources(enablePathSubstitution);
}
else
{
- if (string.IsNullOrWhiteSpace(userId))
- {
- mediaSources = hasMediaSources.GetMediaSources(enablePathSubstitution);
- }
- else
- {
- var user = _userManager.GetUserById(userId);
- mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
- }
+ var user = _userManager.GetUserById(userId);
+ mediaSources = GetStaticMediaSources(hasMediaSources, enablePathSubstitution, user);
}
var dynamicMediaSources = await GetDynamicMediaSources(hasMediaSources, cancellationToken).ConfigureAwait(false);
@@ -161,11 +152,16 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var source in dynamicMediaSources)
{
- source.SupportsTranscoding = false;
-
if (source.Protocol == MediaProtocol.File)
{
source.SupportsDirectStream = File.Exists(source.Path);
+
+ // TODO: Path substitution
+ }
+ else if (source.Protocol == MediaProtocol.Http)
+ {
+ // TODO: Allow this when the source is plain http, e.g. not HLS or Mpeg Dash
+ source.SupportsDirectStream = false;
}
else
{
@@ -175,7 +171,7 @@ namespace MediaBrowser.Server.Implementations.Library
list.Add(source);
}
- return SortMediaSources(list);
+ return SortMediaSources(list).Where(i => i.Type != MediaSourceType.Placeholder);
}
private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
@@ -190,7 +186,15 @@ namespace MediaBrowser.Server.Implementations.Library
{
try
{
- return await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false);
+ var sources = await provider.GetMediaSources(item, cancellationToken).ConfigureAwait(false);
+ var list = sources.ToList();
+
+ foreach (var mediaSource in list)
+ {
+ SetKeyProperties(provider, mediaSource);
+ }
+
+ return list;
}
catch (Exception ex)
{
@@ -199,6 +203,21 @@ namespace MediaBrowser.Server.Implementations.Library
}
}
+ private void SetKeyProperties(IMediaSourceProvider provider, MediaSourceInfo mediaSource)
+ {
+ var prefix = provider.GetType().FullName.GetMD5().ToString("N") + "|";
+
+ if (!string.IsNullOrWhiteSpace(mediaSource.OpenKey) && !mediaSource.OpenKey.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
+ {
+ mediaSource.OpenKey = prefix + mediaSource.OpenKey;
+ }
+
+ if (!string.IsNullOrWhiteSpace(mediaSource.CloseKey) && !mediaSource.CloseKey.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
+ {
+ mediaSource.CloseKey = prefix + mediaSource.CloseKey;
+ }
+ }
+
public Task<IEnumerable<MediaSourceInfo>> GetPlayackMediaSources(string id, bool enablePathSubstitution, CancellationToken cancellationToken)
{
return GetPlayackMediaSources(id, null, enablePathSubstitution, cancellationToken);
@@ -294,5 +313,90 @@ namespace MediaBrowser.Server.Implementations.Library
{
return GetStaticMediaSources(item, enablePathSubstitution).FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase));
}
+
+ private readonly ConcurrentDictionary<string, string> _openStreams =
+ new ConcurrentDictionary<string, string>();
+ private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
+ public async Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken)
+ {
+ await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ var tuple = GetProvider(openKey);
+ var provider = tuple.Item1;
+
+ var mediaSource = await provider.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
+
+ SetKeyProperties(provider, mediaSource);
+
+ _openStreams.AddOrUpdate(mediaSource.CloseKey, mediaSource.CloseKey, (key, i) => mediaSource.CloseKey);
+
+ return mediaSource;
+ }
+ finally
+ {
+ _liveStreamSemaphore.Release();
+ }
+ }
+
+ public async Task CloseMediaSource(string closeKey, CancellationToken cancellationToken)
+ {
+ await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
+
+ try
+ {
+ var tuple = GetProvider(closeKey);
+
+ await tuple.Item1.OpenMediaSource(tuple.Item2, cancellationToken).ConfigureAwait(false);
+
+ string removedKey;
+ _openStreams.TryRemove(closeKey, out removedKey);
+ }
+ finally
+ {
+ _liveStreamSemaphore.Release();
+ }
+ }
+
+ private Tuple<IMediaSourceProvider, string> GetProvider(string key)
+ {
+ var keys = key.Split(new[] { '|' }, 2);
+
+ var provider = _providers.FirstOrDefault(i => string.Equals(i.GetType().FullName.GetMD5().ToString("N"), keys[0], StringComparison.OrdinalIgnoreCase));
+
+ return new Tuple<IMediaSourceProvider, string>(provider, keys[1]);
+ }
+
+ /// <summary>
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ private readonly object _disposeLock = new object();
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources.
+ /// </summary>
+ /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool dispose)
+ {
+ if (dispose)
+ {
+ lock (_disposeLock)
+ {
+ foreach (var key in _openStreams.Keys.ToList())
+ {
+ var task = CloseMediaSource(key, CancellationToken.None);
+
+ Task.WaitAll(task);
+ }
+
+ _openStreams.Clear();
+ }
+ }
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 59daa4921..202a051e3 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -1,10 +1,8 @@
-using System.Globalization;
-using MediaBrowser.Common;
+using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.ScheduledTasks;
-using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
@@ -15,7 +13,6 @@ using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Sorting;
-using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.LiveTv;
@@ -342,6 +339,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
var service = GetService(channel);
_logger.Info("Opening channel stream from {0}, external channel Id: {1}", service.Name, channel.ExternalId);
info = await service.GetChannelStream(channel.ExternalId, null, cancellationToken).ConfigureAwait(false);
+ info.RequiresClosing = true;
+ info.CloseKey = info.Id;
}
else
{
@@ -351,6 +350,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv
_logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.RecordingInfo.Id);
info = await service.GetRecordingStream(recording.RecordingInfo.Id, null, cancellationToken).ConfigureAwait(false);
+ info.RequiresClosing = true;
+ info.CloseKey = info.Id;
}
_logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info));
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
new file mode 100644
index 000000000..186bc499d
--- /dev/null
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs
@@ -0,0 +1,77 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Model.Dto;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.LiveTv
+{
+ public class LiveTvMediaSourceProvider : IMediaSourceProvider
+ {
+ private readonly ILiveTvManager _liveTvManager;
+
+ public LiveTvMediaSourceProvider(ILiveTvManager liveTvManager)
+ {
+ _liveTvManager = liveTvManager;
+ }
+
+ public Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken)
+ {
+ var channelItem = item as ILiveTvItem;
+
+ if (channelItem != null)
+ {
+ var hasMetadata = (IHasMetadata)channelItem;
+
+ if (string.IsNullOrWhiteSpace(hasMetadata.Path))
+ {
+ return GetMediaSourcesInternal(channelItem, cancellationToken);
+ }
+ }
+
+ return Task.FromResult<IEnumerable<MediaSourceInfo>>(new List<MediaSourceInfo>());
+ }
+
+ private async Task<IEnumerable<MediaSourceInfo>> GetMediaSourcesInternal(ILiveTvItem item, CancellationToken cancellationToken)
+ {
+ var hasMediaSources = (IHasMediaSources)item;
+
+ var sources = hasMediaSources.GetMediaSources(false)
+ .ToList();
+
+ foreach (var source in sources)
+ {
+ source.Type = MediaSourceType.Default;
+ source.RequiresOpening = true;
+
+ var openKeys = new List<string>();
+ openKeys.Add(item.GetType().Name);
+ openKeys.Add(item.Id.ToString("N"));
+ source.OpenKey = string.Join("|", openKeys.ToArray());
+ }
+
+ return sources;
+ }
+
+ public async Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken)
+ {
+ var keys = openKey.Split(new[] { '|' }, 2);
+
+ if (string.Equals(keys[0], typeof(LiveTvChannel).Name, StringComparison.OrdinalIgnoreCase))
+ {
+ return await _liveTvManager.GetChannelStream(keys[1], cancellationToken).ConfigureAwait(false);
+ }
+
+ return await _liveTvManager.GetRecordingStream(keys[1], cancellationToken).ConfigureAwait(false);
+ }
+
+ public Task CloseMediaSource(string closeKey, CancellationToken cancellationToken)
+ {
+ return _liveTvManager.CloseLiveStream(closeKey, cancellationToken);
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
index 3eb414068..db2397d2f 100644
--- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
+++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj
@@ -111,6 +111,7 @@
<Compile Include="Branding\BrandingConfigurationFactory.cs" />
<Compile Include="Channels\ChannelConfigurations.cs" />
<Compile Include="Channels\ChannelDownloadScheduledTask.cs" />
+ <Compile Include="Channels\ChannelDynamicMediaSourceProvider.cs" />
<Compile Include="Channels\ChannelImageProvider.cs" />
<Compile Include="Channels\ChannelItemImageProvider.cs" />
<Compile Include="Channels\ChannelManager.cs" />
@@ -225,6 +226,7 @@
<Compile Include="LiveTv\LiveTvConfigurationFactory.cs" />
<Compile Include="LiveTv\LiveTvDtoService.cs" />
<Compile Include="LiveTv\LiveTvManager.cs" />
+ <Compile Include="LiveTv\LiveTvMediaSourceProvider.cs" />
<Compile Include="LiveTv\ProgramImageProvider.cs" />
<Compile Include="LiveTv\RecordingImageProvider.cs" />
<Compile Include="LiveTv\RefreshChannelsScheduledTask.cs" />
diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
index 03a7e92a4..dd8ce82ef 100644
--- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
+++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs
@@ -161,6 +161,7 @@ namespace MediaBrowser.Server.Implementations.Sync
{
mediaSource.Path = sendFileResult.Path;
mediaSource.Protocol = sendFileResult.Protocol;
+ mediaSource.RequiredHttpHeaders = sendFileResult.RequiredHttpHeaders;
mediaSource.SupportsTranscoding = false;
}
}
diff --git a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
index 4172cfc2d..25a52fb95 100644
--- a/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
+++ b/MediaBrowser.Server.Implementations/Sync/SyncedMediaSourceProvider.cs
@@ -1,4 +1,5 @@
-using MediaBrowser.Controller;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sync;
@@ -61,7 +62,7 @@ namespace MediaBrowser.Server.Implementations.Sync
{
foreach (var mediaSource in localItem.Item.MediaSources)
{
- await TryAddMediaSource(list, localItem, mediaSource, syncProvider, syncTarget, cancellationToken).ConfigureAwait(false);
+ AddMediaSource(list, localItem, mediaSource, syncProvider, syncTarget);
}
}
}
@@ -71,41 +72,70 @@ namespace MediaBrowser.Server.Implementations.Sync
return list;
}
- private async Task TryAddMediaSource(List<MediaSourceInfo> list,
+ private void AddMediaSource(List<MediaSourceInfo> list,
LocalItem item,
MediaSourceInfo mediaSource,
IServerSyncProvider provider,
- SyncTarget target,
- CancellationToken cancellationToken)
+ SyncTarget target)
{
+ SetStaticMediaSourceInfo(item, mediaSource);
+
var requiresDynamicAccess = provider as IHasDynamicAccess;
- if (requiresDynamicAccess == null)
+ if (requiresDynamicAccess != null)
{
- list.Add(mediaSource);
- return;
+ mediaSource.RequiresOpening = true;
+
+ var keyList = new List<string>();
+ keyList.Add(provider.GetType().FullName.GetMD5().ToString("N"));
+ keyList.Add(target.Id.GetMD5().ToString("N"));
+ keyList.Add(item.Id);
+ mediaSource.OpenKey = string.Join("|", keyList.ToArray());
}
+ }
- try
- {
- var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(item.LocalPath, target, cancellationToken).ConfigureAwait(false);
+ public async Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken)
+ {
+ var openKeys = openKey.Split(new[] { '|' }, 3);
- foreach (var stream in mediaSource.MediaStreams)
- {
- var dynamicStreamInfo = await requiresDynamicAccess.GetSyncedFileInfo(stream.ExternalId, target, cancellationToken).ConfigureAwait(false);
+ var provider = _syncManager.ServerSyncProviders
+ .FirstOrDefault(i => string.Equals(openKeys[0], i.GetType().FullName.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase));
- stream.Path = dynamicStreamInfo.Path;
- }
+ var target = provider.GetAllSyncTargets()
+ .FirstOrDefault(i => string.Equals(openKeys[1], i.Id.GetMD5().ToString("N"), StringComparison.OrdinalIgnoreCase));
- mediaSource.Path = dynamicInfo.Path;
- mediaSource.Protocol = dynamicInfo.Protocol;
+ var dataProvider = _syncManager.GetDataProvider(provider, target);
+ var localItem = await dataProvider.Get(target, openKeys[2]).ConfigureAwait(false);
- list.Add(mediaSource);
- }
- catch (Exception ex)
+ var requiresDynamicAccess = (IHasDynamicAccess)provider;
+ var dynamicInfo = await requiresDynamicAccess.GetSyncedFileInfo(localItem.LocalPath, target, cancellationToken).ConfigureAwait(false);
+
+ var mediaSource = localItem.Item.MediaSources.First();
+ SetStaticMediaSourceInfo(localItem, mediaSource);
+
+ foreach (var stream in mediaSource.MediaStreams)
{
- _logger.ErrorException("Error getting dynamic media source info", ex);
+ var dynamicStreamInfo = await requiresDynamicAccess.GetSyncedFileInfo(stream.ExternalId, target, cancellationToken).ConfigureAwait(false);
+
+ stream.Path = dynamicStreamInfo.Path;
}
+
+ mediaSource.Path = dynamicInfo.Path;
+ mediaSource.Protocol = dynamicInfo.Protocol;
+ mediaSource.RequiredHttpHeaders = dynamicInfo.RequiredHttpHeaders;
+
+ return mediaSource;
+ }
+
+ private void SetStaticMediaSourceInfo(LocalItem item, MediaSourceInfo mediaSource)
+ {
+ mediaSource.Id = item.Id;
+ mediaSource.SupportsTranscoding = false;
+ }
+
+ public Task CloseMediaSource(string closeKey, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
}
}
}