aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2015-03-28 16:22:27 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2015-03-28 16:22:27 -0400
commitbd2ea703e31522d505407a33089b95f997f6b062 (patch)
treece9e3e4ea90c90fda7e287e841813b1aa0675294
parent3add1872c860cae14f85b339fef843ff962574aa (diff)
implement modular media sources
-rw-r--r--MediaBrowser.Api/Playback/BaseStreamingService.cs255
-rw-r--r--MediaBrowser.Api/Playback/Dash/MpegDashService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Hls/BaseHlsService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs11
-rw-r--r--MediaBrowser.Api/Playback/Hls/VideoHlsService.cs2
-rw-r--r--MediaBrowser.Api/Playback/MediaInfoService.cs108
-rw-r--r--MediaBrowser.Api/Playback/Progressive/AudioService.cs6
-rw-r--r--MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs2
-rw-r--r--MediaBrowser.Api/Playback/Progressive/VideoService.cs6
-rw-r--r--MediaBrowser.Api/Playback/StreamState.cs23
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs2
-rw-r--r--MediaBrowser.Controller/Channels/ChannelAudioItem.cs16
-rw-r--r--MediaBrowser.Controller/Channels/ChannelVideoItem.cs16
-rw-r--r--MediaBrowser.Controller/Channels/IChannelManager.cs6
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceManager.cs24
-rw-r--r--MediaBrowser.Controller/Library/IMediaSourceProvider.cs16
-rw-r--r--MediaBrowser.Controller/LiveTv/ILiveTvItem.cs4
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs21
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvChannel.cs2
-rw-r--r--MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs23
-rw-r--r--MediaBrowser.Dlna/PlayTo/PlayToController.cs2
-rw-r--r--MediaBrowser.Model/Dlna/StreamBuilder.cs24
-rw-r--r--MediaBrowser.Model/Dlna/SubtitleProfile.cs27
-rw-r--r--MediaBrowser.Model/Dto/MediaSourceInfo.cs5
-rw-r--r--MediaBrowser.Model/Dto/MediaSourceType.cs2
-rw-r--r--MediaBrowser.Model/Entities/MediaStream.cs5
-rw-r--r--MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs2
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs2
-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
-rw-r--r--MediaBrowser.Server.Startup.Common/ApplicationHost.cs2
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec6
-rw-r--r--Nuget/MediaBrowser.Model.Signed.nuspec6
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec6
42 files changed, 697 insertions, 366 deletions
diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs
index bc194b45b..435bda2c4 100644
--- a/MediaBrowser.Api/Playback/BaseStreamingService.cs
+++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs
@@ -1,6 +1,5 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
@@ -65,7 +64,6 @@ namespace MediaBrowser.Api.Playback
protected IFileSystem FileSystem { get; private set; }
- protected ILiveTvManager LiveTvManager { get; private set; }
protected IDlnaManager DlnaManager { get; private set; }
protected IDeviceManager DeviceManager { get; private set; }
protected ISubtitleEncoder SubtitleEncoder { get; private set; }
@@ -75,14 +73,13 @@ namespace MediaBrowser.Api.Playback
/// <summary>
/// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
/// </summary>
- protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
+ protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
{
ZipClient = zipClient;
MediaSourceManager = mediaSourceManager;
DeviceManager = deviceManager;
SubtitleEncoder = subtitleEncoder;
DlnaManager = dlnaManager;
- LiveTvManager = liveTvManager;
FileSystem = fileSystem;
ServerConfigurationManager = serverConfig;
UserManager = userManager;
@@ -95,11 +92,10 @@ namespace MediaBrowser.Api.Playback
/// Gets the command line arguments.
/// </summary>
/// <param name="outputPath">The output path.</param>
- /// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="state">The state.</param>
/// <param name="isEncoding">if set to <c>true</c> [is encoding].</param>
/// <returns>System.String.</returns>
- protected abstract string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding);
+ protected abstract string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding);
/// <summary>
/// Gets the type of the transcoding job.
@@ -128,7 +124,7 @@ namespace MediaBrowser.Api.Playback
var outputFileExtension = GetOutputFileExtension(state);
- var data = GetCommandLineArguments("dummy\\dummy", "dummyTranscodingId", state, false);
+ var data = GetCommandLineArguments("dummy\\dummy", state, false);
data += "-" + (state.Request.DeviceId ?? string.Empty);
data += "-" + (state.Request.StreamId ?? string.Empty);
@@ -719,8 +715,10 @@ namespace MediaBrowser.Api.Playback
seconds.ToString(UsCulture));
}
+ var mediaPath = state.MediaPath ?? string.Empty;
+
return string.Format("subtitles='{0}:si={1}',setpts=PTS -{2}/TB",
- state.MediaPath.Replace('\\', '/').Replace(":/", "\\:/"),
+ mediaPath.Replace('\\', '/').Replace(":/", "\\:/"),
state.InternalSubtitleStreamOffset.ToString(UsCulture),
seconds.ToString(UsCulture));
}
@@ -895,12 +893,11 @@ namespace MediaBrowser.Api.Playback
/// <summary>
/// Gets the input argument.
/// </summary>
- /// <param name="transcodingJobId">The transcoding job identifier.</param>
/// <param name="state">The state.</param>
/// <returns>System.String.</returns>
- protected string GetInputArgument(string transcodingJobId, StreamState state)
+ protected string GetInputArgument(StreamState state)
{
- var arg = "-i " + GetInputPathArgument(transcodingJobId, state);
+ var arg = "-i " + GetInputPathArgument(state);
if (state.SubtitleStream != null)
{
@@ -913,27 +910,18 @@ namespace MediaBrowser.Api.Playback
return arg;
}
- private string GetInputPathArgument(string transcodingJobId, StreamState state)
+ private string GetInputPathArgument(StreamState state)
{
- //if (state.InputProtocol == MediaProtocol.File &&
- // state.RunTimeTicks.HasValue &&
- // state.VideoType == VideoType.VideoFile &&
- // !string.Equals(state.OutputVideoCodec, "copy", StringComparison.OrdinalIgnoreCase))
- //{
- // if (state.RunTimeTicks.Value >= TimeSpan.FromMinutes(5).Ticks && state.IsInputVideo)
- // {
- // }
- //}
-
var protocol = state.InputProtocol;
+ var mediaPath = state.MediaPath ?? string.Empty;
- var inputPath = new[] { state.MediaPath };
+ var inputPath = new[] { mediaPath };
if (state.IsInputVideo)
{
if (!(state.VideoType == VideoType.Iso && state.IsoMount == null))
{
- inputPath = MediaEncoderHelpers.GetInputArgument(state.MediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
+ inputPath = MediaEncoderHelpers.GetInputArgument(mediaPath, state.InputProtocol, state.IsoMount, state.PlayableStreamFileNames);
}
}
@@ -947,55 +935,20 @@ namespace MediaBrowser.Api.Playback
state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false);
}
- if (string.IsNullOrEmpty(state.MediaPath))
+ if (state.MediaSource.RequiresOpening)
{
- var checkCodecs = false;
-
- if (string.Equals(state.ItemType, typeof(LiveTvChannel).Name))
- {
- var streamInfo = await LiveTvManager.GetChannelStream(state.Request.Id, cancellationTokenSource.Token).ConfigureAwait(false);
+ var mediaSource = await MediaSourceManager.OpenMediaSource(state.MediaSource.OpenKey, cancellationTokenSource.Token)
+ .ConfigureAwait(false);
- state.LiveTvStreamId = streamInfo.Id;
+ AttachMediaSourceInfo(state, mediaSource, state.VideoRequest, state.RequestedUrl);
- state.MediaPath = streamInfo.Path;
- state.InputProtocol = streamInfo.Protocol;
-
- await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
-
- AttachMediaStreamInfo(state, streamInfo, state.VideoRequest, state.RequestedUrl);
- checkCodecs = true;
- }
-
- else if (string.Equals(state.ItemType, typeof(LiveTvVideoRecording).Name) ||
- string.Equals(state.ItemType, typeof(LiveTvAudioRecording).Name))
+ if (state.VideoRequest != null)
{
- var streamInfo = await LiveTvManager.GetRecordingStream(state.Request.Id, cancellationTokenSource.Token).ConfigureAwait(false);
-
- state.LiveTvStreamId = streamInfo.Id;
-
- state.MediaPath = streamInfo.Path;
- state.InputProtocol = streamInfo.Protocol;
-
- await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
-
- AttachMediaStreamInfo(state, streamInfo, state.VideoRequest, state.RequestedUrl);
- checkCodecs = true;
+ TryStreamCopy(state, state.VideoRequest);
}
- var videoRequest = state.VideoRequest;
-
- if (videoRequest != null && checkCodecs)
- {
- if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
- {
- state.OutputVideoCodec = "copy";
- }
-
- if (state.AudioStream != null && CanStreamCopyAudio(videoRequest, state.AudioStream, state.SupportedAudioCodecs))
- {
- state.OutputAudioCodec = "copy";
- }
- }
+ // TODO: This is only needed for live tv
+ await Task.Delay(1500, cancellationTokenSource.Token).ConfigureAwait(false);
}
}
@@ -1017,7 +970,7 @@ namespace MediaBrowser.Api.Playback
await AcquireResources(state, cancellationTokenSource).ConfigureAwait(false);
var transcodingId = Guid.NewGuid().ToString("N");
- var commandLineArgs = GetCommandLineArguments(outputPath, transcodingId, state, true);
+ var commandLineArgs = GetCommandLineArguments(outputPath, state, true);
if (ApiEntryPoint.Instance.GetEncodingOptions().EnableDebugLogging)
{
@@ -1644,7 +1597,7 @@ namespace MediaBrowser.Api.Playback
request.AudioCodec = InferAudioCodec(url);
}
- var state = new StreamState(LiveTvManager, Logger)
+ var state = new StreamState(MediaSourceManager, Logger)
{
Request = request,
RequestedUrl = url
@@ -1658,109 +1611,20 @@ namespace MediaBrowser.Api.Playback
var item = LibraryManager.GetItemById(request.Id);
- List<MediaStream> mediaStreams = null;
+ state.IsInputVideo = string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
- state.ItemType = item.GetType().Name;
- state.ItemId = item.Id.ToString("N");
var archivable = item as IArchivable;
state.IsInputArchive = archivable != null && archivable.IsArchive;
- if (item is ILiveTvRecording)
- {
- var recording = await LiveTvManager.GetInternalRecording(request.Id, cancellationToken).ConfigureAwait(false);
-
- state.VideoType = VideoType.VideoFile;
- state.IsInputVideo = string.Equals(recording.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
-
- var path = recording.RecordingInfo.Path;
- var mediaUrl = recording.RecordingInfo.Url;
-
- var source = string.IsNullOrEmpty(request.MediaSourceId)
- ? recording.GetMediaSources(false).First()
- : MediaSourceManager.GetStaticMediaSource(recording, request.MediaSourceId, false);
-
- mediaStreams = source.MediaStreams;
-
- // Just to prevent this from being null and causing other methods to fail
- state.MediaPath = string.Empty;
-
- if (!string.IsNullOrEmpty(path))
- {
- state.MediaPath = path;
- state.InputProtocol = MediaProtocol.File;
- }
- else if (!string.IsNullOrEmpty(mediaUrl))
- {
- state.MediaPath = mediaUrl;
- state.InputProtocol = MediaProtocol.Http;
- }
-
- state.RunTimeTicks = recording.RunTimeTicks;
- state.DeInterlace = true;
- state.OutputAudioSync = "1000";
- state.InputVideoSync = "-1";
- state.InputAudioSync = "1";
- state.InputContainer = recording.Container;
- state.ReadInputAtNativeFramerate = source.ReadAtNativeFramerate;
- }
- else if (item is LiveTvChannel)
- {
- var channel = LiveTvManager.GetInternalChannel(request.Id);
-
- state.VideoType = VideoType.VideoFile;
- state.IsInputVideo = string.Equals(channel.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase);
- mediaStreams = new List<MediaStream>();
-
- state.DeInterlace = true;
-
- // Just to prevent this from being null and causing other methods to fail
- state.MediaPath = string.Empty;
- }
- else
- {
- var mediaSources = await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false);
-
- var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
- ? mediaSources.First()
- : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
-
- mediaStreams = mediaSource.MediaStreams;
-
- state.MediaPath = mediaSource.Path;
- state.InputProtocol = mediaSource.Protocol;
- state.InputContainer = mediaSource.Container;
- state.InputFileSize = mediaSource.Size;
- state.InputBitrate = mediaSource.Bitrate;
- state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
- state.RunTimeTicks = mediaSource.RunTimeTicks;
- state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
-
- var video = item as Video;
-
- if (video != null)
- {
- state.IsInputVideo = true;
-
- if (mediaSource.VideoType.HasValue)
- {
- state.VideoType = mediaSource.VideoType.Value;
- }
-
- state.IsoType = mediaSource.IsoType;
-
- state.PlayableStreamFileNames = mediaSource.PlayableStreamFileNames.ToList();
-
- if (mediaSource.Timestamp.HasValue)
- {
- state.InputTimestamp = mediaSource.Timestamp.Value;
- }
- }
-
- }
+ var mediaSources = await MediaSourceManager.GetPlayackMediaSources(request.Id, false, cancellationToken).ConfigureAwait(false);
+ var mediaSource = string.IsNullOrEmpty(request.MediaSourceId)
+ ? mediaSources.First()
+ : mediaSources.First(i => string.Equals(i.Id, request.MediaSourceId));
+
var videoRequest = request as VideoStreamRequest;
- AttachMediaStreamInfo(state, mediaStreams, videoRequest, url);
+ AttachMediaSourceInfo(state, mediaSource, videoRequest, url);
var container = Path.GetExtension(state.RequestedUrl);
@@ -1801,15 +1665,7 @@ namespace MediaBrowser.Api.Playback
if (videoRequest != null)
{
- if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
- {
- state.OutputVideoCodec = "copy";
- }
-
- if (state.AudioStream != null && CanStreamCopyAudio(videoRequest, state.AudioStream, state.SupportedAudioCodecs))
- {
- state.OutputAudioCodec = "copy";
- }
+ TryStreamCopy(state, videoRequest);
}
state.OutputFilePath = GetOutputFilePath(state);
@@ -1817,11 +1673,47 @@ namespace MediaBrowser.Api.Playback
return state;
}
- private void AttachMediaStreamInfo(StreamState state,
+ private void TryStreamCopy(StreamState state, VideoStreamRequest videoRequest)
+ {
+ if (state.VideoStream != null && CanStreamCopyVideo(videoRequest, state.VideoStream))
+ {
+ state.OutputVideoCodec = "copy";
+ }
+
+ if (state.AudioStream != null && CanStreamCopyAudio(videoRequest, state.AudioStream, state.SupportedAudioCodecs))
+ {
+ state.OutputAudioCodec = "copy";
+ }
+ }
+
+ private void AttachMediaSourceInfo(StreamState state,
MediaSourceInfo mediaSource,
VideoStreamRequest videoRequest,
string requestedUrl)
{
+ state.MediaPath = mediaSource.Path;
+ state.InputProtocol = mediaSource.Protocol;
+ state.InputContainer = mediaSource.Container;
+ state.InputFileSize = mediaSource.Size;
+ state.InputBitrate = mediaSource.Bitrate;
+ state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
+ state.RunTimeTicks = mediaSource.RunTimeTicks;
+ state.RemoteHttpHeaders = mediaSource.RequiredHttpHeaders;
+
+ if (mediaSource.VideoType.HasValue)
+ {
+ state.VideoType = mediaSource.VideoType.Value;
+ }
+
+ state.IsoType = mediaSource.IsoType;
+
+ state.PlayableStreamFileNames = mediaSource.PlayableStreamFileNames.ToList();
+
+ if (mediaSource.Timestamp.HasValue)
+ {
+ state.InputTimestamp = mediaSource.Timestamp.Value;
+ }
+
state.InputProtocol = mediaSource.Protocol;
state.MediaPath = mediaSource.Path;
state.RunTimeTicks = mediaSource.RunTimeTicks;
@@ -1830,21 +1722,16 @@ namespace MediaBrowser.Api.Playback
state.InputFileSize = mediaSource.Size;
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
- if (state.ReadInputAtNativeFramerate)
+ if (state.ReadInputAtNativeFramerate ||
+ mediaSource.Protocol == MediaProtocol.File && string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
{
state.OutputAudioSync = "1000";
state.InputVideoSync = "-1";
state.InputAudioSync = "1";
}
- AttachMediaStreamInfo(state, mediaSource.MediaStreams, videoRequest, requestedUrl);
- }
+ var mediaStreams = mediaSource.MediaStreams;
- private void AttachMediaStreamInfo(StreamState state,
- List<MediaStream> mediaStreams,
- VideoStreamRequest videoRequest,
- string requestedUrl)
- {
if (videoRequest != null)
{
if (string.IsNullOrEmpty(videoRequest.VideoCodec))
@@ -1873,7 +1760,7 @@ namespace MediaBrowser.Api.Playback
state.AudioStream = GetMediaStream(mediaStreams, null, MediaStreamType.Audio, true);
}
- state.AllMediaStreams = mediaStreams;
+ state.MediaSource = mediaSource;
}
private bool CanStreamCopyVideo(VideoStreamRequest request, MediaStream videoStream)
diff --git a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
index 3c3f4c039..692e8d4e7 100644
--- a/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
+++ b/MediaBrowser.Api/Playback/Dash/MpegDashService.cs
@@ -54,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
public class MpegDashService : BaseHlsService
{
- public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+ public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
{
NetworkManager = networkManager;
}
@@ -447,7 +447,7 @@ namespace MediaBrowser.Api.Playback.Dash
return args;
}
- protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+ protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
// test url http://192.168.1.2:8096/videos/233e8905d559a8f230db9bffd2ac9d6d/master.mpd?mediasourceid=233e8905d559a8f230db9bffd2ac9d6d&videocodec=h264&audiocodec=aac&maxwidth=1280&videobitrate=500000&audiobitrate=128000&profile=baseline&level=3
// Good info on i-frames http://blog.streamroot.io/encode-multi-bitrate-videos-mpeg-dash-mse-based-media-players/
@@ -461,7 +461,7 @@ namespace MediaBrowser.Api.Playback.Dash
var args = string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts {5} -f dash -init_seg_name \"{6}\" -media_seg_name \"{7}\" -use_template 0 -use_timeline 1 -min_seg_duration {8} -y \"{9}\"",
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
threads,
GetMapArgs(state),
GetVideoArguments(state),
diff --git a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
index 09574e772..207bc2f67 100644
--- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public abstract class BaseHlsService : BaseStreamingService
{
- protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+ protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
{
}
@@ -212,7 +212,7 @@ namespace MediaBrowser.Api.Playback.Hls
}
}
- protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+ protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
var hlsVideoRequest = state.VideoRequest as GetHlsVideoStream;
@@ -240,7 +240,7 @@ namespace MediaBrowser.Api.Playback.Hls
var args = string.Format("{0} {1} {2} -map_metadata -1 -threads {3} {4} {5} -sc_threshold 0 {6} -hls_time {7} -start_number {8} -hls_list_size {9}{10} -y \"{11}\"",
itsOffset,
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
threads,
GetMapArgs(state),
GetVideoArguments(state),
diff --git a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
index 48523e255..b166bc319 100644
--- a/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
public class DynamicHlsService : BaseHlsService
{
- public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+ public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
{
NetworkManager = networkManager;
}
@@ -414,7 +414,8 @@ namespace MediaBrowser.Api.Playback.Hls
var request = (GetMasterHlsVideoStream)state.Request;
- var subtitleStreams = state.AllMediaStreams
+ var subtitleStreams = state.MediaSource
+ .MediaStreams
.Where(i => i.IsTextSubtitleStream)
.ToList();
@@ -684,7 +685,7 @@ namespace MediaBrowser.Api.Playback.Hls
return args;
}
- protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+ protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
var threads = GetNumberOfThreads(state, false);
@@ -699,7 +700,7 @@ namespace MediaBrowser.Api.Playback.Hls
return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -f segment -segment_time {6} -segment_start_number {7} -segment_list \"{8}\" -y \"{9}\"",
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
threads,
GetMapArgs(state),
GetVideoArguments(state),
@@ -713,7 +714,7 @@ namespace MediaBrowser.Api.Playback.Hls
return string.Format("{0} {1} -map_metadata -1 -threads {2} {3} {4} -copyts -flags -global_header {5} -hls_time {6} -start_number {7} -hls_list_size {8} -y \"{9}\"",
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
threads,
GetMapArgs(state),
GetVideoArguments(state),
diff --git a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
index e1baf8c12..b1964f4ae 100644
--- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
+++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
@@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback.Hls
/// </summary>
public class VideoHlsService : BaseHlsService
{
- public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+ public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
{
}
diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs
index e219f4186..cef8a34e5 100644
--- a/MediaBrowser.Api/Playback/MediaInfoService.cs
+++ b/MediaBrowser.Api/Playback/MediaInfoService.cs
@@ -4,6 +4,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Session;
using ServiceStack;
@@ -38,20 +39,23 @@ namespace MediaBrowser.Api.Playback
[Route("/Items/{Id}/PlaybackInfo", "POST", Summary = "Gets live playback media info for an item")]
public class GetPostedPlaybackInfo : PlaybackInfoRequest, IReturn<PlaybackInfoResponse>
{
- [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ [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 = "GET")]
+ [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")]
public string UserId { get; set; }
- [ApiMember(Name = "StartTimeTicks", Description = "Optional. Specify a starting offset, in ticks. 1 tick = 10000 ms", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
+ [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 = "GET")]
+ [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 = "GET")]
+ [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; }
}
[Authenticated]
@@ -82,7 +86,7 @@ namespace MediaBrowser.Api.Playback
public async Task<object> Post(GetPostedPlaybackInfo request)
{
- var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSource).ConfigureAwait(false);
+ var info = await GetPlaybackInfo(request.Id, request.UserId, request.MediaSourceId).ConfigureAwait(false);
var authInfo = AuthorizationContext.GetAuthorizationInfo(Request);
var profile = request.DeviceProfile;
@@ -97,36 +101,36 @@ namespace MediaBrowser.Api.Playback
if (profile != null)
{
- var mediaSourceId = request.MediaSource == null ? null : request.MediaSource.Id;
+ var mediaSourceId = request.MediaSourceId;
SetDeviceSpecificData(request.Id, info, profile, authInfo, null, request.StartTimeTicks ?? 0, mediaSourceId, request.AudioStreamIndex, request.SubtitleStreamIndex);
}
return ToOptimizedResult(info);
}
- private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, MediaSourceInfo mediaSource = null)
+ private async Task<PlaybackInfoResponse> GetPlaybackInfo(string id, string userId, string mediaSourceId = null)
{
var result = new PlaybackInfoResponse();
- if (mediaSource == null)
+ IEnumerable<MediaSourceInfo> mediaSources;
+
+ try
{
- IEnumerable<MediaSourceInfo> mediaSources;
+ mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
+ }
+ catch (PlaybackException ex)
+ {
+ mediaSources = new List<MediaSourceInfo>();
+ result.ErrorCode = ex.ErrorCode;
+ }
- try
- {
- mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false);
- }
- catch (PlaybackException ex)
- {
- mediaSources = new List<MediaSourceInfo>();
- result.ErrorCode = ex.ErrorCode;
- }
+ result.MediaSources = mediaSources.ToList();
- result.MediaSources = mediaSources.ToList();
- }
- else
+ if (!string.IsNullOrWhiteSpace(mediaSourceId))
{
- result.MediaSources = new List<MediaSourceInfo> { mediaSource };
+ result.MediaSources = result.MediaSources
+ .Where(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase))
+ .ToList();
}
if (result.MediaSources.Count == 0)
@@ -185,9 +189,9 @@ namespace MediaBrowser.Api.Playback
mediaSource.SupportsDirectStream = true;
// The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = item is Video ?
- streamBuilder.BuildVideoItem(options) :
- streamBuilder.BuildAudioItem(options);
+ var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
+ streamBuilder.BuildAudioItem(options) :
+ streamBuilder.BuildVideoItem(options);
if (streamInfo == null || !streamInfo.IsDirectStream)
{
@@ -201,9 +205,9 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsDirectStream)
{
// The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = item is Video ?
- streamBuilder.BuildVideoItem(options) :
- streamBuilder.BuildAudioItem(options);
+ var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
+ streamBuilder.BuildAudioItem(options) :
+ streamBuilder.BuildVideoItem(options);
if (streamInfo == null || !streamInfo.IsDirectStream)
{
@@ -214,9 +218,9 @@ namespace MediaBrowser.Api.Playback
if (mediaSource.SupportsTranscoding)
{
// The MediaSource supports direct stream, now test to see if the client supports it
- var streamInfo = item is Video ?
- streamBuilder.BuildVideoItem(options) :
- streamBuilder.BuildAudioItem(options);
+ var streamInfo = string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase) ?
+ streamBuilder.BuildAudioItem(options) :
+ streamBuilder.BuildVideoItem(options);
if (streamInfo != null && streamInfo.PlayMethod == PlayMethod.Transcode)
{
@@ -227,6 +231,46 @@ namespace MediaBrowser.Api.Playback
}
}
}
+
+ SortMediaSources(result);
+ }
+
+ private void SortMediaSources(PlaybackInfoResponse result)
+ {
+ var originalList = result.MediaSources.ToList();
+
+ result.MediaSources = result.MediaSources.OrderBy(i =>
+ {
+ // Nothing beats direct playing a file
+ if (i.SupportsDirectPlay && i.Protocol == MediaProtocol.File)
+ {
+ return 0;
+ }
+
+ return 1;
+
+ }).ThenBy(i =>
+ {
+ // Let's assume direct streaming a file is just as desirable as direct playing a remote url
+ if (i.SupportsDirectPlay || i.SupportsDirectStream)
+ {
+ return 0;
+ }
+
+ return 1;
+
+ }).ThenBy(i =>
+ {
+ switch (i.Protocol)
+ {
+ case MediaProtocol.File:
+ return 0;
+ default:
+ return 1;
+ }
+
+ }).ThenBy(originalList.IndexOf)
+ .ToList();
}
}
}
diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
index af2cf6b03..fee501159 100644
--- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs
@@ -31,7 +31,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class AudioService : BaseProgressiveStreamingService
{
- public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+ public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
{
}
@@ -55,7 +55,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return ProcessRequest(request, true);
}
- protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+ protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
var audioTranscodeParams = new List<string>();
@@ -84,7 +84,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return string.Format("{0} {1} -threads {2}{3} {4} -id3v2_version 3 -write_id3v1 1 -y \"{5}\"",
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
threads,
vn,
string.Join(" ", audioTranscodeParams.ToArray()),
diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
index 7a2990e2a..8ed17ca17 100644
--- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
@@ -27,7 +27,7 @@ namespace MediaBrowser.Api.Playback.Progressive
protected readonly IImageProcessor ImageProcessor;
protected readonly IHttpClient HttpClient;
- protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+ protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
{
ImageProcessor = imageProcessor;
HttpClient = httpClient;
diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
index eb18288e9..540c39a0c 100644
--- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs
+++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs
@@ -62,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
/// </summary>
public class VideoService : BaseProgressiveStreamingService
{
- public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, ILiveTvManager liveTvManager, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, liveTvManager, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+ public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
{
}
@@ -86,7 +86,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return ProcessRequest(request, true);
}
- protected override string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding)
+ protected override string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding)
{
// Get the output codec name
var videoCodec = state.OutputVideoCodec;
@@ -106,7 +106,7 @@ namespace MediaBrowser.Api.Playback.Progressive
return string.Format("{0} {1}{2} {3} {4} -map_metadata -1 -threads {5} {6}{7} -y \"{8}\"",
inputModifier,
- GetInputArgument(transcodingJobId, state),
+ GetInputArgument(state),
keyFrame,
GetMapArgs(state),
GetVideoArguments(state, videoCodec),
diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs
index 1d4dd1aaf..37f2c7702 100644
--- a/MediaBrowser.Api/Playback/StreamState.cs
+++ b/MediaBrowser.Api/Playback/StreamState.cs
@@ -1,6 +1,7 @@
-using MediaBrowser.Controller.LiveTv;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
@@ -17,7 +18,7 @@ namespace MediaBrowser.Api.Playback
public class StreamState : IDisposable
{
private readonly ILogger _logger;
- private readonly ILiveTvManager _liveTvManager;
+ private readonly IMediaSourceManager _mediaSourceManager;
public string RequestedUrl { get; set; }
@@ -39,7 +40,7 @@ namespace MediaBrowser.Api.Playback
public string InputContainer { get; set; }
- public List<MediaStream> AllMediaStreams { get; set; }
+ public MediaSourceInfo MediaSource { get; set; }
public MediaStream AudioStream { get; set; }
public MediaStream VideoStream { get; set; }
@@ -64,8 +65,6 @@ namespace MediaBrowser.Api.Playback
public List<string> PlayableStreamFileNames { get; set; }
- public string LiveTvStreamId { get; set; }
-
public int SegmentLength = 3;
public bool EnableGenericHlsSegmenter = false;
public int HlsListSize
@@ -86,14 +85,13 @@ namespace MediaBrowser.Api.Playback
public List<string> SupportedAudioCodecs { get; set; }
- public StreamState(ILiveTvManager liveTvManager, ILogger logger)
+ public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger)
{
- _liveTvManager = liveTvManager;
+ _mediaSourceManager = mediaSourceManager;
_logger = logger;
SupportedAudioCodecs = new List<string>();
PlayableStreamFileNames = new List<string>();
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
- AllMediaStreams = new List<MediaStream>();
}
public string InputAudioSync { get; set; }
@@ -113,9 +111,6 @@ namespace MediaBrowser.Api.Playback
public long? EncodingDurationTicks { get; set; }
- public string ItemType { get; set; }
- public string ItemId { get; set; }
-
public string GetMimeType(string outputPath)
{
if (!string.IsNullOrEmpty(MimeType))
@@ -187,15 +182,15 @@ namespace MediaBrowser.Api.Playback
private async void DisposeLiveStream()
{
- if (!string.IsNullOrEmpty(LiveTvStreamId))
+ if (MediaSource.RequiresClosing)
{
try
{
- await _liveTvManager.CloseLiveStream(LiveTvStreamId, CancellationToken.None).ConfigureAwait(false);
+ await _mediaSourceManager.CloseMediaSource(MediaSource.CloseKey, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
- _logger.ErrorException("Error closing live tv stream", ex);
+ _logger.ErrorException("Error closing media source", ex);
}
}
}
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 07eb74e81..73589d677 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -192,7 +192,7 @@ namespace MediaBrowser.Api.Subtitles
{
var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
- var mediaSource = item.GetMediaSources(false)
+ var mediaSource = _mediaSourceManager.GetStaticMediaSources(item, false, null)
.First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));
var subtitleStream = mediaSource.MediaStreams
diff --git a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
index 91b2407be..8d9024676 100644
--- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs
@@ -75,17 +75,23 @@ namespace MediaBrowser.Controller.Channels
public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
- var list = base.GetMediaSources(enablePathSubstitution).ToList();
-
- var sources = ChannelManager.GetChannelItemMediaSources(Id.ToString("N"), false, CancellationToken.None)
- .Result.ToList();
+ var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None)
+ .Result.ToList();
if (sources.Count > 0)
{
return sources;
}
- list.InsertRange(0, sources);
+ var list = base.GetMediaSources(enablePathSubstitution).ToList();
+
+ foreach (var mediaSource in list)
+ {
+ if (string.IsNullOrWhiteSpace(mediaSource.Path))
+ {
+ mediaSource.Type = MediaSourceType.Placeholder;
+ }
+ }
return list;
}
diff --git a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
index d7d4483cd..8eec2021b 100644
--- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
+++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs
@@ -90,17 +90,23 @@ namespace MediaBrowser.Controller.Channels
public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
{
- var list = base.GetMediaSources(enablePathSubstitution).ToList();
-
- var sources = ChannelManager.GetChannelItemMediaSources(Id.ToString("N"), false, CancellationToken.None)
- .Result.ToList();
+ var sources = ChannelManager.GetStaticMediaSources(this, false, CancellationToken.None)
+ .Result.ToList();
if (sources.Count > 0)
{
return sources;
}
- list.InsertRange(0, sources);
+ var list = base.GetMediaSources(enablePathSubstitution).ToList();
+
+ foreach (var mediaSource in list)
+ {
+ if (string.IsNullOrWhiteSpace(mediaSource.Path))
+ {
+ mediaSource.Type = MediaSourceType.Placeholder;
+ }
+ }
return list;
}
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs
index 05015da37..f5c4ab373 100644
--- a/MediaBrowser.Controller/Channels/IChannelManager.cs
+++ b/MediaBrowser.Controller/Channels/IChannelManager.cs
@@ -112,11 +112,11 @@ namespace MediaBrowser.Controller.Channels
/// <summary>
/// Gets the channel item media sources.
/// </summary>
- /// <param name="id">The identifier.</param>
- /// <param name="includeDynamicSources">if set to <c>true</c> [include dynamic sources].</param>
+ /// <param name="item">The item.</param>
+ /// <param name="includeCachedVersions">if set to <c>true</c> [include cached versions].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
- Task<IEnumerable<MediaSourceInfo>> GetChannelItemMediaSources(string id, bool includeDynamicSources, CancellationToken cancellationToken);
+ Task<IEnumerable<MediaSourceInfo>> GetStaticMediaSources(IChannelMediaItem item, bool includeCachedVersions, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel folder.
diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
index c21fed6fc..fda17aa27 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs
@@ -65,6 +65,14 @@ namespace MediaBrowser.Controller.Library
IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user);
/// <summary>
+ /// Gets the static media sources.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
+ /// <returns>IEnumerable&lt;MediaSourceInfo&gt;.</returns>
+ IEnumerable<MediaSourceInfo> GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution);
+
+ /// <summary>
/// Gets the static media source.
/// </summary>
/// <param name="item">The item.</param>
@@ -72,5 +80,21 @@ namespace MediaBrowser.Controller.Library
/// <param name="enablePathSubstitution">if set to <c>true</c> [enable path substitution].</param>
/// <returns>MediaSourceInfo.</returns>
MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution);
+
+ /// <summary>
+ /// Opens the media source.
+ /// </summary>
+ /// <param name="openKey">The open key.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
+ Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Closes the media source.
+ /// </summary>
+ /// <param name="closeKey">The close key.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CloseMediaSource(string closeKey, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
index 461285d6c..c5f5b5401 100644
--- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
+++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs
@@ -15,5 +15,21 @@ namespace MediaBrowser.Controller.Library
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task&lt;IEnumerable&lt;MediaSourceInfo&gt;&gt;.</returns>
Task<IEnumerable<MediaSourceInfo>> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Opens the media source.
+ /// </summary>
+ /// <param name="openKey">The open key.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task&lt;MediaSourceInfo&gt;.</returns>
+ Task<MediaSourceInfo> OpenMediaSource(string openKey, CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Closes the media source.
+ /// </summary>
+ /// <param name="closeKey">The close key.</param>
+ /// <param name="cancellationToken">The cancellation token.</param>
+ /// <returns>Task.</returns>
+ Task CloseMediaSource(string closeKey, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs b/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs
index d3334e8ea..6c277a2e1 100644
--- a/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs
+++ b/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs
@@ -1,8 +1,10 @@
-
+using System;
+
namespace MediaBrowser.Controller.LiveTv
{
public interface ILiveTvItem
{
+ Guid Id { get; }
string ServiceName { get; set; }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
index 9815066ef..0dc296d5a 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvAudioRecording.cs
@@ -1,10 +1,12 @@
-using System.Runtime.Serialization;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Users;
+using System.Collections.Generic;
using System.Linq;
+using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@@ -99,5 +101,20 @@ namespace MediaBrowser.Controller.LiveTv
{
return user.Policy.EnableLiveTvManagement;
}
+
+ public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ {
+ var list = base.GetMediaSources(enablePathSubstitution).ToList();
+
+ foreach (var mediaSource in list)
+ {
+ if (string.IsNullOrWhiteSpace(mediaSource.Path))
+ {
+ mediaSource.Type = MediaSourceType.Placeholder;
+ }
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
index 75e418bcc..1e13d8f3f 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvChannel.cs
@@ -127,7 +127,7 @@ namespace MediaBrowser.Controller.LiveTv
Name = Name,
Path = Path,
RunTimeTicks = RunTimeTicks,
- Type = MediaSourceType.Default
+ Type = MediaSourceType.Placeholder
};
list.Add(info);
diff --git a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
index 207684d55..3669f9440 100644
--- a/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
+++ b/MediaBrowser.Controller/LiveTv/LiveTvVideoRecording.cs
@@ -1,9 +1,11 @@
-using System.Runtime.Serialization;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
-using System.Linq;
using MediaBrowser.Model.Users;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.Serialization;
namespace MediaBrowser.Controller.LiveTv
{
@@ -97,5 +99,20 @@ namespace MediaBrowser.Controller.LiveTv
{
return user.Policy.EnableLiveTvManagement;
}
+
+ public override IEnumerable<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution)
+ {
+ var list = base.GetMediaSources(enablePathSubstitution).ToList();
+
+ foreach (var mediaSource in list)
+ {
+ if (string.IsNullOrWhiteSpace(mediaSource.Path))
+ {
+ mediaSource.Type = MediaSourceType.Placeholder;
+ }
+ }
+
+ return list;
+ }
}
}
diff --git a/MediaBrowser.Dlna/PlayTo/PlayToController.cs b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
index f8f939f47..17385bda6 100644
--- a/MediaBrowser.Dlna/PlayTo/PlayToController.cs
+++ b/MediaBrowser.Dlna/PlayTo/PlayToController.cs
@@ -476,7 +476,7 @@ namespace MediaBrowser.Dlna.PlayTo
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
playlistItem.StreamInfo.StartPositionTicks = startPostionTicks;
- playlistItem.StreamUrl = playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken);
+ playlistItem.StreamUrl = playlistItem.StreamInfo.ToDlnaUrl(_serverAddress, _accessToken);
var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager)
.GetItemDidl(item, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 62ac321fe..6534eda10 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -239,6 +239,16 @@ namespace MediaBrowser.Model.Dlna
return playlistItem;
}
+ private int? GetBitrateForDirectPlayCheck(MediaSourceInfo item, AudioOptions options)
+ {
+ if (item.Protocol == MediaProtocol.File)
+ {
+ return options.Profile.MaxStaticBitrate;
+ }
+
+ return options.GetMaxBitrate();
+ }
+
private List<PlayMethod> GetAudioDirectPlayMethods(MediaSourceInfo item, MediaStream audioStream, AudioOptions options)
{
DirectPlayProfile directPlayProfile = null;
@@ -263,7 +273,7 @@ namespace MediaBrowser.Model.Dlna
// The profile describes what the device supports
// If device requirements are satisfied then allow both direct stream and direct play
- if (IsAudioEligibleForDirectPlay(item, options.Profile.MaxStaticBitrate))
+ if (IsAudioEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options)))
{
playMethods.Add(PlayMethod.DirectPlay);
}
@@ -293,7 +303,7 @@ namespace MediaBrowser.Model.Dlna
MediaStream videoStream = item.VideoStream;
// TODO: This doesn't accout for situation of device being able to handle media bitrate, but wifi connection not fast enough
- bool isEligibleForDirectPlay = IsEligibleForDirectPlay(item, options.Profile.MaxStaticBitrate, subtitleStream, options);
+ bool isEligibleForDirectPlay = IsEligibleForDirectPlay(item, GetBitrateForDirectPlayCheck(item, options), subtitleStream, options);
bool isEligibleForDirectStream = IsEligibleForDirectPlay(item, options.GetMaxBitrate(), subtitleStream, options);
if (isEligibleForDirectPlay || isEligibleForDirectStream)
@@ -604,6 +614,11 @@ namespace MediaBrowser.Model.Dlna
// Look for an external profile that matches the stream type (text/graphical)
foreach (SubtitleProfile profile in subtitleProfiles)
{
+ if (!profile.SupportsLanguage(subtitleStream.Language))
+ {
+ continue;
+ }
+
if (profile.Method == SubtitleDeliveryMethod.External && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
{
if (subtitleStream.SupportsExternalStream)
@@ -621,6 +636,11 @@ namespace MediaBrowser.Model.Dlna
foreach (SubtitleProfile profile in subtitleProfiles)
{
+ if (!profile.SupportsLanguage(subtitleStream.Language))
+ {
+ continue;
+ }
+
if (profile.Method == SubtitleDeliveryMethod.Embed && subtitleStream.IsTextSubtitleStream == MediaStream.IsTextFormat(profile.Format))
{
return profile;
diff --git a/MediaBrowser.Model/Dlna/SubtitleProfile.cs b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
index d3989829c..1795c374a 100644
--- a/MediaBrowser.Model/Dlna/SubtitleProfile.cs
+++ b/MediaBrowser.Model/Dlna/SubtitleProfile.cs
@@ -1,4 +1,6 @@
-using System.Xml.Serialization;
+using MediaBrowser.Model.Extensions;
+using System.Collections.Generic;
+using System.Xml.Serialization;
namespace MediaBrowser.Model.Dlna
{
@@ -13,5 +15,28 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("didlMode")]
public string DidlMode { get; set; }
+ [XmlAttribute("language")]
+ public string Language { get; set; }
+
+ public List<string> GetLanguages()
+ {
+ List<string> list = new List<string>();
+ foreach (string i in (Language ?? string.Empty).Split(','))
+ {
+ if (!string.IsNullOrEmpty(i)) list.Add(i);
+ }
+ return list;
+ }
+
+ public bool SupportsLanguage(string language)
+ {
+ if (string.IsNullOrEmpty(language))
+ {
+ language = "und";
+ }
+
+ List<string> languages = GetLanguages();
+ return languages.Count == 0 || ListHelper.ContainsIgnoreCase(languages, language);
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index 31d310acd..92af8d671 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -26,6 +26,11 @@ namespace MediaBrowser.Model.Dto
public bool SupportsDirectStream { get; set; }
public bool SupportsDirectPlay { get; set; }
+ public bool RequiresOpening { get; set; }
+ public string OpenKey { get; set; }
+ public bool RequiresClosing { get; set; }
+ public string CloseKey { get; set; }
+
public VideoType? VideoType { get; set; }
public IsoType? IsoType { get; set; }
diff --git a/MediaBrowser.Model/Dto/MediaSourceType.cs b/MediaBrowser.Model/Dto/MediaSourceType.cs
index a9cd71df5..e04978502 100644
--- a/MediaBrowser.Model/Dto/MediaSourceType.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceType.cs
@@ -4,6 +4,6 @@ namespace MediaBrowser.Model.Dto
{
Default = 0,
Grouping = 1,
- Cache = 2
+ Placeholder = 2
}
} \ No newline at end of file
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index 66fb48628..fa075490a 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -141,6 +141,11 @@ namespace MediaBrowser.Model.Entities
{
if (Type != MediaStreamType.Subtitle) return false;
+ if (string.IsNullOrEmpty(Codec) && !IsExternal)
+ {
+ return false;
+ }
+
return IsTextFormat(Codec);
}
}
diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
index 783fb4120..ffd4995ad 100644
--- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
+++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
@@ -1,11 +1,9 @@
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.MediaInfo
{
public class PlaybackInfoRequest
{
public DeviceProfile DeviceProfile { get; set; }
- public MediaSourceInfo MediaSource { get; set; }
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 65d8e287f..99be102f8 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -96,7 +96,7 @@ namespace MediaBrowser.Providers.MediaInfo
var album = item.Parent as MusicAlbum;
var filename = item.Album ?? string.Empty;
- filename += item.Artists.FirstOrDefault() ?? string.Empty;
+ filename += string.Join(",", item.Artists.ToArray());
filename += album == null ? item.Id.ToString("N") + "_primary" + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks + "_primary";
filename = filename.GetMD5() + ".jpg";
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();
}
}
}
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index 9a7f03341..039c5edf3 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
@@ -472,7 +472,7 @@ namespace MediaBrowser.Server.Startup.Common
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient);
RegisterSingleInstance(ChannelManager);
- MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, ChannelManager, LogManager.GetLogger("MediaSourceManager"));
+ MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"));
RegisterSingleInstance(MediaSourceManager);
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), UserRepository, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec
index 31441ff79..e1659bfb2 100644
--- a/Nuget/MediaBrowser.Common.Internal.nuspec
+++ b/Nuget/MediaBrowser.Common.Internal.nuspec
@@ -9,8 +9,8 @@
<projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description>
- <copyright>Copyright © Media Browser 2013</copyright>
+ <description>Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption.</description>
+ <copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.603" />
<dependency id="NLog" version="3.2.0.0" />
diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec
index 568a47dfe..294bc519e 100644
--- a/Nuget/MediaBrowser.Common.nuspec
+++ b/Nuget/MediaBrowser.Common.nuspec
@@ -4,13 +4,13 @@
<id>MediaBrowser.Common</id>
<version>3.0.603</version>
<title>MediaBrowser.Common</title>
- <authors>Media Browser Team</authors>
+ <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
<projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Contains common model objects and interfaces used by all Media Browser solutions.</description>
- <copyright>Copyright © Media Browser 2013</copyright>
+ <description>Contains common model objects and interfaces used by all Emby solutions.</description>
+ <copyright>Copyright © Emby 2013</copyright>
</metadata>
<files>
<file src="dlls\net35\MediaBrowser.Model.dll" target="lib\net35\MediaBrowser.Model.dll" />
diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec
index fb00fd840..bcbd1d5be 100644
--- a/Nuget/MediaBrowser.Model.Signed.nuspec
+++ b/Nuget/MediaBrowser.Model.Signed.nuspec
@@ -4,13 +4,13 @@
<id>MediaBrowser.Model.Signed</id>
<version>3.0.603</version>
<title>MediaBrowser.Model - Signed Edition</title>
- <authors>Media Browser Team</authors>
+ <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
<projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Contains common model objects and interfaces used by all Media Browser solutions.</description>
- <copyright>Copyright © Media Browser 2013</copyright>
+ <description>Contains common model objects and interfaces used by all Emby solutions.</description>
+ <copyright>Copyright © Emby 2013</copyright>
<dependencies>
</dependencies>
</metadata>
diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec
index c36fb6d6c..ee3925db5 100644
--- a/Nuget/MediaBrowser.Server.Core.nuspec
+++ b/Nuget/MediaBrowser.Server.Core.nuspec
@@ -4,13 +4,13 @@
<id>MediaBrowser.Server.Core</id>
<version>3.0.603</version>
<title>Media Browser.Server.Core</title>
- <authors>Media Browser Team</authors>
+ <authors>Emby Team</authors>
<owners>ebr,Luke,scottisafool</owners>
<projectUrl>https://github.com/MediaBrowser/MediaBrowser</projectUrl>
<iconUrl>http://www.mb3admin.com/images/mb3icons1-1.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
- <description>Contains core components required to build plugins for Media Browser Server.</description>
- <copyright>Copyright © Media Browser 2013</copyright>
+ <description>Contains core components required to build plugins for Emby Server.</description>
+ <copyright>Copyright © Emby 2013</copyright>
<dependencies>
<dependency id="MediaBrowser.Common" version="3.0.603" />
</dependencies>