diff options
Diffstat (limited to 'MediaBrowser.Controller')
10 files changed, 147 insertions, 184 deletions
diff --git a/MediaBrowser.Controller/Channels/IChannelManager.cs b/MediaBrowser.Controller/Channels/IChannelManager.cs index 49be897ef..e392a3493 100644 --- a/MediaBrowser.Controller/Channels/IChannelManager.cs +++ b/MediaBrowser.Controller/Channels/IChannelManager.cs @@ -16,12 +16,6 @@ namespace MediaBrowser.Controller.Channels public interface IChannelManager { /// <summary> - /// Adds the parts. - /// </summary> - /// <param name="channels">The channels.</param> - void AddParts(IEnumerable<IChannel> channels); - - /// <summary> /// Gets the channel features. /// </summary> /// <param name="id">The identifier.</param> diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 11e663301..7912c5e87 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -42,8 +42,6 @@ namespace MediaBrowser.Controller.Drawing public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; } - public bool AddPlayedIndicator { get; set; } - public int? UnplayedCount { get; set; } public int? Blur { get; set; } @@ -111,7 +109,6 @@ namespace MediaBrowser.Controller.Drawing { return (Quality >= 90) && IsFormatSupported(originalImagePath) && - !AddPlayedIndicator && PercentPlayed.Equals(0) && !UnplayedCount.HasValue && !Blur.HasValue && diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 20909c9d5..69c0d26b6 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -18,10 +18,10 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" /> - <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.2" /> - <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" /> - <PackageReference Include="System.Threading.Tasks.Dataflow" Version="7.0.0" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" /> + <PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" /> + <PackageReference Include="System.Threading.Tasks.Dataflow" /> </ItemGroup> <ItemGroup> @@ -51,13 +51,13 @@ <!-- Code Analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4"> + <PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference> - <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> - <PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="All" /> - <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> + <PackageReference Include="SerilogAnalyzer" PrivateAssets="All" /> + <PackageReference Include="StyleCop.Analyzers" PrivateAssets="All" /> + <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" PrivateAssets="All" /> </ItemGroup> </Project> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index e94a04a7d..14547d440 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -38,7 +38,10 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly ISubtitleEncoder _subtitleEncoder; private readonly IConfiguration _config; private readonly Version _minKernelVersionAmdVkFmtModifier = new Version(5, 15); - private readonly Version _minKernelVersioni915Hang = new Version(5, 18); + // i915 hang was fixed by linux 6.2 (3f882f2) + private readonly Version _minKerneli915Hang = new Version(5, 18); + private readonly Version _maxKerneli915Hang = new Version(6, 1, 3); + private readonly Version _minFixedKernel60i915Hang = new Version(6, 0, 18); private static readonly string[] _videoProfilesH264 = new[] { @@ -58,6 +61,16 @@ namespace MediaBrowser.Controller.MediaEncoding "Main10" }; + private static readonly HashSet<string> _mp4ContainerNames = new(StringComparer.OrdinalIgnoreCase) + { + "mp4", + "m4a", + "m4p", + "m4b", + "m4r", + "m4v", + }; + public EncodingHelper( IApplicationPaths appPaths, IMediaEncoder mediaEncoder, @@ -546,6 +559,12 @@ namespace MediaBrowser.Controller.MediaEncoding if (string.Equals(codec, "aac", StringComparison.OrdinalIgnoreCase)) { + // Use Apple's aac encoder if available as it provides best audio quality + if (_mediaEncoder.SupportsEncoder("aac_at")) + { + return "aac_at"; + } + // Use libfdk_aac for better audio quality if using custom build of FFmpeg which has fdk_aac support if (_mediaEncoder.SupportsEncoder("libfdk_aac")) { @@ -1336,7 +1355,7 @@ namespace MediaBrowser.Controller.MediaEncoding // which will reduce overhead in performance intensive tasks such as 4k transcoding and tonemapping. var intelLowPowerHwEncoding = false; - // Workaround for linux 5.18+ i915 hang at cost of performance. + // Workaround for linux 5.18 to 6.1.3 i915 hang at cost of performance. // https://github.com/intel/media-driver/issues/1456 var enableWaFori915Hang = false; @@ -1355,18 +1374,25 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { - if (OperatingSystem.IsLinux() && Environment.OSVersion.Version >= _minKernelVersioni915Hang) + if (OperatingSystem.IsLinux()) { - var vidDecoder = GetHardwareVideoDecoder(state, encodingOptions) ?? string.Empty; - var isIntelDecoder = vidDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase) - || vidDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase); - var doOclTonemap = _mediaEncoder.SupportsHwaccel("qsv") - && IsVaapiSupported(state) - && IsOpenclFullSupported() - && !IsVaapiVppTonemapAvailable(state, encodingOptions) - && IsHwTonemapAvailable(state, encodingOptions); + var ver = Environment.OSVersion.Version; + var isFixedKernel60 = ver.Major == 6 && ver.Minor == 0 && ver >= _minFixedKernel60i915Hang; + var isUnaffectedKernel = ver < _minKerneli915Hang || ver > _maxKerneli915Hang; - enableWaFori915Hang = isIntelDecoder && doOclTonemap; + if (!(isUnaffectedKernel || isFixedKernel60)) + { + var vidDecoder = GetHardwareVideoDecoder(state, encodingOptions) ?? string.Empty; + var isIntelDecoder = vidDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase) + || vidDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase); + var doOclTonemap = _mediaEncoder.SupportsHwaccel("qsv") + && IsVaapiSupported(state) + && IsOpenclFullSupported() + && !IsVaapiVppTonemapAvailable(state, encodingOptions) + && IsHwTonemapAvailable(state, encodingOptions); + + enableWaFori915Hang = isIntelDecoder && doOclTonemap; + } } if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) @@ -2794,6 +2820,13 @@ namespace MediaBrowser.Controller.MediaEncoding { return "deinterlace_qsv=mode=2"; } + else if (hwDeintSuffix.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + return string.Format( + CultureInfo.InvariantCulture, + "yadif_videotoolbox={0}:-1:0", + doubleRateDeint ? "1" : "0"); + } return string.Empty; } @@ -2939,8 +2972,8 @@ namespace MediaBrowser.Controller.MediaEncoding } else if (hasGraphicalSubs) { - // [0:s]scale=expr - var subSwScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH); + // [0:s]scale=s=1280x720 + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=endall:shortest=1:repeatlast=0"); } @@ -3126,9 +3159,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=endall:shortest=1:repeatlast=0"); } @@ -3328,9 +3359,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=endall:shortest=1:repeatlast=0"); } @@ -3582,9 +3611,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=endall:shortest=1:repeatlast=0"); } @@ -3793,9 +3820,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0"); } @@ -4054,9 +4079,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0"); @@ -4251,9 +4274,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0"); @@ -4428,9 +4449,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (hasGraphicalSubs) { - var subSwScaleFilter = isSwDecoder - ? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH) - : GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); + var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH); subFilters.Add(subSwScaleFilter); overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0"); @@ -4445,6 +4464,75 @@ namespace MediaBrowser.Controller.MediaEncoding } /// <summary> + /// Gets the parameter of Apple VideoToolBox filter chain. + /// </summary> + /// <param name="state">Encoding state.</param> + /// <param name="options">Encoding options.</param> + /// <param name="vidEncoder">Video encoder to use.</param> + /// <returns>The tuple contains three lists: main, sub and overlay filters.</returns> + public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetAppleVidFilterChain( + EncodingJobInfo state, + EncodingOptions options, + string vidEncoder) + { + if (!string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + return (null, null, null); + } + + var swFilterChain = GetSwVidFilterChain(state, options, vidEncoder); + + if (!options.EnableHardwareEncoding) + { + return swFilterChain; + } + + if (_mediaEncoder.EncoderVersion.CompareTo(new Version("5.0.0")) < 0) + { + // All features used here requires ffmpeg 5.0 or later, fallback to software filters if using an old ffmpeg + return swFilterChain; + } + + var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true); + var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true); + var doDeintH2645 = doDeintH264 || doDeintHevc; + var inW = state.VideoStream?.Width; + var inH = state.VideoStream?.Height; + var reqW = state.BaseRequest.Width; + var reqH = state.BaseRequest.Height; + var reqMaxW = state.BaseRequest.MaxWidth; + var reqMaxH = state.BaseRequest.MaxHeight; + var threeDFormat = state.MediaSource.Video3DFormat; + var newfilters = new List<string>(); + var noOverlay = swFilterChain.OverlayFilters.Count == 0; + var supportsHwDeint = _mediaEncoder.SupportsFilter("yadif_videotoolbox"); + // fallback to software filters if we are using filters not supported by hardware yet. + var useHardwareFilters = noOverlay && (!doDeintH2645 || supportsHwDeint); + + if (!useHardwareFilters) + { + return swFilterChain; + } + + // ffmpeg cannot use videotoolbox to scale + var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH); + newfilters.Add(swScaleFilter); + + // hwupload on videotoolbox encoders can automatically convert AVFrame into its CVPixelBuffer equivalent + // videotoolbox will automatically convert the CVPixelBuffer to a pixel format the encoder supports, so we don't have to set a pixel format explicitly here + // This will reduce CPU usage significantly on UHD videos with 10 bit colors because we bypassed the ffmpeg pixel format conversion + newfilters.Add("hwupload"); + + if (doDeintH2645) + { + var deintFilter = GetHwDeinterlaceFilter(state, options, "videotoolbox"); + newfilters.Add(deintFilter); + } + + return (newfilters, swFilterChain.SubFilters, swFilterChain.OverlayFilters); + } + + /// <summary> /// Gets the parameter of video processing filters. /// </summary> /// <param name="state">Encoding state.</param> @@ -4486,6 +4574,10 @@ namespace MediaBrowser.Controller.MediaEncoding { (mainFilters, subFilters, overlayFilters) = GetAmdVidFilterChain(state, options, outputVideoCodec); } + else if (string.Equals(options.HardwareAccelerationType, "videotoolbox", StringComparison.OrdinalIgnoreCase)) + { + (mainFilters, subFilters, overlayFilters) = GetAppleVidFilterChain(state, options, outputVideoCodec); + } else { (mainFilters, subFilters, overlayFilters) = GetSwVidFilterChain(state, options, outputVideoCodec); @@ -5766,6 +5858,11 @@ namespace MediaBrowser.Controller.MediaEncoding audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); } + if (!string.IsNullOrEmpty(state.OutputAudioCodec)) + { + audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state)); + } + if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) { // opus only supports specific sampling rates @@ -5785,6 +5882,13 @@ namespace MediaBrowser.Controller.MediaEncoding } } + // Copy the movflags from GetProgressiveVideoFullCommandLine + // See #9248 and the associated PR for why this is needed + if (_mp4ContainerNames.Contains(state.OutputContainer)) + { + audioTranscodeParams.Add("-movflags empty_moov+delay_moov"); + } + var threads = GetNumberOfThreads(state, encodingOptions, null); var inputModifier = GetInputModifier(state, encodingOptions, null); diff --git a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs index fe8e9063e..bc6207ac5 100644 --- a/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs +++ b/MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs @@ -187,13 +187,5 @@ namespace MediaBrowser.Controller.MediaEncoding /// <param name="path">The path.</param> /// <param name="pathType">The type of path.</param> void UpdateEncoderPath(string path, string pathType); - - /// <summary> - /// Gets the primary playlist of .vob files. - /// </summary> - /// <param name="path">The to the .vob files.</param> - /// <param name="titleNumber">The title number to start with.</param> - /// <returns>A playlist.</returns> - IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, uint? titleNumber); } } diff --git a/MediaBrowser.Controller/Notifications/INotificationManager.cs b/MediaBrowser.Controller/Notifications/INotificationManager.cs deleted file mode 100644 index 7caba1097..000000000 --- a/MediaBrowser.Controller/Notifications/INotificationManager.cs +++ /dev/null @@ -1,43 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationManager - { - /// <summary> - /// Sends the notification. - /// </summary> - /// <param name="request">The request.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task SendNotification(NotificationRequest request, CancellationToken cancellationToken); - - Task SendNotification(NotificationRequest request, BaseItem? relatedItem, CancellationToken cancellationToken); - - /// <summary> - /// Adds the parts. - /// </summary> - /// <param name="services">The services.</param> - /// <param name="notificationTypeFactories">The notification type factories.</param> - void AddParts(IEnumerable<INotificationService> services, IEnumerable<INotificationTypeFactory> notificationTypeFactories); - - /// <summary> - /// Gets the notification types. - /// </summary> - /// <returns>IEnumerable{NotificationTypeInfo}.</returns> - List<NotificationTypeInfo> GetNotificationTypes(); - - /// <summary> - /// Gets the notification services. - /// </summary> - /// <returns>IEnumerable{NotificationServiceInfo}.</returns> - IEnumerable<NameIdPair> GetNotificationServices(); - } -} diff --git a/MediaBrowser.Controller/Notifications/INotificationService.cs b/MediaBrowser.Controller/Notifications/INotificationService.cs deleted file mode 100644 index 535c08795..000000000 --- a/MediaBrowser.Controller/Notifications/INotificationService.cs +++ /dev/null @@ -1,34 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System.Threading; -using System.Threading.Tasks; -using Jellyfin.Data.Entities; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationService - { - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - string Name { get; } - - /// <summary> - /// Sends the notification. - /// </summary> - /// <param name="request">The request.</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task.</returns> - Task SendNotification(UserNotification request, CancellationToken cancellationToken); - - /// <summary> - /// Determines whether [is enabled for user] [the specified user identifier]. - /// </summary> - /// <param name="user">The user.</param> - /// <returns><c>true</c> if [is enabled for user] [the specified user identifier]; otherwise, <c>false</c>.</returns> - bool IsEnabledForUser(User user); - } -} diff --git a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs b/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs deleted file mode 100644 index 52a3e120b..000000000 --- a/MediaBrowser.Controller/Notifications/INotificationTypeFactory.cs +++ /dev/null @@ -1,16 +0,0 @@ -#pragma warning disable CS1591 - -using System.Collections.Generic; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public interface INotificationTypeFactory - { - /// <summary> - /// Gets the notification types. - /// </summary> - /// <returns>IEnumerable{NotificationTypeInfo}.</returns> - IEnumerable<NotificationTypeInfo> GetNotificationTypes(); - } -} diff --git a/MediaBrowser.Controller/Notifications/UserNotification.cs b/MediaBrowser.Controller/Notifications/UserNotification.cs deleted file mode 100644 index 4be0e09ae..000000000 --- a/MediaBrowser.Controller/Notifications/UserNotification.cs +++ /dev/null @@ -1,25 +0,0 @@ -#nullable disable - -#pragma warning disable CS1591 - -using System; -using Jellyfin.Data.Entities; -using MediaBrowser.Model.Notifications; - -namespace MediaBrowser.Controller.Notifications -{ - public class UserNotification - { - public string Name { get; set; } - - public string Description { get; set; } - - public string Url { get; set; } - - public NotificationLevel Level { get; set; } - - public DateTime Date { get; set; } - - public User User { get; set; } - } -} diff --git a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs index 52aa44024..841b32037 100644 --- a/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs +++ b/MediaBrowser.Controller/Subtitles/ISubtitleManager.cs @@ -20,12 +20,6 @@ namespace MediaBrowser.Controller.Subtitles event EventHandler<SubtitleDownloadFailureEventArgs> SubtitleDownloadFailure; /// <summary> - /// Adds the parts. - /// </summary> - /// <param name="subtitleProviders">The subtitle providers.</param> - void AddParts(IEnumerable<ISubtitleProvider> subtitleProviders); - - /// <summary> /// Searches the subtitles. /// </summary> /// <param name="video">The video.</param> |
