mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-04 06:48:35 +01:00
Merge branch 'master' into network-rewrite
This commit is contained in:
@@ -15,12 +15,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>
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#nullable disable
|
||||
#pragma warning disable CA1002
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -28,7 +27,7 @@ namespace MediaBrowser.Controller.Dto
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <returns>BaseItemDto.</returns>
|
||||
BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User user = null, BaseItem owner = null);
|
||||
BaseItemDto GetBaseItemDto(BaseItem item, DtoOptions options, User? user = null, BaseItem? owner = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the base item dtos.
|
||||
@@ -38,7 +37,7 @@ namespace MediaBrowser.Controller.Dto
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <returns>The <see cref="IReadOnlyList{T}"/> of <see cref="BaseItemDto"/>.</returns>
|
||||
IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
|
||||
IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User? user = null, BaseItem? owner = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item by name dto.
|
||||
@@ -48,6 +47,6 @@ namespace MediaBrowser.Controller.Dto
|
||||
/// <param name="taggedItems">The list of tagged items.</param>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>The item dto.</returns>
|
||||
BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, User user = null);
|
||||
BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem>? taggedItems, User? user = null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1607,6 +1607,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
var allowedTagsPreference = user.GetPreference(PreferenceKind.AllowedTags);
|
||||
if (allowedTagsPreference.Any() && !allowedTagsPreference.Any(i => Tags.Contains(i, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
EnableTotalRecordCount = true;
|
||||
ExcludeArtistIds = Array.Empty<Guid>();
|
||||
ExcludeInheritedTags = Array.Empty<string>();
|
||||
IncludeInheritedTags = Array.Empty<string>();
|
||||
ExcludeItemIds = Array.Empty<Guid>();
|
||||
ExcludeItemTypes = Array.Empty<BaseItemKind>();
|
||||
ExcludeTags = Array.Empty<string>();
|
||||
@@ -95,6 +96,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public string[] ExcludeInheritedTags { get; set; }
|
||||
|
||||
public string[] IncludeInheritedTags { get; set; }
|
||||
|
||||
public IReadOnlyList<string> Genres { get; set; }
|
||||
|
||||
public bool? IsSpecialSeason { get; set; }
|
||||
@@ -368,6 +371,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
|
||||
IncludeInheritedTags = user.GetPreference(PreferenceKind.AllowedTags);
|
||||
|
||||
User = user;
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
|
||||
public override bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
|
||||
{
|
||||
return true;
|
||||
return user.HasPermission(PermissionKind.IsAdministrator) || user.HasPermission(PermissionKind.EnableCollectionManagement);
|
||||
}
|
||||
|
||||
public override bool IsSaveLocalMetadataEnabled()
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -47,14 +45,14 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="id">The id.</param>
|
||||
/// <returns>The user with the specified Id, or <c>null</c> if the user doesn't exist.</returns>
|
||||
/// <exception cref="ArgumentException"><c>id</c> is an empty Guid.</exception>
|
||||
User GetUserById(Guid id);
|
||||
User? GetUserById(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the user by.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>User.</returns>
|
||||
User GetUserByName(string name);
|
||||
User? GetUserByName(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Renames the user.
|
||||
@@ -128,7 +126,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="remoteEndPoint">The remote end point.</param>
|
||||
/// <returns>UserDto.</returns>
|
||||
UserDto GetUserDto(User user, string remoteEndPoint = null);
|
||||
UserDto GetUserDto(User user, string? remoteEndPoint = null);
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates the user.
|
||||
@@ -139,7 +137,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="remoteEndPoint">Remove endpoint to use.</param>
|
||||
/// <param name="isUserSession">Specifies if a user session.</param>
|
||||
/// <returns>User wrapped in awaitable task.</returns>
|
||||
Task<User> AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession);
|
||||
Task<User?> AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the forgot password process.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -9,7 +7,7 @@ namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
public static class LibraryManagerExtensions
|
||||
{
|
||||
public static BaseItem GetItemById(this ILibraryManager manager, string id)
|
||||
public static BaseItem? GetItemById(this ILibraryManager manager, string id)
|
||||
{
|
||||
return manager.GetItemById(new Guid(id));
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -61,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,
|
||||
@@ -549,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"))
|
||||
{
|
||||
@@ -2804,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;
|
||||
}
|
||||
@@ -4440,6 +4463,75 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return (mainFilters, subFilters, overlayFilters);
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@@ -4482,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);
|
||||
@@ -5762,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
|
||||
@@ -5781,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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,6 @@ namespace MediaBrowser.Controller.Subtitles
|
||||
/// </summary>
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user