From b9cacd8076c00bfc371898c50315304927efaff8 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 5 Oct 2016 03:15:29 -0400 Subject: [PATCH 1/2] update live streams --- MediaBrowser.Api/Library/ChapterService.cs | 30 --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 2 +- MediaBrowser.Api/MediaBrowser.Api.csproj | 1 - .../Playback/BaseStreamingService.cs | 4 +- .../BaseProgressiveStreamingService.cs | 35 +-- .../Progressive/ProgressiveStreamWriter.cs | 29 ++- MediaBrowser.Api/Playback/StreamState.cs | 1 + .../Chapters/ChapterResponse.cs | 19 -- .../Chapters/ChapterSearchRequest.cs | 31 --- .../Chapters/IChapterManager.cs | 47 +--- .../Chapters/IChapterProvider.cs | 39 ---- .../Library/IMediaSourceManager.cs | 8 + .../Library/IMediaSourceProvider.cs | 3 +- .../LiveTv/ILiveTvManager.cs | 3 +- .../LiveTv/ILiveTvService.cs | 6 + .../MediaBrowser.Controller.csproj | 3 - .../MediaBrowser.Model.Portable.csproj | 9 - .../MediaBrowser.Model.net35.csproj | 9 - .../Chapters/ChapterProviderInfo.cs | 8 - .../Chapters/RemoteChapterInfo.cs | 18 -- .../Chapters/RemoteChapterResult.cs | 48 ---- .../Configuration/ChapterOptions.cs | 16 +- MediaBrowser.Model/MediaBrowser.Model.csproj | 3 - .../Chapters/ChapterManager.cs | 220 ------------------ .../MediaInfo/FFProbeVideoInfo.cs | 62 ----- .../MediaInfo/SubtitleScheduledTask.cs | 90 +++++-- .../ChannelDynamicMediaSourceProvider.cs | 2 +- .../Library/LibraryManager.cs | 19 ++ .../Library/MediaSourceManager.cs | 19 +- .../LiveTv/EmbyTV/EmbyTV.cs | 11 +- .../LiveTv/LiveTvManager.cs | 28 ++- .../LiveTv/LiveTvMediaSourceProvider.cs | 11 +- .../HdHomerun/HdHomerunLiveStream.cs | 79 ++++++- .../Sync/SyncedMediaSourceProvider.cs | 4 +- .../ApplicationHost.cs | 1 - 35 files changed, 293 insertions(+), 625 deletions(-) delete mode 100644 MediaBrowser.Api/Library/ChapterService.cs delete mode 100644 MediaBrowser.Controller/Chapters/ChapterResponse.cs delete mode 100644 MediaBrowser.Controller/Chapters/ChapterSearchRequest.cs delete mode 100644 MediaBrowser.Controller/Chapters/IChapterProvider.cs delete mode 100644 MediaBrowser.Model/Chapters/ChapterProviderInfo.cs delete mode 100644 MediaBrowser.Model/Chapters/RemoteChapterInfo.cs delete mode 100644 MediaBrowser.Model/Chapters/RemoteChapterResult.cs diff --git a/MediaBrowser.Api/Library/ChapterService.cs b/MediaBrowser.Api/Library/ChapterService.cs deleted file mode 100644 index 6b8dd18f10..0000000000 --- a/MediaBrowser.Api/Library/ChapterService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using MediaBrowser.Controller.Chapters; -using MediaBrowser.Controller.Net; -using ServiceStack; -using System.Linq; - -namespace MediaBrowser.Api.Library -{ - [Route("/Providers/Chapters", "GET")] - public class GetChapterProviders : IReturnVoid - { - } - - [Authenticated] - public class ChapterService : BaseApiService - { - private readonly IChapterManager _chapterManager; - - public ChapterService(IChapterManager chapterManager) - { - _chapterManager = chapterManager; - } - - public object Get(GetChapterProviders request) - { - var result = _chapterManager.GetProviders().ToList(); - - return ToOptimizedResult(result); - } - } -} diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 4baae031f2..ed7a0990f1 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -705,7 +705,7 @@ namespace MediaBrowser.Api.LiveTv var outputHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - outputHeaders["Content-Type"] = MimeTypes.GetMimeType(filePath); + outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType(filePath); long startPosition = 0; diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index 77949d1793..a986376503 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -79,7 +79,6 @@ - diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bcf3bd28eb..0b2fad580a 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1888,7 +1888,9 @@ namespace MediaBrowser.Api.Playback } else { - mediaSource = await MediaSourceManager.GetLiveStream(request.LiveStreamId, cancellationToken).ConfigureAwait(false); + var liveStreamInfo = await MediaSourceManager.GetLiveStreamWithDirectStreamProvider(request.LiveStreamId, cancellationToken).ConfigureAwait(false); + mediaSource = liveStreamInfo.Item1; + state.DirectStreamProvider = liveStreamInfo.Item2; } var videoRequest = request as VideoStreamRequest; diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index 4adf6fbca1..809eabef8f 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -121,32 +121,33 @@ namespace MediaBrowser.Api.Playback.Progressive var responseHeaders = new Dictionary(); - // Static remote stream - if (request.Static && state.InputProtocol == MediaProtocol.Http) + if (request.Static && state.DirectStreamProvider != null) { AddDlnaHeaders(state, responseHeaders, true); using (state) { - if (state.MediaPath.IndexOf("/livestreamfiles/", StringComparison.OrdinalIgnoreCase) != -1) - { - var parts = state.MediaPath.Split('/'); - var filename = parts[parts.Length - 2] + Path.GetExtension(parts[parts.Length - 1]); - var filePath = Path.Combine(ServerConfigurationManager.ApplicationPaths.TranscodingTempPath, filename); + var outputHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); - var outputHeaders = new Dictionary(StringComparer.OrdinalIgnoreCase); + // TODO: Don't hardcode this + outputHeaders["Content-Type"] = MediaBrowser.Model.Net.MimeTypes.GetMimeType("file.ts"); - outputHeaders["Content-Type"] = MimeTypes.GetMimeType(filePath); + var streamSource = new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, CancellationToken.None) + { + AllowEndOfFile = false + }; + return ResultFactory.GetAsyncStreamWriter(streamSource); + } + } - var streamSource = new ProgressiveFileCopier(FileSystem, filePath, outputHeaders, null, Logger, CancellationToken.None) - { - AllowEndOfFile = false - }; - return ResultFactory.GetAsyncStreamWriter(streamSource); - } + // Static remote stream + if (request.Static && state.InputProtocol == MediaProtocol.Http) + { + AddDlnaHeaders(state, responseHeaders, true); - return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource) - .ConfigureAwait(false); + using (state) + { + return await GetStaticRemoteStreamResult(state, responseHeaders, isHeadRequest, cancellationTokenSource).ConfigureAwait(false); } } diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index f601f4aa30..3477ad57bd 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -7,6 +7,7 @@ using CommonIO; using MediaBrowser.Controller.Net; using System.Collections.Generic; using ServiceStack.Web; +using MediaBrowser.Controller.Library; namespace MediaBrowser.Api.Playback.Progressive { @@ -26,6 +27,8 @@ namespace MediaBrowser.Api.Playback.Progressive public long StartPosition { get; set; } public bool AllowEndOfFile = true; + private IDirectStreamProvider _directStreamProvider; + public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) { _fileSystem = fileSystem; @@ -36,6 +39,15 @@ namespace MediaBrowser.Api.Playback.Progressive _cancellationToken = cancellationToken; } + public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) + { + _directStreamProvider = directStreamProvider; + _outputHeaders = outputHeaders; + _job = job; + _logger = logger; + _cancellationToken = cancellationToken; + } + public IDictionary Options { get @@ -44,22 +56,33 @@ namespace MediaBrowser.Api.Playback.Progressive } } + private Stream GetInputStream() + { + return _fileSystem.GetFileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true); + } + public async Task WriteToAsync(Stream outputStream) { try { + if (_directStreamProvider != null) + { + await _directStreamProvider.CopyToAsync(outputStream, _cancellationToken).ConfigureAwait(false); + return; + } + var eofCount = 0; - using (var fs = _fileSystem.GetFileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) + using (var inputStream = GetInputStream()) { if (StartPosition > 0) { - fs.Position = StartPosition; + inputStream.Position = StartPosition; } while (eofCount < 15 || !AllowEndOfFile) { - var bytesRead = await CopyToAsyncInternal(fs, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false); + var bytesRead = await CopyToAsyncInternal(inputStream, outputStream, BufferSize, _cancellationToken).ConfigureAwait(false); //var position = fs.Position; //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index 863bc01931..a59a7fe09e 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -37,6 +37,7 @@ namespace MediaBrowser.Api.Playback /// /// The log file stream. public Stream LogFileStream { get; set; } + public IDirectStreamProvider DirectStreamProvider { get; set; } public string InputContainer { get; set; } diff --git a/MediaBrowser.Controller/Chapters/ChapterResponse.cs b/MediaBrowser.Controller/Chapters/ChapterResponse.cs deleted file mode 100644 index 3c1b8ed079..0000000000 --- a/MediaBrowser.Controller/Chapters/ChapterResponse.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MediaBrowser.Model.Chapters; -using System.Collections.Generic; - -namespace MediaBrowser.Controller.Chapters -{ - public class ChapterResponse - { - /// - /// Gets or sets the chapters. - /// - /// The chapters. - public List Chapters { get; set; } - - public ChapterResponse() - { - Chapters = new List(); - } - } -} \ No newline at end of file diff --git a/MediaBrowser.Controller/Chapters/ChapterSearchRequest.cs b/MediaBrowser.Controller/Chapters/ChapterSearchRequest.cs deleted file mode 100644 index 982dc35bbc..0000000000 --- a/MediaBrowser.Controller/Chapters/ChapterSearchRequest.cs +++ /dev/null @@ -1,31 +0,0 @@ -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Entities; -using System; -using System.Collections.Generic; - -namespace MediaBrowser.Controller.Chapters -{ - public class ChapterSearchRequest : IHasProviderIds - { - public string Language { get; set; } - - public VideoContentType ContentType { get; set; } - - public string MediaPath { get; set; } - public string SeriesName { get; set; } - public string Name { get; set; } - public int? IndexNumber { get; set; } - public int? IndexNumberEnd { get; set; } - public int? ParentIndexNumber { get; set; } - public int? ProductionYear { get; set; } - public long? RuntimeTicks { get; set; } - public Dictionary ProviderIds { get; set; } - - public bool SearchAllProviders { get; set; } - - public ChapterSearchRequest() - { - ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); - } - } -} \ No newline at end of file diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs index 27e06fb8dd..4b39e66cc2 100644 --- a/MediaBrowser.Controller/Chapters/IChapterManager.cs +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -1,6 +1,4 @@ -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Chapters; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Configuration; @@ -13,12 +11,6 @@ namespace MediaBrowser.Controller.Chapters /// public interface IChapterManager { - /// - /// Adds the parts. - /// - /// The chapter providers. - void AddParts(IEnumerable chapterProviders); - /// /// Gets the chapters. /// @@ -35,43 +27,6 @@ namespace MediaBrowser.Controller.Chapters /// Task. Task SaveChapters(string itemId, List chapters, CancellationToken cancellationToken); - /// - /// Searches the specified video. - /// - /// The video. - /// The cancellation token. - /// Task{IEnumerable{RemoteChapterResult}}. - Task> Search(Video video, CancellationToken cancellationToken); - - /// - /// Searches the specified request. - /// - /// The request. - /// The cancellation token. - /// Task{IEnumerable{RemoteChapterResult}}. - Task> Search(ChapterSearchRequest request, CancellationToken cancellationToken); - - /// - /// Gets the chapters. - /// - /// The identifier. - /// The cancellation token. - /// Task{ChapterResponse}. - Task GetChapters(string id, CancellationToken cancellationToken); - - /// - /// Gets the providers. - /// - /// The item identifier. - /// IEnumerable{ChapterProviderInfo}. - IEnumerable GetProviders(string itemId); - - /// - /// Gets the providers. - /// - /// IEnumerable{ChapterProviderInfo}. - IEnumerable GetProviders(); - /// /// Gets the configuration. /// diff --git a/MediaBrowser.Controller/Chapters/IChapterProvider.cs b/MediaBrowser.Controller/Chapters/IChapterProvider.cs deleted file mode 100644 index a7505347b8..0000000000 --- a/MediaBrowser.Controller/Chapters/IChapterProvider.cs +++ /dev/null @@ -1,39 +0,0 @@ -using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Chapters; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Controller.Chapters -{ - public interface IChapterProvider - { - /// - /// Gets the name. - /// - /// The name. - string Name { get; } - - /// - /// Gets the supported media types. - /// - /// The supported media types. - IEnumerable SupportedMediaTypes { get; } - - /// - /// Searches the specified request. - /// - /// The request. - /// The cancellation token. - /// Task{IEnumerable{RemoteChapterResult}}. - Task> Search(ChapterSearchRequest request, CancellationToken cancellationToken); - - /// - /// Gets the chapters. - /// - /// The identifier. - /// The cancellation token. - /// Task{ChapterResponse}. - Task GetChapters(string id, CancellationToken cancellationToken); - } -} diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index c06470c5e0..1ab0e4cb06 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using System.IO; namespace MediaBrowser.Controller.Library { @@ -79,6 +80,8 @@ namespace MediaBrowser.Controller.Library /// The cancellation token. /// Task<MediaSourceInfo>. Task GetLiveStream(string id, CancellationToken cancellationToken); + + Task> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken); /// /// Pings the media source. @@ -95,4 +98,9 @@ namespace MediaBrowser.Controller.Library /// Task. Task CloseLiveStream(string id); } + + public interface IDirectStreamProvider + { + Task CopyToAsync(Stream stream, CancellationToken cancellationToken); + } } diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 56366e5a84..b0881ba7c4 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -3,6 +3,7 @@ using MediaBrowser.Model.Dto; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using System; namespace MediaBrowser.Controller.Library { @@ -22,7 +23,7 @@ namespace MediaBrowser.Controller.Library /// The open token. /// The cancellation token. /// Task<MediaSourceInfo>. - Task OpenMediaSource(string openToken, CancellationToken cancellationToken); + Task> OpenMediaSource(string openToken, CancellationToken cancellationToken); /// /// Closes the media source. diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index d65d1ae300..a381c7980b 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Events; +using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.LiveTv { @@ -156,7 +157,7 @@ namespace MediaBrowser.Controller.LiveTv /// The media source identifier. /// The cancellation token. /// Task{StreamResponseInfo}. - Task GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken); + Task> GetChannelStream(string id, string mediaSourceId, CancellationToken cancellationToken); /// /// Gets the program. diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs index d7d8336d02..94082b42ec 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvService.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvService.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using MediaBrowser.Controller.Library; namespace MediaBrowser.Controller.LiveTv { @@ -245,4 +246,9 @@ namespace MediaBrowser.Controller.LiveTv /// Task. Task CreateSeriesTimer(SeriesTimerInfo info, CancellationToken cancellationToken); } + + public interface ISupportsDirectStreamProvider + { + Task> GetChannelStreamWithDirectStreamProvider(string channelId, string streamId, CancellationToken cancellationToken); + } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index d70fba742e..e9d2054da3 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -91,10 +91,7 @@ - - - diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index ad7dea0a5d..59e29087c9 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -160,15 +160,6 @@ Channels\ChannelQuery.cs - - Chapters\ChapterProviderInfo.cs - - - Chapters\RemoteChapterInfo.cs - - - Chapters\RemoteChapterResult.cs - Collections\CollectionCreationResult.cs diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index 61f2f3f13a..47ebb3a926 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -132,15 +132,6 @@ Channels\ChannelQuery.cs - - Chapters\ChapterProviderInfo.cs - - - Chapters\RemoteChapterInfo.cs - - - Chapters\RemoteChapterResult.cs - Collections\CollectionCreationResult.cs diff --git a/MediaBrowser.Model/Chapters/ChapterProviderInfo.cs b/MediaBrowser.Model/Chapters/ChapterProviderInfo.cs deleted file mode 100644 index 570407c573..0000000000 --- a/MediaBrowser.Model/Chapters/ChapterProviderInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace MediaBrowser.Model.Chapters -{ - public class ChapterProviderInfo - { - public string Name { get; set; } - public string Id { get; set; } - } -} \ No newline at end of file diff --git a/MediaBrowser.Model/Chapters/RemoteChapterInfo.cs b/MediaBrowser.Model/Chapters/RemoteChapterInfo.cs deleted file mode 100644 index f2674c8424..0000000000 --- a/MediaBrowser.Model/Chapters/RemoteChapterInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ - -namespace MediaBrowser.Model.Chapters -{ - public class RemoteChapterInfo - { - /// - /// Gets or sets the start position ticks. - /// - /// The start position ticks. - public long StartPositionTicks { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } - } -} diff --git a/MediaBrowser.Model/Chapters/RemoteChapterResult.cs b/MediaBrowser.Model/Chapters/RemoteChapterResult.cs deleted file mode 100644 index 425c3ded82..0000000000 --- a/MediaBrowser.Model/Chapters/RemoteChapterResult.cs +++ /dev/null @@ -1,48 +0,0 @@ - -namespace MediaBrowser.Model.Chapters -{ - public class RemoteChapterResult - { - /// - /// Gets or sets the identifier. - /// - /// The identifier. - public string Id { get; set; } - - /// - /// Gets or sets the run time ticks. - /// - /// The run time ticks. - public long? RunTimeTicks { get; set; } - - /// - /// Gets or sets the name. - /// - /// The name. - public string Name { get; set; } - - /// - /// Gets or sets the name of the provider. - /// - /// The name of the provider. - public string ProviderName { get; set; } - - /// - /// Gets or sets the community rating. - /// - /// The community rating. - public float? CommunityRating { get; set; } - - /// - /// Gets or sets the chapter count. - /// - /// The chapter count. - public int? ChapterCount { get; set; } - - /// - /// Gets or sets the name of the three letter iso language. - /// - /// The name of the three letter iso language. - public string ThreeLetterISOLanguageName { get; set; } - } -} diff --git a/MediaBrowser.Model/Configuration/ChapterOptions.cs b/MediaBrowser.Model/Configuration/ChapterOptions.cs index c7bb6f861e..1c2b0c5276 100644 --- a/MediaBrowser.Model/Configuration/ChapterOptions.cs +++ b/MediaBrowser.Model/Configuration/ChapterOptions.cs @@ -2,18 +2,10 @@ { public class ChapterOptions { - public bool DownloadMovieChapters { get; set; } - public bool DownloadEpisodeChapters { get; set; } + public bool EnableMovieChapterImageExtraction { get; set; } + public bool EnableEpisodeChapterImageExtraction { get; set; } + public bool EnableOtherVideoChapterImageExtraction { get; set; } - public string[] FetcherOrder { get; set; } - public string[] DisabledFetchers { get; set; } - - public ChapterOptions() - { - DownloadMovieChapters = true; - - DisabledFetchers = new string[] { }; - FetcherOrder = new string[] { }; - } + public bool ExtractDuringLibraryScan { get; set; } } } \ No newline at end of file diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index c1a01680d8..69754204e5 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -84,9 +84,6 @@ - - - diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs index 88811c850d..87aaafb39f 100644 --- a/MediaBrowser.Providers/Chapters/ChapterManager.cs +++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.Chapters; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; @@ -22,7 +21,6 @@ namespace MediaBrowser.Providers.Chapters { public class ChapterManager : IChapterManager { - private IChapterProvider[] _providers; private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IServerConfigurationManager _config; @@ -36,224 +34,6 @@ namespace MediaBrowser.Providers.Chapters _itemRepo = itemRepo; } - public void AddParts(IEnumerable chapterProviders) - { - _providers = chapterProviders.ToArray(); - } - - public Task> Search(Video video, CancellationToken cancellationToken) - { - VideoContentType mediaType; - - if (video is Episode) - { - mediaType = VideoContentType.Episode; - } - else if (video is Movie) - { - mediaType = VideoContentType.Movie; - } - else - { - // These are the only supported types - return Task.FromResult>(new List()); - } - - var request = new ChapterSearchRequest - { - ContentType = mediaType, - IndexNumber = video.IndexNumber, - Language = video.GetPreferredMetadataLanguage(), - MediaPath = video.Path, - Name = video.Name, - ParentIndexNumber = video.ParentIndexNumber, - ProductionYear = video.ProductionYear, - ProviderIds = video.ProviderIds, - RuntimeTicks = video.RunTimeTicks, - SearchAllProviders = false - }; - - var episode = video as Episode; - - if (episode != null) - { - request.IndexNumberEnd = episode.IndexNumberEnd; - request.SeriesName = episode.SeriesName; - } - - return Search(request, cancellationToken); - } - - public async Task> Search(ChapterSearchRequest request, CancellationToken cancellationToken) - { - var contentType = request.ContentType; - var providers = GetInternalProviders(false) - .Where(i => i.SupportedMediaTypes.Contains(contentType)) - .ToList(); - - // If not searching all, search one at a time until something is found - if (!request.SearchAllProviders) - { - foreach (var provider in providers) - { - try - { - var currentResults = await Search(request, provider, cancellationToken).ConfigureAwait(false); - - if (currentResults.Count > 0) - { - return currentResults; - } - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading subtitles from {0}", ex, provider.Name); - } - } - return new List(); - } - - var tasks = providers.Select(async i => - { - try - { - return await Search(request, i, cancellationToken).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading subtitles from {0}", ex, i.Name); - return new List(); - } - }); - - var results = await Task.WhenAll(tasks).ConfigureAwait(false); - - return results.SelectMany(i => i); - } - - private async Task> Search(ChapterSearchRequest request, - IChapterProvider provider, - CancellationToken cancellationToken) - { - var searchResults = await provider.Search(request, cancellationToken).ConfigureAwait(false); - - var list = searchResults.ToList(); - - foreach (var result in list) - { - result.Id = GetProviderId(provider.Name) + "_" + result.Id; - result.ProviderName = provider.Name; - } - - return list; - } - - public Task GetChapters(string id, CancellationToken cancellationToken) - { - var parts = id.Split(new[] { '_' }, 2); - - var provider = GetProvider(parts.First()); - id = parts.Last(); - - return provider.GetChapters(id, cancellationToken); - } - - public IEnumerable GetProviders(string itemId) - { - var video = _libraryManager.GetItemById(itemId) as Video; - VideoContentType mediaType; - - if (video is Episode) - { - mediaType = VideoContentType.Episode; - } - else if (video is Movie) - { - mediaType = VideoContentType.Movie; - } - else - { - // These are the only supported types - return new List(); - } - - var providers = GetInternalProviders(false) - .Where(i => i.SupportedMediaTypes.Contains(mediaType)); - - return GetInfos(providers); - } - - public IEnumerable GetProviders() - { - return GetInfos(GetInternalProviders(true)); - } - - private IEnumerable GetInternalProviders(bool includeDisabledProviders) - { - var providers = _providers; - - if (!includeDisabledProviders) - { - var options = GetConfiguration(); - - providers = providers - .Where(i => !options.DisabledFetchers.Contains(i.Name)) - .ToArray(); - } - - return providers - .OrderBy(GetConfiguredOrder) - .ThenBy(GetDefaultOrder) - .ToArray(); - } - - private IEnumerable GetInfos(IEnumerable providers) - { - return providers.Select(i => new ChapterProviderInfo - { - Name = i.Name, - Id = GetProviderId(i.Name) - }); - } - - private string GetProviderId(string name) - { - return name.ToLower().GetMD5().ToString("N"); - } - - private IChapterProvider GetProvider(string id) - { - return _providers.First(i => string.Equals(id, GetProviderId(i.Name))); - } - - private int GetConfiguredOrder(IChapterProvider provider) - { - var options = GetConfiguration(); - - // See if there's a user-defined order - var index = Array.IndexOf(options.FetcherOrder, provider.Name); - - if (index != -1) - { - return index; - } - - // Not configured. Just return some high number to put it at the end. - return 100; - } - - private int GetDefaultOrder(IChapterProvider provider) - { - var hasOrder = provider as IHasOrder; - - if (hasOrder != null) - { - return hasOrder.Order; - } - - return 0; - } - public IEnumerable GetChapters(string itemId) { return _itemRepo.GetChapters(new Guid(itemId)); diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index 66fe7ea81f..8c87e991e7 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -238,22 +238,6 @@ namespace MediaBrowser.Providers.MediaInfo if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || options.MetadataRefreshMode == MetadataRefreshMode.Default) { - var chapterOptions = _chapterManager.GetConfiguration(); - - try - { - var remoteChapters = await DownloadChapters(video, chapters, chapterOptions, cancellationToken).ConfigureAwait(false); - - if (remoteChapters.Count > 0) - { - chapters = remoteChapters; - } - } - catch (Exception ex) - { - _logger.ErrorException("Error downloading chapters", ex); - } - if (chapters.Count == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video)) { AddDummyChapters(video, chapters); @@ -561,52 +545,6 @@ namespace MediaBrowser.Providers.MediaInfo currentStreams.AddRange(externalSubtitleStreams); } - private async Task> DownloadChapters(Video video, List currentChapters, ChapterOptions options, CancellationToken cancellationToken) - { - if ((options.DownloadEpisodeChapters && - video is Episode) || - (options.DownloadMovieChapters && - video is Movie)) - { - var results = await _chapterManager.Search(video, cancellationToken).ConfigureAwait(false); - - var result = results.FirstOrDefault(); - - if (result != null) - { - var chapters = await _chapterManager.GetChapters(result.Id, cancellationToken).ConfigureAwait(false); - - var chapterInfos = chapters.Chapters.Select(i => new ChapterInfo - { - Name = i.Name, - StartPositionTicks = i.StartPositionTicks - - }).ToList(); - - if (chapterInfos.All(i => i.StartPositionTicks == 0)) - { - if (currentChapters.Count >= chapterInfos.Count) - { - var index = 0; - foreach (var info in chapterInfos) - { - info.StartPositionTicks = currentChapters[index].StartPositionTicks; - index++; - } - } - else - { - chapterInfos.Clear(); - } - } - - return chapterInfos; - } - } - - return new List(); - } - /// /// The dummy chapter duration /// diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs index 79da291b77..2490f71453 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleScheduledTask.cs @@ -14,6 +14,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; +using System.IO; +using MediaBrowser.Model.Serialization; namespace MediaBrowser.Providers.MediaInfo { @@ -24,14 +26,16 @@ namespace MediaBrowser.Providers.MediaInfo private readonly ISubtitleManager _subtitleManager; private readonly IMediaSourceManager _mediaSourceManager; private readonly ILogger _logger; + private IJsonSerializer _json; - public SubtitleScheduledTask(ILibraryManager libraryManager, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, IMediaSourceManager mediaSourceManager) + public SubtitleScheduledTask(ILibraryManager libraryManager, IJsonSerializer json, IServerConfigurationManager config, ISubtitleManager subtitleManager, ILogger logger, IMediaSourceManager mediaSourceManager) { _libraryManager = libraryManager; _config = config; _subtitleManager = subtitleManager; _logger = logger; _mediaSourceManager = mediaSourceManager; + _json = json; } public string Name @@ -58,38 +62,65 @@ namespace MediaBrowser.Providers.MediaInfo { var options = GetOptions(); - var videos = _libraryManager.RootFolder - .GetRecursiveChildren(i => - { - if (!(i is Video)) - { - return false; - } + var types = new List(); - if (i.LocationType == LocationType.Remote || i.LocationType == LocationType.Virtual) - { - return false; - } + if (options.DownloadEpisodeSubtitles) + { + types.Add("Episode"); + } + if (options.DownloadMovieSubtitles) + { + types.Add("Movie"); + } - return (options.DownloadEpisodeSubtitles && - i is Episode) || - (options.DownloadMovieSubtitles && - i is Movie); - }) - .Cast