From 348b8c44142ce14a8395552f8d429fb9d0b24a36 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 26 Mar 2015 12:58:02 -0400 Subject: use server to build initial stream url's --- MediaBrowser.Controller/Channels/ChannelMediaInfo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Controller/Channels') diff --git a/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs b/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs index 0c2e30923c..94fa1ac02f 100644 --- a/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs @@ -62,7 +62,8 @@ namespace MediaBrowser.Controller.Channels RunTimeTicks = RunTimeTicks, Name = id, Id = id, - ReadAtNativeFramerate = ReadAtNativeFramerate + ReadAtNativeFramerate = ReadAtNativeFramerate, + SupportsDirectStream = Protocol == MediaProtocol.File || Protocol == MediaProtocol.Http }; var bitrate = (AudioBitrate ?? 0) + (VideoBitrate ?? 0); -- cgit v1.2.3 From d8cbd649176566dbdcc49e72d0fa2ddd4f25d536 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 27 Mar 2015 16:55:31 -0400 Subject: fix mp4 sync encoding --- .../Channels/ChannelMediaInfo.cs | 5 ++- MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs | 9 +++-- MediaBrowser.Model/ApiClient/ServerCredentials.cs | 21 +++++++--- MediaBrowser.Model/ApiClient/ServerInfo.cs | 8 +++- MediaBrowser.Model/Dlna/StreamInfoSorter.cs | 2 +- .../LiveTv/LiveTvManager.cs | 46 +++++++++++++++------- .../Sync/MediaSync.cs | 15 ++++--- MediaBrowser.Server.Mono/Native/BaseMonoApp.cs | 1 - Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 2 +- Nuget/MediaBrowser.Model.Signed.nuspec | 2 +- Nuget/MediaBrowser.Server.Core.nuspec | 4 +- SharedVersion.cs | 4 +- 13 files changed, 82 insertions(+), 41 deletions(-) (limited to 'MediaBrowser.Controller/Channels') diff --git a/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs b/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs index 94fa1ac02f..1672b75fac 100644 --- a/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelMediaInfo.cs @@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Channels public string Id { get; set; } public bool ReadAtNativeFramerate { get; set; } + public bool SupportsDirectPlay { get; set; } public ChannelMediaInfo() { @@ -45,6 +46,7 @@ namespace MediaBrowser.Controller.Channels // This is most common Protocol = MediaProtocol.Http; + SupportsDirectPlay = true; } public MediaSourceInfo ToMediaSource() @@ -63,7 +65,8 @@ namespace MediaBrowser.Controller.Channels Name = id, Id = id, ReadAtNativeFramerate = ReadAtNativeFramerate, - SupportsDirectStream = Protocol == MediaProtocol.File || Protocol == MediaProtocol.Http + SupportsDirectStream = Protocol == MediaProtocol.File || Protocol == MediaProtocol.Http, + SupportsDirectPlay = SupportsDirectPlay }; var bitrate = (AudioBitrate ?? 0) + (VideoBitrate ?? 0); diff --git a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs index a714b160ec..b8ed97b1fc 100644 --- a/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs @@ -73,10 +73,13 @@ namespace MediaBrowser.MediaEncoding.Encoder args; } - var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", - 5.ToString(UsCulture)); + if (state.Options.Context == EncodingContext.Streaming) + { + var keyFrameArg = string.Format(" -force_key_frames expr:gte(t,n_forced*{0})", + 5.ToString(UsCulture)); - args += keyFrameArg; + args += keyFrameArg; + } var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream; diff --git a/MediaBrowser.Model/ApiClient/ServerCredentials.cs b/MediaBrowser.Model/ApiClient/ServerCredentials.cs index d911f81211..6ba2a80c87 100644 --- a/MediaBrowser.Model/ApiClient/ServerCredentials.cs +++ b/MediaBrowser.Model/ApiClient/ServerCredentials.cs @@ -1,7 +1,6 @@ using MediaBrowser.Model.Extensions; using System; using System.Collections.Generic; -using System.Linq; namespace MediaBrowser.Model.ApiClient { @@ -24,7 +23,12 @@ namespace MediaBrowser.Model.ApiClient throw new ArgumentNullException("server"); } - var list = Servers.ToList(); + // Clone the existing list of servers + var list = new List(); + foreach (ServerInfo serverInfo in Servers) + { + list.Add(serverInfo); + } var index = FindIndex(list, server.Id); @@ -32,8 +36,11 @@ namespace MediaBrowser.Model.ApiClient { var existing = list[index]; - // Merge the data - existing.DateLastAccessed = new[] { existing.DateLastAccessed, server.DateLastAccessed }.Max(); + // Take the most recent DateLastAccessed + if (server.DateLastAccessed > existing.DateLastAccessed) + { + existing.DateLastAccessed = server.DateLastAccessed; + } existing.UserLinkType = server.UserLinkType; @@ -64,7 +71,11 @@ namespace MediaBrowser.Model.ApiClient } if (server.WakeOnLanInfos != null && server.WakeOnLanInfos.Count > 0) { - existing.WakeOnLanInfos = server.WakeOnLanInfos.ToList(); + existing.WakeOnLanInfos = new List(); + foreach (WakeOnLanInfo info in server.WakeOnLanInfos) + { + existing.WakeOnLanInfos.Add(info); + } } if (server.LastConnectionMode.HasValue) { diff --git a/MediaBrowser.Model/ApiClient/ServerInfo.cs b/MediaBrowser.Model/ApiClient/ServerInfo.cs index cc062f2f60..e1fa581d7b 100644 --- a/MediaBrowser.Model/ApiClient/ServerInfo.cs +++ b/MediaBrowser.Model/ApiClient/ServerInfo.cs @@ -3,7 +3,6 @@ using MediaBrowser.Model.Extensions; using MediaBrowser.Model.System; using System; using System.Collections.Generic; -using System.Linq; namespace MediaBrowser.Model.ApiClient { @@ -83,7 +82,12 @@ namespace MediaBrowser.Model.ApiClient throw new ArgumentNullException("user"); } - var list = Users.ToList(); + // Clone the existing list of users + var list = new List(); + foreach (ServerUserInfo serverUserInfo in Users) + { + list.Add(serverUserInfo); + } var index = FindIndex(list, user.Id); diff --git a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs index 87c6615480..0cccd80804 100644 --- a/MediaBrowser.Model/Dlna/StreamInfoSorter.cs +++ b/MediaBrowser.Model/Dlna/StreamInfoSorter.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Model.Dlna case PlayMethod.DirectPlay: return 0; default: - return 2; + return 1; } }).ThenBy(i => diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 2bc6cbadfe..59daa4921a 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -333,10 +333,12 @@ namespace MediaBrowser.Server.Implementations.LiveTv try { MediaSourceInfo info; + var isVideo = true; if (isChannel) { var channel = GetInternalChannel(id); + isVideo = channel.ChannelType == ChannelType.TV; 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); @@ -344,6 +346,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv else { var recording = await GetInternalRecording(id, cancellationToken).ConfigureAwait(false); + isVideo = !string.Equals(recording.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase); var service = GetService(recording); _logger.Info("Opening recording stream from {0}, external recording Id: {1}", service.Name, recording.RecordingInfo.Id); @@ -351,7 +354,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv } _logger.Info("Live stream info: {0}", _jsonSerializer.SerializeToString(info)); - Sanitize(info); + Normalize(info, isVideo); var data = new LiveStreamData { @@ -377,25 +380,40 @@ namespace MediaBrowser.Server.Implementations.LiveTv } } - private void Sanitize(MediaSourceInfo mediaSource) + private void Normalize(MediaSourceInfo mediaSource, bool isVideo) { if (mediaSource.MediaStreams.Count == 0) { - mediaSource.MediaStreams.AddRange(new List + if (isVideo) { - new MediaStream + mediaSource.MediaStreams.AddRange(new List { - Type = MediaStreamType.Video, - // Set the index to -1 because we don't know the exact index of the video stream within the container - Index = -1 - }, - new MediaStream + new MediaStream + { + Type = MediaStreamType.Video, + // Set the index to -1 because we don't know the exact index of the video stream within the container + Index = -1 + }, + new MediaStream + { + Type = MediaStreamType.Audio, + // Set the index to -1 because we don't know the exact index of the audio stream within the container + Index = -1 + } + }); + } + else + { + mediaSource.MediaStreams.AddRange(new List { - Type = MediaStreamType.Audio, - // Set the index to -1 because we don't know the exact index of the audio stream within the container - Index = -1 - } - }); + new MediaStream + { + Type = MediaStreamType.Audio, + // Set the index to -1 because we don't know the exact index of the audio stream within the container + Index = -1 + } + }); + } } // Clean some bad data coming from providers diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index 936f1b1fe8..cac0e15546 100644 --- a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs +++ b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs @@ -1,5 +1,4 @@ -using System.IO; -using MediaBrowser.Common.IO; +using MediaBrowser.Common.IO; using MediaBrowser.Common.Progress; using MediaBrowser.Controller; using MediaBrowser.Controller.Sync; @@ -10,6 +9,7 @@ using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Sync; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; @@ -140,9 +140,6 @@ namespace MediaBrowser.Server.Implementations.Sync var libraryItem = jobItem.Item; var internalSyncJobItem = _syncManager.GetJobItem(jobItem.SyncJobItemId); - var fileTransferProgress = new ActionableProgress(); - fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92)); - var localItem = CreateLocalItem(provider, jobItem, target, libraryItem, serverId, jobItem.OriginalFileName); await _syncManager.ReportSyncJobItemTransferBeginning(internalSyncJobItem.Id); @@ -152,6 +149,9 @@ namespace MediaBrowser.Server.Implementations.Sync try { + var fileTransferProgress = new ActionableProgress(); + fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92)); + var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath, target, fileTransferProgress, cancellationToken).ConfigureAwait(false); if (localItem.Item.MediaSources != null) @@ -342,7 +342,10 @@ namespace MediaBrowser.Server.Implementations.Sync private string GetSyncJobFolderName(SyncedItem syncedItem, IServerSyncProvider provider) { - var name = syncedItem.SyncJobName + syncedItem.SyncJobDateCreated.ToLocalTime().ToString("g"); + var name = syncedItem.SyncJobName + "-" + syncedItem.SyncJobDateCreated + .ToLocalTime() + .ToString("g") + .Replace(" ", "-"); name = GetValidFilename(provider, name); diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs index 1ec0109ad8..aea6d73679 100644 --- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs +++ b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs @@ -139,7 +139,6 @@ namespace MediaBrowser.Server.Mono.Native } else if (string.Equals(sysName, "BSD", StringComparison.OrdinalIgnoreCase)) { - // TODO: How to detect BSD? info.OperatingSystem = Startup.Common.OperatingSystem.Bsd; } diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index d229302bde..dccef68ed4 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common.Internal - 3.0.599 + 3.0.600 MediaBrowser.Common.Internal Luke ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. Copyright © Media Browser 2013 - + diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 65205fa250..b35ce68d6d 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Common - 3.0.599 + 3.0.600 MediaBrowser.Common Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index 2e829b436a..ea45fdfe19 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Model.Signed - 3.0.599 + 3.0.600 MediaBrowser.Model - Signed Edition Media Browser Team ebr,Luke,scottisafool diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index f5d5b788bb..6fc7e46393 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ MediaBrowser.Server.Core - 3.0.599 + 3.0.600 Media Browser.Server.Core Media Browser Team ebr,Luke,scottisafool @@ -12,7 +12,7 @@ Contains core components required to build plugins for Media Browser Server. Copyright © Media Browser 2013 - + diff --git a/SharedVersion.cs b/SharedVersion.cs index fa4ca1ac7e..621b97a63d 100644 --- a/SharedVersion.cs +++ b/SharedVersion.cs @@ -1,4 +1,4 @@ using System.Reflection; -[assembly: AssemblyVersion("3.0.*")] -//[assembly: AssemblyVersion("3.0.5557.20000")] +//[assembly: AssemblyVersion("3.0.*")] +[assembly: AssemblyVersion("3.0.5557.30000")] -- cgit v1.2.3 From bd2ea703e31522d505407a33089b95f997f6b062 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 28 Mar 2015 16:22:27 -0400 Subject: implement modular media sources --- MediaBrowser.Api/Playback/BaseStreamingService.cs | 255 ++++++--------------- MediaBrowser.Api/Playback/Dash/MpegDashService.cs | 6 +- MediaBrowser.Api/Playback/Hls/BaseHlsService.cs | 6 +- MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs | 11 +- MediaBrowser.Api/Playback/Hls/VideoHlsService.cs | 2 +- MediaBrowser.Api/Playback/MediaInfoService.cs | 108 ++++++--- .../Playback/Progressive/AudioService.cs | 6 +- .../Progressive/BaseProgressiveStreamingService.cs | 2 +- .../Playback/Progressive/VideoService.cs | 6 +- MediaBrowser.Api/Playback/StreamState.cs | 23 +- MediaBrowser.Api/Subtitles/SubtitleService.cs | 2 +- .../Channels/ChannelAudioItem.cs | 16 +- .../Channels/ChannelVideoItem.cs | 16 +- .../Channels/IChannelManager.cs | 6 +- .../Library/IMediaSourceManager.cs | 24 ++ .../Library/IMediaSourceProvider.cs | 16 ++ MediaBrowser.Controller/LiveTv/ILiveTvItem.cs | 4 +- .../LiveTv/LiveTvAudioRecording.cs | 21 +- MediaBrowser.Controller/LiveTv/LiveTvChannel.cs | 2 +- .../LiveTv/LiveTvVideoRecording.cs | 23 +- MediaBrowser.Dlna/PlayTo/PlayToController.cs | 2 +- MediaBrowser.Model/Dlna/StreamBuilder.cs | 24 +- MediaBrowser.Model/Dlna/SubtitleProfile.cs | 27 ++- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 5 + MediaBrowser.Model/Dto/MediaSourceType.cs | 2 +- MediaBrowser.Model/Entities/MediaStream.cs | 5 + .../MediaInfo/PlaybackInfoRequest.cs | 2 - .../MediaInfo/AudioImageProvider.cs | 2 +- .../Channels/ChannelDownloadScheduledTask.cs | 14 +- .../Channels/ChannelDynamicMediaSourceProvider.cs | 43 ++++ .../Channels/ChannelManager.cs | 47 ++-- .../Library/MediaSourceManager.cs | 148 ++++++++++-- .../LiveTv/LiveTvManager.cs | 9 +- .../LiveTv/LiveTvMediaSourceProvider.cs | 77 +++++++ .../MediaBrowser.Server.Implementations.csproj | 2 + .../Sync/MediaSync.cs | 1 + .../Sync/SyncedMediaSourceProvider.cs | 74 ++++-- .../ApplicationHost.cs | 2 +- Nuget/MediaBrowser.Common.Internal.nuspec | 4 +- Nuget/MediaBrowser.Common.nuspec | 6 +- Nuget/MediaBrowser.Model.Signed.nuspec | 6 +- Nuget/MediaBrowser.Server.Core.nuspec | 6 +- 42 files changed, 697 insertions(+), 366 deletions(-) create mode 100644 MediaBrowser.Server.Implementations/Channels/ChannelDynamicMediaSourceProvider.cs create mode 100644 MediaBrowser.Server.Implementations/LiveTv/LiveTvMediaSourceProvider.cs (limited to 'MediaBrowser.Controller/Channels') diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bc194b45b0..435bda2c44 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 /// /// Initializes a new instance of the class. /// - 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. /// /// The output path. - /// The transcoding job identifier. /// The state. /// if set to true [is encoding]. /// System.String. - protected abstract string GetCommandLineArguments(string outputPath, string transcodingJobId, StreamState state, bool isEncoding); + protected abstract string GetCommandLineArguments(string outputPath, StreamState state, bool isEncoding); /// /// 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 /// /// Gets the input argument. /// - /// The transcoding job identifier. /// The state. /// System.String. - 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 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(); - - 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 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 3c3f4c0397..692e8d4e74 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 09574e772c..207bc2f679 100644 --- a/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/BaseHlsService.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls /// 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 48523e2556..b166bc319f 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 e1baf8c121..b1964f4aef 100644 --- a/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs +++ b/MediaBrowser.Api/Playback/Hls/VideoHlsService.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback.Hls /// 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 e219f41869..cef8a34e57 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 { - [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 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 GetPlaybackInfo(string id, string userId, MediaSourceInfo mediaSource = null) + private async Task GetPlaybackInfo(string id, string userId, string mediaSourceId = null) { var result = new PlaybackInfoResponse(); - if (mediaSource == null) + IEnumerable mediaSources; + + try { - IEnumerable mediaSources; + mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false); + } + catch (PlaybackException ex) + { + mediaSources = new List(); + result.ErrorCode = ex.ErrorCode; + } - try - { - mediaSources = await _mediaSourceManager.GetPlayackMediaSources(id, userId, true, CancellationToken.None).ConfigureAwait(false); - } - catch (PlaybackException ex) - { - mediaSources = new List(); - result.ErrorCode = ex.ErrorCode; - } + result.MediaSources = mediaSources.ToList(); - result.MediaSources = mediaSources.ToList(); - } - else + if (!string.IsNullOrWhiteSpace(mediaSourceId)) { - result.MediaSources = new List { 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 af2cf6b038..fee5011596 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// 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(); @@ -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 7a2990e2af..8ed17ca17e 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 eb18288e98..540c39a0c7 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -62,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive /// 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 1d4dd1aafb..37f2c7702c 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 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 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 SupportedAudioCodecs { get; set; } - public StreamState(ILiveTvManager liveTvManager, ILogger logger) + public StreamState(IMediaSourceManager mediaSourceManager, ILogger logger) { - _liveTvManager = liveTvManager; + _mediaSourceManager = mediaSourceManager; _logger = logger; SupportedAudioCodecs = new List(); PlayableStreamFileNames = new List(); RemoteHttpHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - AllMediaStreams = new List(); } 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 07eb74e81b..73589d6777 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 91b2407bee..8d90246765 100644 --- a/MediaBrowser.Controller/Channels/ChannelAudioItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelAudioItem.cs @@ -75,17 +75,23 @@ namespace MediaBrowser.Controller.Channels public override IEnumerable 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 d7d4483cd1..8eec2021b5 100644 --- a/MediaBrowser.Controller/Channels/ChannelVideoItem.cs +++ b/MediaBrowser.Controller/Channels/ChannelVideoItem.cs @@ -90,17 +90,23 @@ namespace MediaBrowser.Controller.Channels public override IEnumerable 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 05015da37d..f5c4ab3733 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -112,11 +112,11 @@ namespace MediaBrowser.Controller.Channels /// /// Gets the channel item media sources. /// - /// The identifier. - /// if set to true [include dynamic sources]. + /// The item. + /// if set to true [include cached versions]. /// The cancellation token. /// Task{IEnumerable{MediaSourceInfo}}. - Task> GetChannelItemMediaSources(string id, bool includeDynamicSources, CancellationToken cancellationToken); + Task> GetStaticMediaSources(IChannelMediaItem item, bool includeCachedVersions, CancellationToken cancellationToken); /// /// Gets the channel folder. diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index c21fed6fc5..fda17aa279 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -64,6 +64,14 @@ namespace MediaBrowser.Controller.Library /// IEnumerable<MediaSourceInfo>. IEnumerable GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution, User user); + /// + /// Gets the static media sources. + /// + /// The item. + /// if set to true [enable path substitution]. + /// IEnumerable<MediaSourceInfo>. + IEnumerable GetStaticMediaSources(IHasMediaSources item, bool enablePathSubstitution); + /// /// Gets the static media source. /// @@ -72,5 +80,21 @@ namespace MediaBrowser.Controller.Library /// if set to true [enable path substitution]. /// MediaSourceInfo. MediaSourceInfo GetStaticMediaSource(IHasMediaSources item, string mediaSourceId, bool enablePathSubstitution); + + /// + /// Opens the media source. + /// + /// The open key. + /// The cancellation token. + /// Task<MediaSourceInfo>. + Task OpenMediaSource(string openKey, CancellationToken cancellationToken); + + /// + /// Closes the media source. + /// + /// The close key. + /// The cancellation token. + /// Task. + Task CloseMediaSource(string closeKey, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 461285d6cc..c5f5b54010 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -15,5 +15,21 @@ namespace MediaBrowser.Controller.Library /// The cancellation token. /// Task<IEnumerable<MediaSourceInfo>>. Task> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken); + + /// + /// Opens the media source. + /// + /// The open key. + /// The cancellation token. + /// Task<MediaSourceInfo>. + Task OpenMediaSource(string openKey, CancellationToken cancellationToken); + + /// + /// Closes the media source. + /// + /// The close key. + /// The cancellation token. + /// Task. + Task CloseMediaSource(string closeKey, CancellationToken cancellationToken); } } diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs b/MediaBrowser.Controller/LiveTv/ILiveTvItem.cs index d3334e8ea0..6c277a2e19 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 9815066efc..0dc296d5a5 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 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 75e418bcc9..1e13d8f3f4 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 207684d55d..3669f94403 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 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 f8f939f479..17385bda62 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 62ac321fe3..6534eda10c 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 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 d3989829ca..1795c374a4 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 GetLanguages() + { + List list = new List(); + 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 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 31d310acda..92af8d671c 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 a9cd71df56..e049785025 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 66fb486284..fa075490a5 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 783fb41203..ffd4995ad9 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 65d8e287f9..99be102f85 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 e0b616605d..980c3f31b7 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(), cancellationToken) + await _manager.DownloadChannelItem(item, destination, new Progress(), 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 0000000000..6a7163bb3b --- /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> GetMediaSources(IHasMediaSources item, CancellationToken cancellationToken) + { + var channelItem = item as IChannelMediaItem; + + if (channelItem != null) + { + return _channelManager.GetDynamicMediaSources(channelItem, cancellationToken); + } + + return Task.FromResult>(new List()); + } + + public Task 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 f0f30229ec..e22bf2e7f7 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> GetChannelItemMediaSources(string id, bool includeDynamicSources, CancellationToken cancellationToken) + public async Task> GetStaticMediaSources(IChannelMediaItem item, bool includeCachedVersions, CancellationToken cancellationToken) { - var item = (IChannelMediaItem)_libraryManager.GetItemById(id); + IEnumerable 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> GetDynamicMediaSources(IChannelMediaItem item, CancellationToken cancellationToken) + { var channel = GetChannel(item.ChannelId); var channelPlugin = GetChannelProvider(channel); @@ -252,24 +267,25 @@ namespace MediaBrowser.Server.Implementations.Channels IEnumerable 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(); } - 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>> _channelItemMediaInfo = @@ -297,14 +313,7 @@ namespace MediaBrowser.Server.Implementations.Channels return list; } - public IEnumerable GetCachedChannelItemMediaSources(string id) - { - var item = (IChannelMediaItem)_libraryManager.GetItemById(id); - - return GetCachedChannelItemMediaSources(item); - } - - public IEnumerable GetCachedChannelItemMediaSources(IChannelMediaItem item) + private IEnumerable 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 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 39219b5415..40cf240d7e 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 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> 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> 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 _openStreams = + new ConcurrentDictionary(); + private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1); + public async Task 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 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(provider, keys[1]); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + public void Dispose() + { + Dispose(true); + } + + private readonly object _disposeLock = new object(); + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + 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 59daa4921a..202a051e3b 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 0000000000..186bc499db --- /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> 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>(new List()); + } + + private async Task> 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(); + openKeys.Add(item.GetType().Name); + openKeys.Add(item.Id.ToString("N")); + source.OpenKey = string.Join("|", openKeys.ToArray()); + } + + return sources; + } + + public async Task 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 3eb414068f..db2397d2f7 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -111,6 +111,7 @@ + @@ -225,6 +226,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Sync/MediaSync.cs b/MediaBrowser.Server.Implementations/Sync/MediaSync.cs index 03a7e92a45..dd8ce82ef1 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 4172cfc2da..25a52fb950 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 list, + private void AddMediaSource(List 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(); + 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 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 9a7f03341c..039c5edf38 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 31441ff791..e1659bfb28 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -9,8 +9,8 @@ https://github.com/MediaBrowser/MediaBrowser http://www.mb3admin.com/images/mb3icons1-1.png false - Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption. - Copyright © Media Browser 2013 + Contains common components shared by Emby Theater and Emby Server. Not intended for plugin developer consumption. + Copyright © Emby 2013 diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 568a47dfe0..294bc519eb 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -4,13 +4,13 @@ MediaBrowser.Common 3.0.603 MediaBrowser.Common - Media Browser Team + Emby Team ebr,Luke,scottisafool https://github.com/MediaBrowser/MediaBrowser http://www.mb3admin.com/images/mb3icons1-1.png false - Contains common model objects and interfaces used by all Media Browser solutions. - Copyright © Media Browser 2013 + Contains common model objects and interfaces used by all Emby solutions. + Copyright © Emby 2013 diff --git a/Nuget/MediaBrowser.Model.Signed.nuspec b/Nuget/MediaBrowser.Model.Signed.nuspec index fb00fd8407..bcbd1d5bea 100644 --- a/Nuget/MediaBrowser.Model.Signed.nuspec +++ b/Nuget/MediaBrowser.Model.Signed.nuspec @@ -4,13 +4,13 @@ MediaBrowser.Model.Signed 3.0.603 MediaBrowser.Model - Signed Edition - Media Browser Team + Emby Team ebr,Luke,scottisafool https://github.com/MediaBrowser/MediaBrowser http://www.mb3admin.com/images/mb3icons1-1.png false - Contains common model objects and interfaces used by all Media Browser solutions. - Copyright © Media Browser 2013 + Contains common model objects and interfaces used by all Emby solutions. + Copyright © Emby 2013 diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index c36fb6d6cd..ee3925db5b 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -4,13 +4,13 @@ MediaBrowser.Server.Core 3.0.603 Media Browser.Server.Core - Media Browser Team + Emby Team ebr,Luke,scottisafool https://github.com/MediaBrowser/MediaBrowser http://www.mb3admin.com/images/mb3icons1-1.png false - Contains core components required to build plugins for Media Browser Server. - Copyright © Media Browser 2013 + Contains core components required to build plugins for Emby Server. + Copyright © Emby 2013 -- cgit v1.2.3 From ddbbe9ce4e054565272a69e1ea709f8df4d96479 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 1 Apr 2015 00:23:34 -0400 Subject: post release housecleaning --- MediaBrowser.Api/ApiEntryPoint.cs | 2 +- MediaBrowser.Api/ConfigurationService.cs | 2 +- MediaBrowser.Api/Playback/TranscodingThrottler.cs | 2 +- MediaBrowser.Controller/Channels/Channel.cs | 15 ++--------- MediaBrowser.Controller/Entities/BaseItem.cs | 29 ---------------------- MediaBrowser.Controller/Entities/Folder.cs | 17 ++----------- MediaBrowser.Controller/Entities/LinkedChild.cs | 3 --- .../Providers/BaseItemXmlParser.cs | 14 +---------- MediaBrowser.LocalMetadata/BaseXmlProvider.cs | 2 +- .../Savers/XmlSaverHelpers.cs | 5 ---- .../Configuration/ServerConfiguration.cs | 5 ++-- .../Configuration/UserConfiguration.cs | 7 ------ MediaBrowser.Model/Dlna/StreamInfo.cs | 5 ++++ .../Notifications/NotificationOptions.cs | 5 ++-- MediaBrowser.Model/Users/UserPolicy.cs | 2 -- .../HttpServer/Security/AuthService.cs | 2 +- .../Library/UserManager.cs | 26 +++---------------- .../Notifications/NotificationManager.cs | 2 +- .../FFMpeg/FFMpegDownloadInfo.cs | 18 +++++++------- .../Migrations/RenameXmlOptions.cs | 7 +++++- MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs | 10 -------- 21 files changed, 39 insertions(+), 141 deletions(-) (limited to 'MediaBrowser.Controller/Channels') diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 08ac5671d5..0db56e299f 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -296,7 +296,7 @@ namespace MediaBrowser.Api // TODO: Lower this hls timeout var timerDuration = job.Type == TranscodingJobType.Progressive ? 1000 : - 7200000; + 1800000; if (job.KillTimer == null) { diff --git a/MediaBrowser.Api/ConfigurationService.cs b/MediaBrowser.Api/ConfigurationService.cs index d0abd18c28..9f6c07dd21 100644 --- a/MediaBrowser.Api/ConfigurationService.cs +++ b/MediaBrowser.Api/ConfigurationService.cs @@ -123,7 +123,7 @@ namespace MediaBrowser.Api public void Post(AutoSetMetadataOptions request) { - _configurationManager.DisableMetadataService("Media Browser Xml"); + _configurationManager.DisableMetadataService("Emby Xml"); _configurationManager.SaveConfiguration(); } diff --git a/MediaBrowser.Api/Playback/TranscodingThrottler.cs b/MediaBrowser.Api/Playback/TranscodingThrottler.cs index 58cfa086e3..ff79bb48f4 100644 --- a/MediaBrowser.Api/Playback/TranscodingThrottler.cs +++ b/MediaBrowser.Api/Playback/TranscodingThrottler.cs @@ -42,7 +42,7 @@ namespace MediaBrowser.Api.Playback var options = GetOptions(); - if (options.EnableThrottling && IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) + if (/*options.EnableThrottling &&*/ IsThrottleAllowed(_job, options.ThrottleThresholdSeconds)) { PauseTranscoding(); } diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs index b6514ca0a6..f746d87fff 100644 --- a/MediaBrowser.Controller/Channels/Channel.cs +++ b/MediaBrowser.Controller/Channels/Channel.cs @@ -5,7 +5,6 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Users; namespace MediaBrowser.Controller.Channels { @@ -15,19 +14,9 @@ namespace MediaBrowser.Controller.Channels public override bool IsVisible(User user) { - if (user.Policy.BlockedChannels != null) + if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { - if (user.Policy.BlockedChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } - } - else - { - if (!user.Policy.EnableAllChannels && !user.Policy.EnabledChannels.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } + return false; } return base.IsVisible(user); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cdb52ec668..94fc761253 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1219,18 +1219,6 @@ namespace MediaBrowser.Controller.Entities private BaseItem FindLinkedChild(LinkedChild info) { - if (!string.IsNullOrWhiteSpace(info.ItemName)) - { - if (string.Equals(info.ItemType, "musicgenre", StringComparison.OrdinalIgnoreCase)) - { - return LibraryManager.GetMusicGenre(info.ItemName); - } - if (string.Equals(info.ItemType, "musicartist", StringComparison.OrdinalIgnoreCase)) - { - return LibraryManager.GetArtist(info.ItemName); - } - } - if (!string.IsNullOrEmpty(info.Path)) { var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); @@ -1243,23 +1231,6 @@ namespace MediaBrowser.Controller.Entities return itemByPath; } - if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) - { - return LibraryManager.RootFolder.GetRecursiveChildren(i => - { - if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; - - }).FirstOrDefault(); - } - return null; } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index cffc0989a5..14095f7ffc 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -334,22 +334,9 @@ namespace MediaBrowser.Controller.Entities { if (this is ICollectionFolder && !(this is BasePluginFolder)) { - if (user.Policy.BlockedMediaFolders != null) + if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) { - if (user.Policy.BlockedMediaFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase) || - - // Backwards compatibility - user.Policy.BlockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase)) - { - return false; - } - } - else - { - if (!user.Policy.EnableAllFolders && !user.Policy.EnabledFolders.Contains(Id.ToString("N"), StringComparer.OrdinalIgnoreCase)) - { - return false; - } + return false; } } diff --git a/MediaBrowser.Controller/Entities/LinkedChild.cs b/MediaBrowser.Controller/Entities/LinkedChild.cs index 949c9741b1..ac13657b94 100644 --- a/MediaBrowser.Controller/Entities/LinkedChild.cs +++ b/MediaBrowser.Controller/Entities/LinkedChild.cs @@ -9,9 +9,6 @@ namespace MediaBrowser.Controller.Entities public string Path { get; set; } public LinkedChildType Type { get; set; } - public string ItemName { get; set; } - public string ItemType { get; set; } - [IgnoreDataMember] public string Id { get; set; } diff --git a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs index 6facc1074a..13f83c0fc9 100644 --- a/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Providers/BaseItemXmlParser.cs @@ -1404,24 +1404,12 @@ namespace MediaBrowser.Controller.Providers { switch (reader.Name) { - case "Name": - { - linkedItem.ItemName = reader.ReadElementContentAsString(); - break; - } - case "Path": { linkedItem.Path = reader.ReadElementContentAsString(); break; } - case "Type": - { - linkedItem.ItemType = reader.ReadElementContentAsString(); - break; - } - default: reader.Skip(); break; @@ -1435,7 +1423,7 @@ namespace MediaBrowser.Controller.Providers return linkedItem; } - return string.IsNullOrWhiteSpace(linkedItem.ItemName) || string.IsNullOrWhiteSpace(linkedItem.ItemType) ? null : linkedItem; + return null; } diff --git a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs index afe4b5799b..154d026008 100644 --- a/MediaBrowser.LocalMetadata/BaseXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/BaseXmlProvider.cs @@ -92,7 +92,7 @@ namespace MediaBrowser.LocalMetadata { get { - return "Media Browser Xml"; + return "Emby Xml"; } } diff --git a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs index c59d574bf4..1b98e75bef 100644 --- a/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs +++ b/MediaBrowser.LocalMetadata/Savers/XmlSaverHelpers.cs @@ -756,11 +756,6 @@ namespace MediaBrowser.LocalMetadata.Savers { builder.Append("<" + singularNodeName + ">"); - if (!string.IsNullOrWhiteSpace(link.ItemType)) - { - builder.Append("" + SecurityElement.Escape(link.ItemType) + ""); - } - if (!string.IsNullOrWhiteSpace(link.Path)) { builder.Append("" + SecurityElement.Escape((link.Path)) + ""); diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index c06aedb500..bc167333ae 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -200,7 +200,7 @@ namespace MediaBrowser.Model.Configuration public PeopleMetadataOptions PeopleMetadataOptions { get; set; } public bool FindInternetTrailers { get; set; } - public string[] InsecureApps8 { get; set; } + public string[] InsecureApps9 { get; set; } public bool SaveMetadataHidden { get; set; } @@ -257,7 +257,7 @@ namespace MediaBrowser.Model.Configuration PeopleMetadataOptions = new PeopleMetadataOptions(); - InsecureApps8 = new[] + InsecureApps9 = new[] { "Chromecast", "iOS", @@ -266,7 +266,6 @@ namespace MediaBrowser.Model.Configuration "Media Portal", "iPad", "iPhone", - "Roku", "Windows Phone" }; diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 98641636ae..a361da18b9 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -6,12 +6,6 @@ namespace MediaBrowser.Model.Configuration /// public class UserConfiguration { - /// - /// Gets or sets a value indicating whether this instance is administrator. - /// - /// true if this instance is administrator; otherwise, false. - public bool IsAdministrator { get; set; } - /// /// Gets or sets the audio language preference. /// @@ -53,7 +47,6 @@ namespace MediaBrowser.Model.Configuration public string[] LatestItemsExcludes { get; set; } - public bool HasMigratedToPolicy { get; set; } public bool HidePlayedInLatest { get; set; } /// diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs index 3977a9ab07..c3e868cd49 100644 --- a/MediaBrowser.Model/Dlna/StreamInfo.cs +++ b/MediaBrowser.Model/Dlna/StreamInfo.cs @@ -217,6 +217,11 @@ namespace MediaBrowser.Model.Dlna return list; } + public List GetExternalSubtitles(bool includeSelectedTrackOnly, string baseUrl, string accessToken) + { + return GetExternalSubtitles(includeSelectedTrackOnly, false, baseUrl, accessToken); + } + public List GetExternalSubtitles(bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken) { List list = GetSubtitleProfiles(includeSelectedTrackOnly, enableAllProfiles, baseUrl, accessToken); diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs index e57955c9e2..683f1a76c8 100644 --- a/MediaBrowser.Model/Notifications/NotificationOptions.cs +++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs @@ -1,5 +1,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Extensions; +using MediaBrowser.Model.Users; namespace MediaBrowser.Model.Notifications { @@ -106,7 +107,7 @@ namespace MediaBrowser.Model.Notifications !ListHelper.ContainsIgnoreCase(opt.DisabledMonitorUsers, userId); } - public bool IsEnabledToSendToUser(string type, string userId, UserConfiguration userConfig) + public bool IsEnabledToSendToUser(string type, string userId, UserPolicy userPolicy) { NotificationOption opt = GetOptions(type); @@ -117,7 +118,7 @@ namespace MediaBrowser.Model.Notifications return true; } - if (opt.SendToUserMode == SendToUserType.Admins && userConfig.IsAdministrator) + if (opt.SendToUserMode == SendToUserType.Admins && userPolicy.IsAdministrator) { return true; } diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs index 7efc2cf6f6..738f5bffa9 100644 --- a/MediaBrowser.Model/Users/UserPolicy.cs +++ b/MediaBrowser.Model/Users/UserPolicy.cs @@ -32,8 +32,6 @@ namespace MediaBrowser.Model.Users public bool EnableUserPreferenceAccess { get; set; } public AccessSchedule[] AccessSchedules { get; set; } public UnratedItem[] BlockUnratedItems { get; set; } - public string[] BlockedMediaFolders { get; set; } - public string[] BlockedChannels { get; set; } public bool EnableRemoteControlOfOtherUsers { get; set; } public bool EnableSharedDeviceControl { get; set; } diff --git a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs index 3903c62b1e..b4da407026 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/Security/AuthService.cs @@ -140,7 +140,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer.Security return true; } - return _config.Configuration.InsecureApps8.Contains(auth.Client ?? string.Empty, + return _config.Configuration.InsecureApps9.Contains(auth.Client ?? string.Empty, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.Server.Implementations/Library/UserManager.cs b/MediaBrowser.Server.Implementations/Library/UserManager.cs index b101f6ae1a..03471a8e9b 100644 --- a/MediaBrowser.Server.Implementations/Library/UserManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserManager.cs @@ -166,11 +166,6 @@ namespace MediaBrowser.Server.Implementations.Library var users = Users.ToList(); - foreach (var user in users) - { - await DoPolicyMigration(user).ConfigureAwait(false); - } - // If there are no local users with admin rights, make them all admins if (!users.Any(i => i.Policy.IsAdministrator)) { @@ -286,10 +281,10 @@ namespace MediaBrowser.Server.Implementations.Library if (newValue >= maxCount) { - //_logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); - //user.Policy.IsDisabled = true; + _logger.Debug("Disabling user {0} due to {1} unsuccessful login attempts.", user.Name, newValue.ToString(CultureInfo.InvariantCulture)); + user.Policy.IsDisabled = true; - //fireLockout = true; + fireLockout = true; } await UpdateUserPolicy(user, user.Policy, false).ConfigureAwait(false); @@ -366,19 +361,6 @@ namespace MediaBrowser.Server.Implementations.Library return users; } - private async Task DoPolicyMigration(User user) - { - if (!user.Configuration.HasMigratedToPolicy) - { - user.Policy.IsAdministrator = user.Configuration.IsAdministrator; - - await UpdateUserPolicy(user, user.Policy, false); - - user.Configuration.HasMigratedToPolicy = true; - await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); - } - } - public UserDto GetUserDto(User user, string remoteEndPoint = null) { if (user == null) @@ -953,8 +935,6 @@ namespace MediaBrowser.Server.Implementations.Library user.Policy = userPolicy; } - user.Configuration.IsAdministrator = user.Policy.IsAdministrator; - await UpdateConfiguration(user, user.Configuration, true).ConfigureAwait(false); } diff --git a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs index 5e02b2bacb..1ff928cd5b 100644 --- a/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs +++ b/MediaBrowser.Server.Implementations/Notifications/NotificationManager.cs @@ -95,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Notifications var config = GetConfiguration(); return _userManager.Users - .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Configuration)) + .Where(i => config.IsEnabledToSendToUser(request.NotificationType, i.Id.ToString("N"), i.Policy)) .Select(i => i.Id.ToString("N")); } diff --git a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs index cabb8dc839..4d2ed067be 100644 --- a/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs +++ b/MediaBrowser.Server.Startup.Common/FFMpeg/FFMpegDownloadInfo.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg var info = new FFMpegDownloadInfo(); // Windows builds: http://ffmpeg.zeranoe.com/builds/ - // Linux builds: http://ffmpeg.gusari.org/static/ + // Linux builds: http://johnvansickle.com/ffmpeg/ // OS X builds: http://ffmpegmac.net/ // OS X x64: http://www.evermeet.cx/ffmpeg/ @@ -33,7 +33,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case OperatingSystem.Linux: info.ArchiveType = "7z"; - info.Version = "20150124"; + info.Version = "20150331"; break; case OperatingSystem.Osx: @@ -54,7 +54,7 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg info.FFMpegFilename = "ffmpeg.exe"; info.FFProbeFilename = "ffprobe.exe"; - info.Version = "20150110"; + info.Version = "20150331"; info.ArchiveType = "7z"; switch (environment.SystemArchitecture) @@ -83,14 +83,14 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case Architecture.X86_X64: return new[] { - "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150110-git-4df01d5-win64-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150110-git-4df01d5-win64-static.7z" + "http://ffmpeg.zeranoe.com/builds/win64/static/ffmpeg-20150331-git-5cba529-win64-static.7z", + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150331-git-5cba529-win64-static.7z" }; case Architecture.X86: return new[] { - "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150110-git-4df01d5-win32-static.7z", - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150110-git-4df01d5-win32-static.7z" + "http://ffmpeg.zeranoe.com/builds/win32/static/ffmpeg-20150331-git-5cba529-win32-static.7z", + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/windows/ffmpeg-20150331-git-5cba529-win32-static.7z" }; } break; @@ -119,12 +119,12 @@ namespace MediaBrowser.Server.Startup.Common.FFMpeg case Architecture.X86_X64: return new[] { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.5.3-64bit-static.7z" + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.6.1-64bit-static.7z" }; case Architecture.X86: return new[] { - "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.5.3-32bit-static.7z" + "https://github.com/MediaBrowser/MediaBrowser.Resources/raw/master/ffmpeg/linux/ffmpeg-2.6.1-32bit-static.7z" }; } break; diff --git a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs index be8ae2f814..49114b96f3 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/RenameXmlOptions.cs @@ -44,7 +44,12 @@ namespace MediaBrowser.Server.Startup.Common.Migrations { if (string.Equals(options[i], "Media Browser Legacy Xml", StringComparison.OrdinalIgnoreCase)) { - options[i] = "Media Browser Xml"; + options[i] = "Emby Xml"; + changed = true; + } + else if (string.Equals(options[i], "Media Browser Xml", StringComparison.OrdinalIgnoreCase)) + { + options[i] = "Emby Xml"; changed = true; } } diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs index 5c4319d228..9cde958c46 100644 --- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs +++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs @@ -856,16 +856,6 @@ namespace MediaBrowser.XbmcMetadata.Savers { writer.WriteStartElement("collectionitem"); - if (!string.IsNullOrWhiteSpace(link.ItemName)) - { - writer.WriteElementString("name", link.ItemName); - } - - if (!string.IsNullOrWhiteSpace(link.ItemType)) - { - writer.WriteElementString("type", link.ItemType); - } - if (!string.IsNullOrWhiteSpace(link.Path)) { writer.WriteElementString("path", link.Path); -- cgit v1.2.3