mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-21 15:10:44 +01:00
Merge remote-tracking branch 'upstream/master' into network-rewrite
This commit is contained in:
@@ -35,7 +35,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
public SemaphoreSlim MetadataRefreshThrottler { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name)
|
||||
public bool IsMetadataFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name)
|
||||
{
|
||||
if (baseItem is Channel)
|
||||
{
|
||||
@@ -49,10 +49,9 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
return !baseItem.EnableMediaSourceDisplay;
|
||||
}
|
||||
|
||||
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
|
||||
if (typeOptions != null)
|
||||
if (libraryTypeOptions != null)
|
||||
{
|
||||
return typeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
return libraryTypeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
@@ -61,7 +60,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name)
|
||||
public bool IsImageFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name)
|
||||
{
|
||||
if (baseItem is Channel)
|
||||
{
|
||||
@@ -75,10 +74,9 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
return !baseItem.EnableMediaSourceDisplay;
|
||||
}
|
||||
|
||||
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
|
||||
if (typeOptions != null)
|
||||
if (libraryTypeOptions != null)
|
||||
{
|
||||
return typeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
return libraryTypeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
@@ -18,18 +18,18 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
/// Is metadata fetcher enabled.
|
||||
/// </summary>
|
||||
/// <param name="baseItem">The base item.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <param name="libraryTypeOptions">The type options for <c>baseItem</c> from the library (if defined).</param>
|
||||
/// <param name="name">The metadata fetcher name.</param>
|
||||
/// <returns><c>true</c> if metadata fetcher is enabled, else false.</returns>
|
||||
bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
|
||||
bool IsMetadataFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Is image fetcher enabled.
|
||||
/// </summary>
|
||||
/// <param name="baseItem">The base item.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <param name="libraryTypeOptions">The type options for <c>baseItem</c> from the library (if defined).</param>
|
||||
/// <param name="name">The image fetcher name.</param>
|
||||
/// <returns><c>true</c> if image fetcher is enabled, else false.</returns>
|
||||
bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
|
||||
bool IsImageFetcherEnabled(BaseItem baseItem, TypeOptions? libraryTypeOptions, string name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
public string AlbumArtist => AlbumArtists.FirstOrDefault();
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
public override bool SupportsPeople => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
|
||||
@@ -75,7 +75,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
Model.Entities.ExtraType.DeletedScene,
|
||||
Model.Entities.ExtraType.Interview,
|
||||
Model.Entities.ExtraType.Sample,
|
||||
Model.Entities.ExtraType.Scene
|
||||
Model.Entities.ExtraType.Scene,
|
||||
Model.Entities.ExtraType.Featurette,
|
||||
Model.Entities.ExtraType.Short
|
||||
};
|
||||
|
||||
private string _sortName;
|
||||
@@ -775,36 +777,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return Id.ToString("N", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
|
||||
{
|
||||
var list = new List<Tuple<StringBuilder, bool>>();
|
||||
|
||||
int thisMarker = 0;
|
||||
|
||||
while (thisMarker < s1.Length)
|
||||
{
|
||||
char thisCh = s1[thisMarker];
|
||||
|
||||
var thisChunk = new StringBuilder();
|
||||
bool isNumeric = char.IsDigit(thisCh);
|
||||
|
||||
while (thisMarker < s1.Length && char.IsDigit(thisCh) == isNumeric)
|
||||
{
|
||||
thisChunk.Append(thisCh);
|
||||
thisMarker++;
|
||||
|
||||
if (thisMarker < s1.Length)
|
||||
{
|
||||
thisCh = s1[thisMarker];
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public virtual bool CanDelete()
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
@@ -951,28 +923,40 @@ namespace MediaBrowser.Controller.Entities
|
||||
return ModifySortChunks(sortable);
|
||||
}
|
||||
|
||||
private string ModifySortChunks(string name)
|
||||
internal static string ModifySortChunks(string name)
|
||||
{
|
||||
var chunks = GetSortChunks(name);
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var chunk in chunks)
|
||||
void AppendChunk(StringBuilder builder, bool isDigitChunk, ReadOnlySpan<char> chunk)
|
||||
{
|
||||
var chunkBuilder = chunk.Item1;
|
||||
|
||||
// This chunk is numeric
|
||||
if (chunk.Item2)
|
||||
if (isDigitChunk && chunk.Length < 10)
|
||||
{
|
||||
while (chunkBuilder.Length < 10)
|
||||
{
|
||||
chunkBuilder.Insert(0, '0');
|
||||
}
|
||||
builder.Append('0', 10 - chunk.Length);
|
||||
}
|
||||
|
||||
builder.Append(chunkBuilder);
|
||||
builder.Append(chunk);
|
||||
}
|
||||
|
||||
if (name.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var builder = new StringBuilder(name.Length);
|
||||
|
||||
int chunkStart = 0;
|
||||
bool isDigitChunk = char.IsDigit(name[0]);
|
||||
for (int i = 0; i < name.Length; i++)
|
||||
{
|
||||
var isDigit = char.IsDigit(name[i]);
|
||||
if (isDigit != isDigitChunk)
|
||||
{
|
||||
AppendChunk(builder, isDigitChunk, name.AsSpan(chunkStart, i - chunkStart));
|
||||
chunkStart = i;
|
||||
isDigitChunk = isDigit;
|
||||
}
|
||||
}
|
||||
|
||||
AppendChunk(builder, isDigitChunk, name.AsSpan(chunkStart));
|
||||
|
||||
// logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
|
||||
return builder.ToString().RemoveDiacritics();
|
||||
}
|
||||
|
||||
@@ -205,6 +205,16 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public int? MinIndexNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum ParentIndexNumber and IndexNumber.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It produces this where clause:
|
||||
/// <para>(ParentIndexNumber = X and IndexNumber >= Y) or ParentIndexNumber > X.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public (int ParentIndexNumber, int IndexNumber)? MinParentAndIndexNumber { get; set; }
|
||||
|
||||
public int? AiredDuringSeason { get; set; }
|
||||
|
||||
public double? MinCriticRating { get; set; }
|
||||
|
||||
@@ -33,9 +33,9 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the TMDB collection.
|
||||
/// Gets or sets the name of the TMDb collection.
|
||||
/// </summary>
|
||||
/// <value>The name of the TMDB collection.</value>
|
||||
/// <value>The name of the TMDb collection.</value>
|
||||
public string TmdbCollectionName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
|
||||
@@ -34,12 +34,5 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
void ReportFileSystemChanged(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is path locked] [the specified path].
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is path locked] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
bool IsPathLocked(string path);
|
||||
}
|
||||
}
|
||||
|
||||
24
MediaBrowser.Controller/Lyrics/ILyricManager.cs
Normal file
24
MediaBrowser.Controller/Lyrics/ILyricManager.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// Interface ILyricManager.
|
||||
/// </summary>
|
||||
public interface ILyricManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the lyrics.
|
||||
/// </summary>
|
||||
/// <param name="item">The media item.</param>
|
||||
/// <returns>A task representing found lyrics the passed item.</returns>
|
||||
Task<LyricResponse?> GetLyrics(BaseItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if requested item has a matching local lyric file.
|
||||
/// </summary>
|
||||
/// <param name="item">The media item.</param>
|
||||
/// <returns>True if item has a matching lyric file; otherwise false.</returns>
|
||||
bool HasLyricFile(BaseItem item);
|
||||
}
|
||||
36
MediaBrowser.Controller/Lyrics/ILyricProvider.cs
Normal file
36
MediaBrowser.Controller/Lyrics/ILyricProvider.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// Interface ILyricsProvider.
|
||||
/// </summary>
|
||||
public interface ILyricProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating the provider name.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the priority.
|
||||
/// </summary>
|
||||
/// <value>The priority.</value>
|
||||
ResolverPriority Priority { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the supported media types for this provider.
|
||||
/// </summary>
|
||||
/// <value>The supported media types.</value>
|
||||
IReadOnlyCollection<string> SupportedMediaTypes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lyrics.
|
||||
/// </summary>
|
||||
/// <param name="item">The media item.</param>
|
||||
/// <returns>A task representing found lyrics.</returns>
|
||||
Task<LyricResponse?> GetLyrics(BaseItem item);
|
||||
}
|
||||
49
MediaBrowser.Controller/Lyrics/LyricInfo.cs
Normal file
49
MediaBrowser.Controller/Lyrics/LyricInfo.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Jellyfin.Extensions;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// Lyric helper methods.
|
||||
/// </summary>
|
||||
public static class LyricInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets matching lyric file for a requested item.
|
||||
/// </summary>
|
||||
/// <param name="lyricProvider">The lyricProvider interface to use.</param>
|
||||
/// <param name="itemPath">Path of requested item.</param>
|
||||
/// <returns>Lyric file path if passed lyric provider's supported media type is found; otherwise, null.</returns>
|
||||
public static string? GetLyricFilePath(this ILyricProvider lyricProvider, string itemPath)
|
||||
{
|
||||
// Ensure we have a provider
|
||||
if (lyricProvider is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure the path to the item is not null
|
||||
string? itemDirectoryPath = Path.GetDirectoryName(itemPath);
|
||||
if (itemDirectoryPath is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Ensure the directory path exists
|
||||
if (!Directory.Exists(itemDirectoryPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var lyricFilePath in Directory.GetFiles(itemDirectoryPath, $"{Path.GetFileNameWithoutExtension(itemPath)}.*"))
|
||||
{
|
||||
if (lyricProvider.SupportedMediaTypes.Contains(Path.GetExtension(lyricFilePath.AsSpan())[1..], StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return lyricFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
28
MediaBrowser.Controller/Lyrics/LyricLine.cs
Normal file
28
MediaBrowser.Controller/Lyrics/LyricLine.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// Lyric model.
|
||||
/// </summary>
|
||||
public class LyricLine
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LyricLine"/> class.
|
||||
/// </summary>
|
||||
/// <param name="text">The lyric text.</param>
|
||||
/// <param name="start">The lyric start time in ticks.</param>
|
||||
public LyricLine(string text, long? start = null)
|
||||
{
|
||||
Text = text;
|
||||
Start = start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text of this lyric line.
|
||||
/// </summary>
|
||||
public string Text { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the start time in ticks.
|
||||
/// </summary>
|
||||
public long? Start { get; }
|
||||
}
|
||||
54
MediaBrowser.Controller/Lyrics/LyricMetadata.cs
Normal file
54
MediaBrowser.Controller/Lyrics/LyricMetadata.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// LyricMetadata model.
|
||||
/// </summary>
|
||||
public class LyricMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the song artist.
|
||||
/// </summary>
|
||||
public string? Artist { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album this song is on.
|
||||
/// </summary>
|
||||
public string? Album { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title of the song.
|
||||
/// </summary>
|
||||
public string? Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the author of the lyric data.
|
||||
/// </summary>
|
||||
public string? Author { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the length of the song in ticks.
|
||||
/// </summary>
|
||||
public long? Length { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets who the LRC file was created by.
|
||||
/// </summary>
|
||||
public string? By { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the lyric offset compared to audio in ticks.
|
||||
/// </summary>
|
||||
public long? Offset { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the software used to create the LRC file.
|
||||
/// </summary>
|
||||
public string? Creator { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the version of the creator used.
|
||||
/// </summary>
|
||||
public string? Version { get; set; }
|
||||
}
|
||||
20
MediaBrowser.Controller/Lyrics/LyricResponse.cs
Normal file
20
MediaBrowser.Controller/Lyrics/LyricResponse.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// LyricResponse model.
|
||||
/// </summary>
|
||||
public class LyricResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets Metadata for the lyrics.
|
||||
/// </summary>
|
||||
public LyricMetadata Metadata { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a collection of individual lyric lines.
|
||||
/// </summary>
|
||||
public IReadOnlyList<LyricLine> Lyrics { get; set; } = Array.Empty<LyricLine>();
|
||||
}
|
||||
@@ -31,10 +31,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
private const string VideotoolboxAlias = "vt";
|
||||
private const string OpenclAlias = "ocl";
|
||||
private const string CudaAlias = "cu";
|
||||
private const string DrmAlias = "dr";
|
||||
private const string VulkanAlias = "vk";
|
||||
private readonly IApplicationPaths _appPaths;
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ISubtitleEncoder _subtitleEncoder;
|
||||
private readonly IConfiguration _config;
|
||||
private readonly Version _minKernelVersionAmdVkFmtModifier = new Version(5, 15);
|
||||
private readonly Version _minKernelVersioni915Hang = new Version(5, 18);
|
||||
|
||||
private static readonly string[] _videoProfilesH264 = new[]
|
||||
@@ -149,6 +152,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
&& _mediaEncoder.SupportsFilter("hwupload_cuda");
|
||||
}
|
||||
|
||||
private bool IsVulkanFullSupported()
|
||||
{
|
||||
return _mediaEncoder.SupportsHwaccel("vulkan")
|
||||
&& _mediaEncoder.SupportsFilter("libplacebo")
|
||||
&& _mediaEncoder.SupportsFilter("scale_vulkan")
|
||||
&& _mediaEncoder.SupportsFilterWithOption(FilterOptionType.OverlayVulkanFrameSync);
|
||||
}
|
||||
|
||||
private bool IsHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
|
||||
{
|
||||
if (state.VideoStream == null
|
||||
@@ -176,6 +187,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|| string.Equals(state.VideoStream.VideoRangeType, "HLG", StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
|
||||
{
|
||||
if (state.VideoStream == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// libplacebo has partial Dolby Vision to SDR tonemapping support.
|
||||
return options.EnableTonemapping
|
||||
&& string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase)
|
||||
&& GetVideoColorBitDepth(state) == 10;
|
||||
}
|
||||
|
||||
private bool IsVaapiVppTonemapAvailable(EncodingJobInfo state, EncodingOptions options)
|
||||
{
|
||||
if (state.VideoStream == null
|
||||
@@ -756,8 +780,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
else if (_mediaEncoder.IsVaapiDeviceAmd)
|
||||
{
|
||||
args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias));
|
||||
filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias);
|
||||
if (!IsVulkanFullSupported()
|
||||
|| !_mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier
|
||||
|| Environment.OSVersion.Version < _minKernelVersionAmdVkFmtModifier)
|
||||
{
|
||||
args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias));
|
||||
filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -948,7 +977,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
// Disable auto inserted SW scaler for HW decoders in case of changed resolution.
|
||||
var isSwDecoder = string.IsNullOrEmpty(GetHardwareVideoDecoder(state, options));
|
||||
if (!isSwDecoder)
|
||||
if (!isSwDecoder && _mediaEncoder.EncoderVersion >= new Version(4, 4))
|
||||
{
|
||||
arg.Append(" -autoscale 0");
|
||||
}
|
||||
@@ -1147,24 +1176,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
":fontsdir='{0}'",
|
||||
_mediaEncoder.EscapeSubtitleFilterPath(fontPath));
|
||||
|
||||
// TODO
|
||||
// var fallbackFontPath = Path.Combine(_appPaths.ProgramDataPath, "fonts", "DroidSansFallback.ttf");
|
||||
// string fallbackFontParam = string.Empty;
|
||||
|
||||
// if (!File.Exists(fallbackFontPath))
|
||||
// {
|
||||
// _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fallbackFontPath));
|
||||
// using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), GetType().Namespace + ".DroidSansFallback.ttf"))
|
||||
// {
|
||||
// using (var fileStream = new FileStream(fallbackFontPath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
// {
|
||||
// stream.CopyTo(fileStream);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// fallbackFontParam = string.Format(CultureInfo.InvariantCulture, ":force_style='FontName=Droid Sans Fallback':fontsdir='{0}'", _mediaEncoder.EscapeSubtitleFilterPath(_fileSystem.GetDirectoryName(fallbackFontPath)));
|
||||
|
||||
if (state.SubtitleStream.IsExternal)
|
||||
{
|
||||
var charsetParam = string.Empty;
|
||||
@@ -1192,7 +1203,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
alphaParam,
|
||||
sub2videoParam,
|
||||
fontParam,
|
||||
// fallbackFontParam,
|
||||
setPtsParam);
|
||||
}
|
||||
|
||||
@@ -1430,7 +1440,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
param += " -preset 7";
|
||||
}
|
||||
|
||||
param += " -look_ahead 0";
|
||||
// Only h264_qsv has look_ahead option
|
||||
if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
param += " -look_ahead 0";
|
||||
}
|
||||
}
|
||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|
||||
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
|
||||
@@ -1468,7 +1482,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
break;
|
||||
|
||||
default:
|
||||
param += " -preset p4";
|
||||
param += " -preset p1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2774,22 +2788,41 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709";
|
||||
var args = string.Empty;
|
||||
var algorithm = options.TonemappingAlgorithm;
|
||||
|
||||
if (hwTonemapSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
if (string.Equals(hwTonemapSuffix, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
args += ",procamp_vaapi=b={2}:c={3}:extra_hw_frames=16";
|
||||
args = "tonemap_vaapi=format={0}:p=bt709:t=bt709:m=bt709,procamp_vaapi=b={1}:c={2}:extra_hw_frames=16";
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
args,
|
||||
hwTonemapSuffix,
|
||||
videoFormat ?? "nv12",
|
||||
options.VppTonemappingBrightness,
|
||||
options.VppTonemappingContrast);
|
||||
}
|
||||
else if (string.Equals(hwTonemapSuffix, "vulkan", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
args = "libplacebo=format={1}:tonemapping={2}:color_primaries=bt709:color_trc=bt709:colorspace=bt709:peak_detect=0:upscaler=none:downscaler=none";
|
||||
|
||||
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
args += ":range={6}";
|
||||
}
|
||||
|
||||
if (string.Equals(options.TonemappingAlgorithm, "bt2390", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
algorithm = "bt.2390";
|
||||
}
|
||||
|
||||
else if (string.Equals(options.TonemappingAlgorithm, "none", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
algorithm = "clip";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args += ":tonemap={2}:peak={3}:desat={4}";
|
||||
args = "tonemap_{0}=format={1}:p=bt709:t=bt709:m=bt709:tonemap={2}:peak={3}:desat={4}";
|
||||
|
||||
if (options.TonemappingParam != 0)
|
||||
{
|
||||
@@ -2807,7 +2840,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
args,
|
||||
hwTonemapSuffix,
|
||||
videoFormat ?? "nv12",
|
||||
options.TonemappingAlgorithm,
|
||||
algorithm,
|
||||
options.TonemappingPeak,
|
||||
options.TonemappingDesat,
|
||||
options.TonemappingParam,
|
||||
@@ -3419,6 +3452,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// map from d3d11va to qsv.
|
||||
mainFilters.Add("hwmap=derive_device=qsv");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert a qsv scaler to sync the decoder surface,
|
||||
// msdk will passthrough this internally.
|
||||
mainFilters.Add("hwmap=derive_device=qsv,scale_qsv");
|
||||
}
|
||||
}
|
||||
|
||||
// hw deint
|
||||
@@ -3770,7 +3809,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty;
|
||||
var isSwDecoder = string.IsNullOrEmpty(vidDecoder);
|
||||
var isSwEncoder = !vidEncoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
|
||||
var isVaapiOclSupported = isLinux && IsVaapiSupported(state) && IsVaapiFullSupported() && IsOpenclFullSupported();
|
||||
var isVaapiFullSupported = isLinux && IsVaapiSupported(state) && IsVaapiFullSupported();
|
||||
var isVaapiOclSupported = isVaapiFullSupported && IsOpenclFullSupported();
|
||||
var isVaapiVkSupported = isVaapiFullSupported && IsVulkanFullSupported();
|
||||
|
||||
// legacy vaapi pipeline(copy-back)
|
||||
if ((isSwDecoder && isSwEncoder)
|
||||
@@ -3798,14 +3839,24 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
if (_mediaEncoder.IsVaapiDeviceInteliHD)
|
||||
{
|
||||
// Intel iHD path, with extra vpp tonemap and overlay support.
|
||||
return GetVaapiFullVidFiltersPrefered(state, options, vidDecoder, vidEncoder);
|
||||
return GetIntelVaapiFullVidFiltersPrefered(state, options, vidDecoder, vidEncoder);
|
||||
}
|
||||
|
||||
// Intel i965 and Amd radeonsi/r600 path, only featuring scale and deinterlace support.
|
||||
// prefered vaapi + vulkan filters pipeline
|
||||
if (_mediaEncoder.IsVaapiDeviceAmd
|
||||
&& isVaapiVkSupported
|
||||
&& _mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier
|
||||
&& Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier)
|
||||
{
|
||||
// AMD radeonsi path(Vega/gfx9+, kernel>=5.15), with extra vulkan tonemap and overlay support.
|
||||
return GetAmdVaapiFullVidFiltersPrefered(state, options, vidDecoder, vidEncoder);
|
||||
}
|
||||
|
||||
// Intel i965 and Amd radeonsi/r600 path(Polaris/gfx8-), only featuring scale and deinterlace support.
|
||||
return GetVaapiLimitedVidFiltersPrefered(state, options, vidDecoder, vidEncoder);
|
||||
}
|
||||
|
||||
public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetVaapiFullVidFiltersPrefered(
|
||||
public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetIntelVaapiFullVidFiltersPrefered(
|
||||
EncodingJobInfo state,
|
||||
EncodingOptions options,
|
||||
string vidDecoder,
|
||||
@@ -4003,6 +4054,203 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return (mainFilters, subFilters, overlayFilters);
|
||||
}
|
||||
|
||||
public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetAmdVaapiFullVidFiltersPrefered(
|
||||
EncodingJobInfo state,
|
||||
EncodingOptions options,
|
||||
string vidDecoder,
|
||||
string vidEncoder)
|
||||
{
|
||||
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 isVaapiDecoder = vidDecoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
|
||||
var isVaapiEncoder = vidEncoder.Contains("vaapi", StringComparison.OrdinalIgnoreCase);
|
||||
var isSwDecoder = string.IsNullOrEmpty(vidDecoder);
|
||||
var isSwEncoder = !isVaapiEncoder;
|
||||
var isVaInVaOut = isVaapiDecoder && isVaapiEncoder;
|
||||
|
||||
var doDeintH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
||||
var doDeintHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
||||
var doVkTonemap = IsVulkanHwTonemapAvailable(state, options);
|
||||
var doDeintH2645 = doDeintH264 || doDeintHevc;
|
||||
|
||||
var hasSubs = state.SubtitleStream != null && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
|
||||
var hasTextSubs = hasSubs && state.SubtitleStream.IsTextSubtitleStream;
|
||||
var hasGraphicalSubs = hasSubs && !state.SubtitleStream.IsTextSubtitleStream;
|
||||
var hasAssSubs = hasSubs
|
||||
&& (string.Equals(state.SubtitleStream.Codec, "ass", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(state.SubtitleStream.Codec, "ssa", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
/* Make main filters for video stream */
|
||||
var mainFilters = new List<string>();
|
||||
|
||||
mainFilters.Add(GetOverwriteColorPropertiesParam(state, doVkTonemap));
|
||||
|
||||
if (isSwDecoder)
|
||||
{
|
||||
// INPUT sw surface(memory)
|
||||
// sw deint
|
||||
if (doDeintH2645)
|
||||
{
|
||||
var swDeintFilter = GetSwDeinterlaceFilter(state, options);
|
||||
mainFilters.Add(swDeintFilter);
|
||||
}
|
||||
|
||||
var outFormat = doVkTonemap ? "yuv420p10le" : "nv12";
|
||||
var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH);
|
||||
// sw scale
|
||||
mainFilters.Add(swScaleFilter);
|
||||
mainFilters.Add("format=" + outFormat);
|
||||
|
||||
// keep video at memory except vk tonemap,
|
||||
// since the overhead caused by hwupload >>> using sw filter.
|
||||
// sw => hw
|
||||
if (doVkTonemap)
|
||||
{
|
||||
mainFilters.Add("hwupload=derive_device=vulkan:extra_hw_frames=16");
|
||||
}
|
||||
}
|
||||
else if (isVaapiDecoder)
|
||||
{
|
||||
// INPUT vaapi surface(vram)
|
||||
// hw deint
|
||||
if (doDeintH2645)
|
||||
{
|
||||
var deintFilter = GetHwDeinterlaceFilter(state, options, "vaapi");
|
||||
mainFilters.Add(deintFilter);
|
||||
}
|
||||
|
||||
var outFormat = doVkTonemap ? string.Empty : (hasSubs && isVaInVaOut ? "bgra" : "nv12");
|
||||
var hwScaleFilter = GetHwScaleFilter("vaapi", outFormat, inW, inH, reqW, reqH, reqMaxW, reqMaxH);
|
||||
|
||||
// allocate extra pool sizes for overlay_vulkan
|
||||
if (!string.IsNullOrEmpty(hwScaleFilter) && isVaInVaOut && hasSubs)
|
||||
{
|
||||
hwScaleFilter += ":extra_hw_frames=32";
|
||||
}
|
||||
|
||||
// hw scale
|
||||
mainFilters.Add(hwScaleFilter);
|
||||
}
|
||||
|
||||
if ((isVaapiDecoder && doVkTonemap) || (isVaInVaOut && (doVkTonemap || hasSubs)))
|
||||
{
|
||||
// map from vaapi to vulkan via vaapi-vulkan interop (Vega/gfx9+).
|
||||
mainFilters.Add("hwmap=derive_device=vulkan");
|
||||
}
|
||||
|
||||
// vk tonemap
|
||||
if (doVkTonemap)
|
||||
{
|
||||
var outFormat = isVaInVaOut && hasSubs ? "bgra" : "nv12";
|
||||
var tonemapFilter = GetHwTonemapFilter(options, "vulkan", outFormat);
|
||||
mainFilters.Add(tonemapFilter);
|
||||
}
|
||||
|
||||
if (doVkTonemap && isVaInVaOut && !hasSubs)
|
||||
{
|
||||
// OUTPUT vaapi(nv12/bgra) surface(vram)
|
||||
// reverse-mapping via vaapi-vulkan interop.
|
||||
mainFilters.Add("hwmap=derive_device=vaapi:reverse=1");
|
||||
mainFilters.Add("format=vaapi");
|
||||
}
|
||||
|
||||
var memoryOutput = false;
|
||||
var isUploadForVkTonemap = isSwDecoder && doVkTonemap;
|
||||
if ((isVaapiDecoder && isSwEncoder) || isUploadForVkTonemap)
|
||||
{
|
||||
memoryOutput = true;
|
||||
|
||||
// OUTPUT nv12 surface(memory)
|
||||
mainFilters.Add("hwdownload");
|
||||
mainFilters.Add("format=nv12");
|
||||
}
|
||||
|
||||
// OUTPUT nv12 surface(memory)
|
||||
if (isSwDecoder && isVaapiEncoder)
|
||||
{
|
||||
memoryOutput = true;
|
||||
}
|
||||
|
||||
if (memoryOutput)
|
||||
{
|
||||
// text subtitles
|
||||
if (hasTextSubs)
|
||||
{
|
||||
var textSubtitlesFilter = GetTextSubtitlesFilter(state, false, false);
|
||||
mainFilters.Add(textSubtitlesFilter);
|
||||
}
|
||||
}
|
||||
|
||||
if (memoryOutput && isVaapiEncoder)
|
||||
{
|
||||
if (!hasGraphicalSubs)
|
||||
{
|
||||
mainFilters.Add("hwupload_vaapi");
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sub and overlay filters for subtitle stream */
|
||||
var subFilters = new List<string>();
|
||||
var overlayFilters = new List<string>();
|
||||
if (isVaInVaOut)
|
||||
{
|
||||
if (hasSubs)
|
||||
{
|
||||
if (hasGraphicalSubs)
|
||||
{
|
||||
// scale=s=1280x720,format=bgra,hwupload
|
||||
var subSwScaleFilter = GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH);
|
||||
subFilters.Add(subSwScaleFilter);
|
||||
subFilters.Add("format=bgra");
|
||||
}
|
||||
else if (hasTextSubs)
|
||||
{
|
||||
var alphaSrcFilter = GetAlphaSrcFilter(state, inW, inH, reqW, reqH, reqMaxW, reqMaxH, hasAssSubs ? 10 : 5);
|
||||
var subTextSubtitlesFilter = GetTextSubtitlesFilter(state, true, true);
|
||||
subFilters.Add(alphaSrcFilter);
|
||||
subFilters.Add("format=bgra");
|
||||
subFilters.Add(subTextSubtitlesFilter);
|
||||
}
|
||||
|
||||
subFilters.Add("hwupload=derive_device=vulkan:extra_hw_frames=16");
|
||||
|
||||
overlayFilters.Add("overlay_vulkan=eof_action=endall:shortest=1:repeatlast=0");
|
||||
|
||||
// explicitly sync using libplacebo.
|
||||
overlayFilters.Add("libplacebo=format=nv12:upscaler=none:downscaler=none");
|
||||
|
||||
// OUTPUT vaapi(nv12/bgra) surface(vram)
|
||||
// reverse-mapping via vaapi-vulkan interop.
|
||||
overlayFilters.Add("hwmap=derive_device=vaapi:reverse=1");
|
||||
overlayFilters.Add("format=vaapi");
|
||||
}
|
||||
}
|
||||
else if (memoryOutput)
|
||||
{
|
||||
if (hasGraphicalSubs)
|
||||
{
|
||||
var subSwScaleFilter = isSwDecoder
|
||||
? GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH)
|
||||
: GetCustomSwScaleFilter(inW, inH, reqW, reqH, reqMaxW, reqMaxH);
|
||||
subFilters.Add(subSwScaleFilter);
|
||||
overlayFilters.Add("overlay=eof_action=pass:shortest=1:repeatlast=0");
|
||||
|
||||
if (isVaapiEncoder)
|
||||
{
|
||||
overlayFilters.Add("hwupload_vaapi");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (mainFilters, subFilters, overlayFilters);
|
||||
}
|
||||
|
||||
public (List<string> MainFilters, List<string> SubFilters, List<string> OverlayFilters) GetVaapiLimitedVidFiltersPrefered(
|
||||
EncodingJobInfo state,
|
||||
EncodingOptions options,
|
||||
@@ -5321,7 +5569,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
&& state.BaseRequest.Context == EncodingContext.Streaming)
|
||||
{
|
||||
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||
format = " -f mp4 -movflags frag_keyframe+empty_moov";
|
||||
format = " -f mp4 -movflags frag_keyframe+empty_moov+delay_moov";
|
||||
}
|
||||
|
||||
var threads = GetNumberOfThreads(state, encodingOptions, videoCodec);
|
||||
|
||||
@@ -28,6 +28,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <summary>
|
||||
/// The overlay_vaapi_framesync.
|
||||
/// </summary>
|
||||
OverlayVaapiFrameSync = 4
|
||||
OverlayVaapiFrameSync = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The overlay_vulkan_framesync.
|
||||
/// </summary>
|
||||
OverlayVulkanFrameSync = 5
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <value><c>true</c> if the Vaapi device is an Intel(legacy i965 driver) GPU, <c>false</c> otherwise.</value>
|
||||
bool IsVaapiDeviceInteli965 { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the configured Vaapi device supports vulkan drm format modifier.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if the Vaapi device supports vulkan drm format modifier, <c>false</c> otherwise.</value>
|
||||
bool IsVaapiDeviceSupportVulkanFmtModifier { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether given encoder codec is supported.
|
||||
/// </summary>
|
||||
|
||||
@@ -227,9 +227,10 @@ namespace MediaBrowser.Controller.Net
|
||||
connection.Item2.Cancel();
|
||||
connection.Item2.Dispose();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
// TODO Investigate and properly fix.
|
||||
Logger.LogError(ex, "Object Disposed");
|
||||
}
|
||||
|
||||
lock (_activeConnections)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
@@ -14,6 +15,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: InternalsVisibleTo("Jellyfin.Controller.Tests")]
|
||||
[assembly: InternalsVisibleTo("Jellyfin.Server.Implementations.Tests")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
|
||||
@@ -18,9 +18,9 @@ namespace MediaBrowser.Controller.Providers
|
||||
/// Fetches the metadata asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task{ItemUpdateType}.</returns>
|
||||
/// <param name="options">The <see cref="MetadataRefreshOptions"/>.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
||||
/// <returns>A <see cref="Task"/> fetching the <see cref="ItemUpdateType"/>.</returns>
|
||||
Task<ItemUpdateType> FetchAsync(TItemType item, MetadataRefreshOptions options, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHasOrder.
|
||||
/// </summary>
|
||||
public interface IHasOrder
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
int Order { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ namespace MediaBrowser.Controller.Providers
|
||||
/// <returns><c>true</c> if this instance can refresh the specified item.</returns>
|
||||
bool CanRefresh(BaseItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance primarily targets the specified type.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
/// <returns><c>true</c> if this instance primarily targets the specified type.</returns>
|
||||
bool CanRefreshPrimary(Type type);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -131,6 +131,24 @@ namespace MediaBrowser.Controller.Providers
|
||||
/// <returns>IEnumerable{ImageProviderInfo}.</returns>
|
||||
IEnumerable<ImageProviderInfo> GetRemoteImageProviderInfo(BaseItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the image providers for the provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="refreshOptions">The image refresh options.</param>
|
||||
/// <returns>The image providers for the item.</returns>
|
||||
IEnumerable<IImageProvider> GetImageProviders(BaseItem item, ImageRefreshOptions refreshOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the metadata providers for the provided item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <typeparam name="T">The type of metadata provider.</typeparam>
|
||||
/// <returns>The metadata providers.</returns>
|
||||
IEnumerable<IMetadataProvider<T>> GetMetadataProviders<T>(BaseItem item, LibraryOptions libraryOptions)
|
||||
where T : BaseItem;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all metadata plugins.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -8,20 +6,41 @@ using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IRemoteMetadataProvider.
|
||||
/// </summary>
|
||||
public interface IRemoteMetadataProvider : IMetadataProvider
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface IRemoteMetadataProvider.
|
||||
/// </summary>
|
||||
public interface IRemoteMetadataProvider<TItemType, in TLookupInfoType> : IMetadataProvider<TItemType>, IRemoteMetadataProvider, IRemoteSearchProvider<TLookupInfoType>
|
||||
where TItemType : BaseItem, IHasLookupInfo<TLookupInfoType>
|
||||
where TLookupInfoType : ItemLookupInfo, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the metadata for a specific LookupInfoType.
|
||||
/// </summary>
|
||||
/// <param name="info">The LookupInfoType to get metadata for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
||||
/// <returns>A task returning a MetadataResult for the specific LookupInfoType.</returns>
|
||||
Task<MetadataResult<TItemType>> GetMetadata(TLookupInfoType info, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface IRemoteMetadataProvider.
|
||||
/// </summary>
|
||||
public interface IRemoteSearchProvider<in TLookupInfoType> : IRemoteSearchProvider
|
||||
where TLookupInfoType : ItemLookupInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="RemoteSearchResult"/> for a specific LookupInfoType.
|
||||
/// </summary>
|
||||
/// <param name="searchInfo">The LookupInfoType to search for.</param>
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
|
||||
/// <returns>A task returning RemoteSearchResults for the searchInfo.</returns>
|
||||
Task<IEnumerable<RemoteSearchResult>> GetSearchResults(TLookupInfoType searchInfo, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>`0.</returns>
|
||||
public virtual T Resolve(ItemResolveArgs args)
|
||||
protected internal virtual T Resolve(ItemResolveArgs args)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>BaseItem.</returns>
|
||||
BaseItem IItemResolver.ResolvePath(ItemResolveArgs args)
|
||||
public BaseItem ResolvePath(ItemResolveArgs args)
|
||||
{
|
||||
var item = Resolve(args);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user