mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-03-16 23:26:22 +00:00
Merge branch 'master' into trickplay
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Threading.Tasks;
|
||||
@@ -23,7 +21,7 @@ namespace MediaBrowser.Controller.Authentication
|
||||
|
||||
public interface IRequiresResolvedUser
|
||||
{
|
||||
Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser);
|
||||
Task<ProviderAuthenticationResult> Authenticate(string username, string password, User? resolvedUser);
|
||||
}
|
||||
|
||||
public interface IHasNewUserPolicy
|
||||
@@ -33,8 +31,8 @@ namespace MediaBrowser.Controller.Authentication
|
||||
|
||||
public class ProviderAuthenticationResult
|
||||
{
|
||||
public string Username { get; set; }
|
||||
public required string Username { get; set; }
|
||||
|
||||
public string DisplayName { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
||||
|
||||
@@ -23,9 +23,12 @@ namespace MediaBrowser.Controller.ClientEvent
|
||||
{
|
||||
var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log";
|
||||
var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName);
|
||||
await using var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
return fileName;
|
||||
var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
|
||||
await using (fileStream.ConfigureAwait(false))
|
||||
{
|
||||
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@@ -66,18 +65,10 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <returns>Guid.</returns>
|
||||
string GetImageCacheTag(BaseItem item, ItemImageInfo image);
|
||||
|
||||
string GetImageCacheTag(BaseItem item, ChapterInfo chapter);
|
||||
string? GetImageCacheTag(BaseItem item, ChapterInfo chapter);
|
||||
|
||||
string? GetImageCacheTag(User user);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the image.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="toStream">To stream.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ProcessImage(ImageProcessingOptions options, Stream toStream);
|
||||
|
||||
/// <summary>
|
||||
/// Processes the image.
|
||||
/// </summary>
|
||||
@@ -97,7 +88,5 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="libraryName">The library name to draw onto the collage.</param>
|
||||
void CreateImageCollage(ImageCollageOptions options, string? libraryName);
|
||||
|
||||
bool SupportsTransparency(string path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,8 @@ namespace MediaBrowser.Controller.Drawing
|
||||
private bool IsFormatSupported(string originalImagePath)
|
||||
{
|
||||
var ext = Path.GetExtension(originalImagePath);
|
||||
return SupportedOutputFormats.Any(outputFormat => string.Equals(ext, "." + outputFormat, StringComparison.OrdinalIgnoreCase));
|
||||
ext = ext.Replace(".jpeg", ".jpg", StringComparison.OrdinalIgnoreCase);
|
||||
return SupportedOutputFormats.Any(outputFormat => string.Equals(ext, outputFormat.GetExtension(), StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@@ -9,12 +7,12 @@ namespace MediaBrowser.Controller.Drawing
|
||||
{
|
||||
public static class ImageProcessorExtensions
|
||||
{
|
||||
public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType)
|
||||
public static string? GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType)
|
||||
{
|
||||
return processor.GetImageCacheTag(item, imageType, 0);
|
||||
}
|
||||
|
||||
public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType, int imageIndex)
|
||||
public static string? GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType, int imageIndex)
|
||||
{
|
||||
var imageInfo = item.GetImageInfo(imageType, imageIndex);
|
||||
|
||||
|
||||
@@ -183,6 +183,9 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
progress.Report(percent * 95);
|
||||
}
|
||||
|
||||
// get album LUFS
|
||||
LUFS = items.OfType<Audio>().Max(item => item.LUFS);
|
||||
|
||||
var parentRefreshOptions = refreshOptions;
|
||||
if (childUpdateType > ItemUpdateType.None)
|
||||
{
|
||||
|
||||
@@ -1864,7 +1864,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <exception cref="ArgumentException">Backdrops should be accessed using Item.Backdrops.</exception>
|
||||
public bool HasImage(ImageType type, int imageIndex)
|
||||
{
|
||||
return GetImageInfo(type, imageIndex) != null;
|
||||
return GetImageInfo(type, imageIndex) is not null;
|
||||
}
|
||||
|
||||
public void SetImage(ItemImageInfo image, int index)
|
||||
|
||||
@@ -95,10 +95,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
var p = destProps.Find(x => x.Name == sourceProp.Name);
|
||||
if (p is not null)
|
||||
{
|
||||
p.SetValue(dest, v);
|
||||
}
|
||||
p?.SetValue(dest, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -29,7 +30,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public class CollectionFolder : Folder, ICollectionFolder
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
private static readonly Dictionary<string, LibraryOptions> _libraryOptions = new Dictionary<string, LibraryOptions>();
|
||||
private static readonly ConcurrentDictionary<string, LibraryOptions> _libraryOptions = new ConcurrentDictionary<string, LibraryOptions>();
|
||||
private bool _requiresRefresh;
|
||||
|
||||
/// <summary>
|
||||
@@ -139,45 +140,26 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
public static LibraryOptions GetLibraryOptions(string path)
|
||||
{
|
||||
lock (_libraryOptions)
|
||||
{
|
||||
if (!_libraryOptions.TryGetValue(path, out var options))
|
||||
{
|
||||
options = LoadLibraryOptions(path);
|
||||
_libraryOptions[path] = options;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
=> _libraryOptions.GetOrAdd(path, LoadLibraryOptions);
|
||||
|
||||
public static void SaveLibraryOptions(string path, LibraryOptions options)
|
||||
{
|
||||
lock (_libraryOptions)
|
||||
_libraryOptions[path] = options;
|
||||
|
||||
var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
|
||||
foreach (var mediaPath in clone.PathInfos)
|
||||
{
|
||||
_libraryOptions[path] = options;
|
||||
|
||||
var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
|
||||
foreach (var mediaPath in clone.PathInfos)
|
||||
if (!string.IsNullOrEmpty(mediaPath.Path))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(mediaPath.Path))
|
||||
{
|
||||
mediaPath.Path = ApplicationHost.ReverseVirtualPath(mediaPath.Path);
|
||||
}
|
||||
mediaPath.Path = ApplicationHost.ReverseVirtualPath(mediaPath.Path);
|
||||
}
|
||||
|
||||
XmlSerializer.SerializeToFile(clone, GetLibraryOptionsPath(path));
|
||||
}
|
||||
|
||||
XmlSerializer.SerializeToFile(clone, GetLibraryOptionsPath(path));
|
||||
}
|
||||
|
||||
public static void OnCollectionFolderChange()
|
||||
{
|
||||
lock (_libraryOptions)
|
||||
{
|
||||
_libraryOptions.Clear();
|
||||
}
|
||||
}
|
||||
=> _libraryOptions.Clear();
|
||||
|
||||
public override bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
|
||||
@@ -598,7 +598,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
for (var i = 0; i < childrenCount; i++)
|
||||
{
|
||||
await actionBlock.SendAsync(i).ConfigureAwait(false);
|
||||
await actionBlock.SendAsync(i, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
actionBlock.Complete();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -14,7 +12,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the path.
|
||||
/// </summary>
|
||||
/// <value>The path.</value>
|
||||
public string Path { get; set; }
|
||||
public required string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type.
|
||||
@@ -36,9 +34,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Gets or sets the blurhash.
|
||||
/// </summary>
|
||||
/// <value>The blurhash.</value>
|
||||
public string BlurHash { get; set; }
|
||||
public string? BlurHash { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsLocalFile => Path is null || !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase);
|
||||
public bool IsLocalFile => !Path.StartsWith("http", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsInSeasonFolder => FindParent<Season>() != null;
|
||||
public bool IsInSeasonFolder => FindParent<Season>() is not null;
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPresentationUniqueKey { get; set; }
|
||||
|
||||
@@ -333,7 +333,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
protected override bool IsActiveRecording()
|
||||
{
|
||||
return LiveTvManager.GetActiveRecordingInfo(Path) != null;
|
||||
return LiveTvManager.GetActiveRecordingInfo(Path) is not null;
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Events.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// A class representing an authentication result event.
|
||||
/// </summary>
|
||||
public class AuthenticationRequestEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationRequestEventArgs"/> class.
|
||||
/// </summary>
|
||||
/// <param name="request">The <see cref="AuthenticationRequest"/>.</param>
|
||||
public AuthenticationRequestEventArgs(AuthenticationRequest request)
|
||||
{
|
||||
Username = request.Username;
|
||||
UserId = request.UserId;
|
||||
App = request.App;
|
||||
AppVersion = request.AppVersion;
|
||||
DeviceId = request.DeviceId;
|
||||
DeviceName = request.DeviceName;
|
||||
RemoteEndPoint = request.RemoteEndPoint;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user name.
|
||||
/// </summary>
|
||||
public string? Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the app.
|
||||
/// </summary>
|
||||
public string? App { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the app version.
|
||||
/// </summary>
|
||||
public string? AppVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device id.
|
||||
/// </summary>
|
||||
public string? DeviceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the device name.
|
||||
/// </summary>
|
||||
public string? DeviceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote endpoint.
|
||||
/// </summary>
|
||||
public string? RemoteEndPoint { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Controller.Events.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// A class representing an authentication result event.
|
||||
/// </summary>
|
||||
public class AuthenticationResultEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthenticationResultEventArgs"/> class.
|
||||
/// </summary>
|
||||
/// <param name="result">The <see cref="AuthenticationResult"/>.</param>
|
||||
public AuthenticationResultEventArgs(AuthenticationResult result)
|
||||
{
|
||||
User = result.User;
|
||||
SessionInfo = result.SessionInfo;
|
||||
ServerId = result.ServerId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
public UserDto User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the session information.
|
||||
/// </summary>
|
||||
public SessionInfo? SessionInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server id.
|
||||
/// </summary>
|
||||
public string? ServerId { get; set; }
|
||||
}
|
||||
193
MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs
Normal file
193
MediaBrowser.Controller/Extensions/XmlReaderExtensions.cs
Normal file
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods for <see cref="XmlReader"/> to parse <see cref="BaseItem"/>'s.
|
||||
/// </summary>
|
||||
public static class XmlReaderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads a trimmed string from the current node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <returns>The trimmed content.</returns>
|
||||
public static string ReadNormalizedString(this XmlReader reader)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
|
||||
return reader.ReadElementContentAsString().Trim();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an int from the current node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <param name="value">The parsed <c>int</c>.</param>
|
||||
/// <returns>A value indicating whether the parsing succeeded.</returns>
|
||||
public static bool TryReadInt(this XmlReader reader, out int value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
|
||||
return int.TryParse(reader.ReadElementContentAsString(), CultureInfo.InvariantCulture, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="DateTime"/> from the current node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <param name="value">The parsed <see cref="DateTime"/>.</param>
|
||||
/// <returns>A value indicating whether the parsing succeeded.</returns>
|
||||
public static bool TryReadDateTime(this XmlReader reader, out DateTime value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
|
||||
return DateTime.TryParse(
|
||||
reader.ReadElementContentAsString(),
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
|
||||
out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="DateTime"/> from the current node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <param name="formatString">The date format string.</param>
|
||||
/// <param name="value">The parsed <see cref="DateTime"/>.</param>
|
||||
/// <returns>A value indicating whether the parsing succeeded.</returns>
|
||||
public static bool TryReadDateTimeExact(this XmlReader reader, string formatString, out DateTime value)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
ArgumentNullException.ThrowIfNull(formatString);
|
||||
|
||||
return DateTime.TryParseExact(
|
||||
reader.ReadElementContentAsString(),
|
||||
formatString,
|
||||
CultureInfo.InvariantCulture,
|
||||
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
|
||||
out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="PersonInfo"/> from the xml node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <returns>A <see cref="PersonInfo"/>, or <c>null</c> if none is found.</returns>
|
||||
public static PersonInfo? GetPersonFromXmlNode(this XmlReader reader)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
|
||||
if (reader.IsEmptyElement)
|
||||
{
|
||||
reader.Read();
|
||||
return null;
|
||||
}
|
||||
|
||||
var name = string.Empty;
|
||||
var type = PersonKind.Actor; // If type is not specified assume actor
|
||||
var role = string.Empty;
|
||||
int? sortOrder = null;
|
||||
string? imageUrl = null;
|
||||
|
||||
using var subtree = reader.ReadSubtree();
|
||||
subtree.MoveToContent();
|
||||
subtree.Read();
|
||||
|
||||
while (subtree is { EOF: false, ReadState: ReadState.Interactive })
|
||||
{
|
||||
if (subtree.NodeType != XmlNodeType.Element)
|
||||
{
|
||||
subtree.Read();
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (subtree.Name)
|
||||
{
|
||||
case "name":
|
||||
case "Name":
|
||||
name = subtree.ReadNormalizedString();
|
||||
break;
|
||||
case "role":
|
||||
case "Role":
|
||||
role = subtree.ReadNormalizedString();
|
||||
break;
|
||||
case "type":
|
||||
case "Type":
|
||||
Enum.TryParse(subtree.ReadElementContentAsString(), true, out type);
|
||||
break;
|
||||
case "order":
|
||||
case "sortorder":
|
||||
case "SortOrder":
|
||||
if (subtree.TryReadInt(out var sortOrderVal))
|
||||
{
|
||||
sortOrder = sortOrderVal;
|
||||
}
|
||||
|
||||
break;
|
||||
case "thumb":
|
||||
imageUrl = subtree.ReadNormalizedString();
|
||||
break;
|
||||
default:
|
||||
subtree.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PersonInfo
|
||||
{
|
||||
Name = name,
|
||||
Role = role,
|
||||
Type = type,
|
||||
SortOrder = sortOrder,
|
||||
ImageUrl = imageUrl
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to split names of comma or pipe delimited genres and people.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
public static IEnumerable<string> GetStringArray(this XmlReader reader)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(reader);
|
||||
var value = reader.ReadElementContentAsString();
|
||||
|
||||
// Only split by comma if there is no pipe in the string
|
||||
// We have to be careful to not split names like Matthew, Jr.
|
||||
var separator = !value.Contains('|', StringComparison.Ordinal)
|
||||
&& !value.Contains(';', StringComparison.Ordinal)
|
||||
? new[] { ',' }
|
||||
: new[] { '|', ';' };
|
||||
|
||||
foreach (var part in value.Trim().Trim(separator).Split(separator))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(part))
|
||||
{
|
||||
yield return part.Trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses a <see cref="PersonInfo"/> array from the xml node.
|
||||
/// </summary>
|
||||
/// <param name="reader">The <see cref="XmlReader"/>.</param>
|
||||
/// <param name="personKind">The <see cref="PersonKind"/>.</param>
|
||||
/// <returns>The <see cref="IEnumerable{PersonInfo}"/>.</returns>
|
||||
public static IEnumerable<PersonInfo> GetPersonArray(this XmlReader reader, PersonKind personKind)
|
||||
=> reader.GetStringArray()
|
||||
.Select(part => new PersonInfo { Name = part, Type = personKind });
|
||||
}
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
using System.Net;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Controller
|
||||
@@ -17,8 +15,6 @@ namespace MediaBrowser.Controller
|
||||
{
|
||||
bool CoreStartupHasCompleted { get; }
|
||||
|
||||
bool CanLaunchWebBrowser { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the HTTP server port.
|
||||
/// </summary>
|
||||
@@ -42,15 +38,6 @@ namespace MediaBrowser.Controller
|
||||
/// <value>The name of the friendly.</value>
|
||||
string FriendlyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system info.
|
||||
/// </summary>
|
||||
/// <param name="request">The HTTP request.</param>
|
||||
/// <returns>SystemInfo.</returns>
|
||||
SystemInfo GetSystemInfo(HttpRequest request);
|
||||
|
||||
PublicSystemInfo GetPublicSystemInfo(HttpRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a URL specific for the request.
|
||||
/// </summary>
|
||||
@@ -75,10 +62,10 @@ namespace MediaBrowser.Controller
|
||||
/// <summary>
|
||||
/// Gets an URL that can be used to access the API over LAN.
|
||||
/// </summary>
|
||||
/// <param name="hostname">An optional hostname to use.</param>
|
||||
/// <param name="ipAddress">An optional IP address to use.</param>
|
||||
/// <param name="allowHttps">A value indicating whether to allow HTTPS.</param>
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true);
|
||||
string GetApiUrlForLocalAccess(IPAddress ipAddress = null, bool allowHttps = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a local (LAN) URL that can be used to access the API.
|
||||
|
||||
34
MediaBrowser.Controller/ISystemManager.cs
Normal file
34
MediaBrowser.Controller/ISystemManager.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using MediaBrowser.Model.System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Controller;
|
||||
|
||||
/// <summary>
|
||||
/// A service for managing the application instance.
|
||||
/// </summary>
|
||||
public interface ISystemManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the system info.
|
||||
/// </summary>
|
||||
/// <param name="request">The HTTP request.</param>
|
||||
/// <returns>The <see cref="SystemInfo"/>.</returns>
|
||||
SystemInfo GetSystemInfo(HttpRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the public system info.
|
||||
/// </summary>
|
||||
/// <param name="request">The HTTP request.</param>
|
||||
/// <returns>The <see cref="PublicSystemInfo"/>.</returns>
|
||||
PublicSystemInfo GetPublicSystemInfo(HttpRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Starts the application restart process.
|
||||
/// </summary>
|
||||
void Restart();
|
||||
|
||||
/// <summary>
|
||||
/// Starts the application shutdown process.
|
||||
/// </summary>
|
||||
void Shutdown();
|
||||
}
|
||||
@@ -217,7 +217,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns><c>true</c> if [contains file system entry by name] [the specified name]; otherwise, <c>false</c>.</returns>
|
||||
public bool ContainsFileSystemEntryByName(string name)
|
||||
{
|
||||
return GetFileSystemEntryByName(name) != null;
|
||||
return GetFileSystemEntryByName(name) is not null;
|
||||
}
|
||||
|
||||
public string GetCollectionType()
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes
|
||||
{
|
||||
private static string EmbyServiceName = "Emby";
|
||||
private const string EmbyServiceName = "Emby";
|
||||
|
||||
public LiveTvProgram()
|
||||
{
|
||||
|
||||
28
MediaBrowser.Controller/Lyrics/ILyricParser.cs
Normal file
28
MediaBrowser.Controller/Lyrics/ILyricParser.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Providers.Lyric;
|
||||
|
||||
namespace MediaBrowser.Controller.Lyrics;
|
||||
|
||||
/// <summary>
|
||||
/// Interface ILyricParser.
|
||||
/// </summary>
|
||||
public interface ILyricParser
|
||||
{
|
||||
/// <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>
|
||||
/// Parses the raw lyrics into a response.
|
||||
/// </summary>
|
||||
/// <param name="lyrics">The raw lyrics content.</param>
|
||||
/// <returns>The parsed lyrics or null if invalid.</returns>
|
||||
LyricResponse? ParseLyrics(LyricFile lyrics);
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
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);
|
||||
}
|
||||
28
MediaBrowser.Controller/Lyrics/LyricFile.cs
Normal file
28
MediaBrowser.Controller/Lyrics/LyricFile.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
namespace MediaBrowser.Providers.Lyric;
|
||||
|
||||
/// <summary>
|
||||
/// The information for a raw lyrics file before parsing.
|
||||
/// </summary>
|
||||
public class LyricFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LyricFile"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="content">The content, must not be empty.</param>
|
||||
public LyricFile(string name, string content)
|
||||
{
|
||||
Name = name;
|
||||
Content = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the lyrics file. This must include the file extension.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contents of the file.
|
||||
/// </summary>
|
||||
public string Content { get; set; }
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
public class EncodingHelper
|
||||
public partial class EncodingHelper
|
||||
{
|
||||
private const string QsvAlias = "qs";
|
||||
private const string VaapiAlias = "va";
|
||||
@@ -37,7 +37,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
private readonly IMediaEncoder _mediaEncoder;
|
||||
private readonly ISubtitleEncoder _subtitleEncoder;
|
||||
private readonly IConfiguration _config;
|
||||
private readonly Version _minKernelVersionAmdVkFmtModifier = new Version(5, 15);
|
||||
private readonly IConfigurationManager _configurationManager;
|
||||
|
||||
// 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);
|
||||
@@ -47,6 +48,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
private readonly Version _minFFmpegHwaUnsafeOutput = new Version(6, 0);
|
||||
private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1, 3);
|
||||
private readonly Version _minFFmpegSvtAv1Params = new Version(5, 1);
|
||||
private readonly Version _minFFmpegVaapiH26xEncA53CcSei = new Version(6, 0);
|
||||
|
||||
private static readonly string[] _videoProfilesH264 = new[]
|
||||
{
|
||||
@@ -119,14 +121,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
IApplicationPaths appPaths,
|
||||
IMediaEncoder mediaEncoder,
|
||||
ISubtitleEncoder subtitleEncoder,
|
||||
IConfiguration config)
|
||||
IConfiguration config,
|
||||
IConfigurationManager configurationManager)
|
||||
{
|
||||
_appPaths = appPaths;
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_subtitleEncoder = subtitleEncoder;
|
||||
_config = config;
|
||||
_configurationManager = configurationManager;
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"\s+")]
|
||||
private static partial Regex WhiteSpaceRegex();
|
||||
|
||||
public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions)
|
||||
=> GetH26xOrAv1Encoder("libx264", "h264", state, encodingOptions);
|
||||
|
||||
@@ -571,25 +578,25 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <returns>System.Nullable{VideoCodecs}.</returns>
|
||||
public string InferVideoCodec(string url)
|
||||
{
|
||||
var ext = Path.GetExtension(url);
|
||||
var ext = Path.GetExtension(url.AsSpan());
|
||||
|
||||
if (string.Equals(ext, ".asf", StringComparison.OrdinalIgnoreCase))
|
||||
if (ext.Equals(".asf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "wmv";
|
||||
}
|
||||
|
||||
if (string.Equals(ext, ".webm", StringComparison.OrdinalIgnoreCase))
|
||||
if (ext.Equals(".webm", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// TODO: this may not always mean VP8, as the codec ages
|
||||
return "vp8";
|
||||
}
|
||||
|
||||
if (string.Equals(ext, ".ogg", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ogv", StringComparison.OrdinalIgnoreCase))
|
||||
if (ext.Equals(".ogg", StringComparison.OrdinalIgnoreCase) || ext.Equals(".ogv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "theora";
|
||||
}
|
||||
|
||||
if (string.Equals(ext, ".m3u8", StringComparison.OrdinalIgnoreCase) || string.Equals(ext, ".ts", StringComparison.OrdinalIgnoreCase))
|
||||
if (ext.Equals(".m3u8", StringComparison.OrdinalIgnoreCase) || ext.Equals(".ts", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "h264";
|
||||
}
|
||||
@@ -918,9 +925,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
else if (_mediaEncoder.IsVaapiDeviceAmd)
|
||||
{
|
||||
// Disable AMD EFC feature since it's still unstable in upstream Mesa.
|
||||
Environment.SetEnvironmentVariable("AMD_DEBUG", "noefc");
|
||||
|
||||
if (IsVulkanFullSupported()
|
||||
&& _mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier
|
||||
&& Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier)
|
||||
&& _mediaEncoder.IsVaapiDeviceSupportVulkanDrmInterop)
|
||||
{
|
||||
args.Append(GetDrmDeviceArgs(options.VaapiDevice, DrmAlias));
|
||||
args.Append(GetVaapiDeviceArgs(null, null, null, DrmAlias, VaapiAlias));
|
||||
@@ -1083,7 +1092,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (state.MediaSource.VideoType == VideoType.Dvd || state.MediaSource.VideoType == VideoType.BluRay)
|
||||
{
|
||||
var tmpConcatPath = Path.Join(options.TranscodingTempPath, state.MediaSource.Id + ".concat");
|
||||
var tmpConcatPath = Path.Join(_configurationManager.GetTranscodePath(), state.MediaSource.Id + ".concat");
|
||||
_mediaEncoder.GenerateConcatConfig(state.MediaSource, tmpConcatPath);
|
||||
arg.Append(" -f concat -safe 0 -i ")
|
||||
.Append(tmpConcatPath);
|
||||
@@ -1101,10 +1110,10 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
&& state.SubtitleStream.IsExternal)
|
||||
{
|
||||
var subtitlePath = state.SubtitleStream.Path;
|
||||
var subtitleExtension = Path.GetExtension(subtitlePath);
|
||||
var subtitleExtension = Path.GetExtension(subtitlePath.AsSpan());
|
||||
|
||||
if (string.Equals(subtitleExtension, ".sub", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(subtitleExtension, ".sup", StringComparison.OrdinalIgnoreCase))
|
||||
if (subtitleExtension.Equals(".sub", StringComparison.OrdinalIgnoreCase)
|
||||
|| subtitleExtension.Equals(".sup", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var idxFile = Path.ChangeExtension(subtitlePath, ".idx");
|
||||
if (File.Exists(idxFile))
|
||||
@@ -1238,6 +1247,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
int bitrate = state.OutputVideoBitrate.Value;
|
||||
|
||||
// Bit rate under 1000k is not allowed in h264_qsv
|
||||
if (string.Equals(videoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
bitrate = Math.Max(bitrate, 1000);
|
||||
}
|
||||
|
||||
// Currently use the same buffer size for all encoders
|
||||
int bufsize = bitrate * 2;
|
||||
|
||||
@@ -1484,6 +1499,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
args += keyFrameArg + gopArg;
|
||||
}
|
||||
|
||||
// global_header produced by AMD HEVC VA-API encoder causes non-playable fMP4 on iOS
|
||||
if (string.Equals(codec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase)
|
||||
&& _mediaEncoder.IsVaapiDeviceAmd)
|
||||
{
|
||||
args += " -flags:v -global_header";
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
@@ -1753,11 +1775,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// Values 0-3, 0 being highest quality but slower
|
||||
var profileScore = 0;
|
||||
|
||||
string crf;
|
||||
var qmin = "0";
|
||||
var qmax = "50";
|
||||
|
||||
crf = "10";
|
||||
var crf = "10";
|
||||
|
||||
if (isVc1)
|
||||
{
|
||||
@@ -1854,7 +1874,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
var profile = state.GetRequestedProfiles(targetVideoCodec).FirstOrDefault() ?? string.Empty;
|
||||
profile = Regex.Replace(profile, @"\s+", string.Empty);
|
||||
profile = WhiteSpaceRegex().Replace(profile, string.Empty);
|
||||
|
||||
// We only transcode to HEVC 8-bit for now, force Main Profile.
|
||||
if (profile.Contains("main10", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -1925,7 +1945,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (!string.IsNullOrEmpty(profile))
|
||||
{
|
||||
if (!string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
|
||||
// Currently there's no profile option in av1_nvenc encoder
|
||||
if (!(string.Equals(videoEncoder, "av1_nvenc", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
param += " -profile:v:0 " + profile;
|
||||
}
|
||||
@@ -2013,6 +2035,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
param += " -svtav1-params:0 rc=1:tune=0:film-grain=0:enable-overlays=1:enable-tf=0";
|
||||
}
|
||||
|
||||
/* Access unit too large: 8192 < 20880 error */
|
||||
if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(videoEncoder, "hevc_vaapi", StringComparison.OrdinalIgnoreCase)) &&
|
||||
_mediaEncoder.EncoderVersion >= _minFFmpegVaapiH26xEncA53CcSei)
|
||||
{
|
||||
param += " -sei -a53_cc";
|
||||
}
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
@@ -2710,7 +2740,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
string args = string.Empty;
|
||||
|
||||
// http://ffmpeg.org/ffmpeg-all.html#toc-Complex-filtergraphs-1
|
||||
if (state.VideoStream != null && videoProcessFilters.Contains("-filter_complex", StringComparison.Ordinal))
|
||||
if (state.VideoStream is not null && videoProcessFilters.Contains("-filter_complex", StringComparison.Ordinal))
|
||||
{
|
||||
int videoStreamIndex = FindIndex(state.MediaSource.MediaStreams, state.VideoStream);
|
||||
|
||||
@@ -2945,7 +2975,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"scale=trunc(min(max(iw\\,ih*a)\\,min({0}\\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\\,ih)\\,min({0}/a\\,{1}))/2)*2",
|
||||
@"scale=trunc(min(max(iw\,ih*a)\,min({0}\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\,ih)\,min({0}/a\,{1}))/2)*2",
|
||||
maxWidthParam,
|
||||
maxHeightParam,
|
||||
scaleVal);
|
||||
@@ -2987,7 +3017,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"scale=trunc(min(max(iw\\,ih*a)\\,{0})/{1})*{1}:trunc(ow/a/2)*2",
|
||||
@"scale=trunc(min(max(iw\,ih*a)\,{0})/{1})*{1}:trunc(ow/a/2)*2",
|
||||
maxWidthParam,
|
||||
scaleVal);
|
||||
}
|
||||
@@ -2999,7 +3029,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
return string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"scale=trunc(oh*a/{1})*{1}:min(max(iw/a\\,ih)\\,{0})",
|
||||
@"scale=trunc(oh*a/{1})*{1}:min(max(iw/a\,ih)\,{0})",
|
||||
maxHeightParam,
|
||||
scaleVal);
|
||||
}
|
||||
@@ -3019,19 +3049,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
switch (threedFormat.Value)
|
||||
{
|
||||
case Video3DFormat.HalfSideBySide:
|
||||
filter = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
filter = @"crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
// hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
|
||||
break;
|
||||
case Video3DFormat.FullSideBySide:
|
||||
filter = "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
filter = @"crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
// fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to requestedWidth.
|
||||
break;
|
||||
case Video3DFormat.HalfTopAndBottom:
|
||||
filter = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
filter = @"crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
// htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth
|
||||
break;
|
||||
case Video3DFormat.FullTopAndBottom:
|
||||
filter = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
filter = @"crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
|
||||
// ftab crop height in half, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth
|
||||
break;
|
||||
default:
|
||||
@@ -3829,12 +3859,6 @@ 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
|
||||
@@ -4225,14 +4249,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// prefered vaapi + vulkan filters pipeline
|
||||
if (_mediaEncoder.IsVaapiDeviceAmd
|
||||
&& isVaapiVkSupported
|
||||
&& _mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier
|
||||
&& Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier)
|
||||
&& _mediaEncoder.IsVaapiDeviceSupportVulkanDrmInterop)
|
||||
{
|
||||
// AMD radeonsi path(Vega/gfx9+, kernel>=5.15), with extra vulkan tonemap and overlay support.
|
||||
// AMD radeonsi path(targeting Polaris/gfx8+), 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.
|
||||
// Intel i965 and Amd legacy driver path, only featuring scale and deinterlace support.
|
||||
return GetVaapiLimitedVidFiltersPrefered(state, options, vidDecoder, vidEncoder);
|
||||
}
|
||||
|
||||
@@ -4504,7 +4527,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// INPUT vaapi surface(vram)
|
||||
if (doVkTonemap || hasSubs)
|
||||
{
|
||||
// map from vaapi to vulkan/drm via interop (Vega/gfx9+).
|
||||
// map from vaapi to vulkan/drm via interop (Polaris/gfx8+).
|
||||
mainFilters.Add("hwmap=derive_device=vulkan");
|
||||
mainFilters.Add("format=vulkan");
|
||||
}
|
||||
@@ -4533,9 +4556,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
if (doVkTonemap && !hasSubs)
|
||||
{
|
||||
// OUTPUT vaapi(nv12) surface(vram)
|
||||
// map from vulkan/drm to vaapi via interop (Vega/gfx9+).
|
||||
mainFilters.Add("hwmap=derive_device=drm");
|
||||
mainFilters.Add("format=drm_prime");
|
||||
// map from vulkan/drm to vaapi via interop (Polaris/gfx8+).
|
||||
mainFilters.Add("hwmap=derive_device=vaapi");
|
||||
mainFilters.Add("format=vaapi");
|
||||
|
||||
@@ -4601,9 +4622,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
else if (isVaapiEncoder)
|
||||
{
|
||||
// OUTPUT vaapi(nv12) surface(vram)
|
||||
// map from vulkan/drm to vaapi via interop (Vega/gfx9+).
|
||||
overlayFilters.Add("hwmap=derive_device=drm");
|
||||
overlayFilters.Add("format=drm_prime");
|
||||
// map from vulkan/drm to vaapi via interop (Polaris/gfx8+).
|
||||
overlayFilters.Add("hwmap=derive_device=vaapi");
|
||||
overlayFilters.Add("format=vaapi");
|
||||
|
||||
@@ -5273,10 +5292,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (isD3d11Supported && isCodecAvailable)
|
||||
{
|
||||
// set -threads 3 to intel d3d11va decoder explicitly. Lower threads may result in dead lock.
|
||||
// on newer devices such as Xe, the larger the init_pool_size, the longer the initialization time for opencl to derive from d3d11.
|
||||
return " -hwaccel d3d11va" + (outputHwSurface ? " -hwaccel_output_format d3d11" : string.Empty)
|
||||
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + " -threads 3" + (isAv1 ? " -c:v av1" : string.Empty);
|
||||
+ (profileMismatch ? " -hwaccel_flags +allow_profile_mismatch" : string.Empty) + " -threads 2" + (isAv1 ? " -c:v av1" : string.Empty);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -5710,7 +5727,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
// Apply -analyzeduration as per the environment variable,
|
||||
// otherwise ffmpeg will break on certain files due to default value is 0.
|
||||
// The default value of -probesize is more than enough, so leave it as is.
|
||||
var ffmpegAnalyzeDuration = _config.GetFFmpegAnalyzeDuration() ?? string.Empty;
|
||||
|
||||
if (state.MediaSource.AnalyzeDurationMs > 0)
|
||||
@@ -5729,6 +5745,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
inputModifier = inputModifier.Trim();
|
||||
|
||||
// Apply -probesize if configured
|
||||
var ffmpegProbeSize = _config.GetFFmpegProbeSize();
|
||||
|
||||
if (!string.IsNullOrEmpty(ffmpegProbeSize))
|
||||
{
|
||||
inputModifier += $" -probesize {ffmpegProbeSize}";
|
||||
}
|
||||
|
||||
var userAgentParam = GetUserAgentParam(state);
|
||||
|
||||
if (!string.IsNullOrEmpty(userAgentParam))
|
||||
@@ -6053,7 +6077,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var format = string.Empty;
|
||||
var keyFrame = string.Empty;
|
||||
|
||||
if (string.Equals(Path.GetExtension(outputPath), ".mp4", StringComparison.OrdinalIgnoreCase)
|
||||
if (Path.GetExtension(outputPath.AsSpan()).Equals(".mp4", StringComparison.OrdinalIgnoreCase)
|
||||
&& state.BaseRequest.Context == EncodingContext.Streaming)
|
||||
{
|
||||
// Comparison: https://github.com/jansmolders86/mediacenterjs/blob/master/lib/transcoding/desktop.js
|
||||
@@ -6262,6 +6286,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state));
|
||||
}
|
||||
|
||||
if (GetAudioEncoder(state).StartsWith("pcm_", StringComparison.Ordinal))
|
||||
{
|
||||
audioTranscodeParams.Add(string.Concat("-f ", GetAudioEncoder(state).AsSpan(4)));
|
||||
audioTranscodeParams.Add("-ar " + state.BaseRequest.AudioBitRate);
|
||||
}
|
||||
|
||||
if (!string.Equals(outputCodec, "opus", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// opus only supports specific sampling rates
|
||||
|
||||
@@ -66,8 +66,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <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; }
|
||||
/// <value><c>true</c> if the Vaapi device supports vulkan drm interop, <c>false</c> otherwise.</value>
|
||||
bool IsVaapiDeviceSupportVulkanDrmInterop { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether given encoder codec is supported.
|
||||
|
||||
@@ -20,12 +20,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task StartStreamingLog(EncodingJobInfo state, Stream source, Stream target)
|
||||
public async Task StartStreamingLog(EncodingJobInfo state, StreamReader reader, Stream target)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (target)
|
||||
using (var reader = new StreamReader(source))
|
||||
using (reader)
|
||||
{
|
||||
while (!reader.EndOfStream && reader.BaseStream.CanRead)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
using MediaBrowser.Model.Session;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
protected ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger;
|
||||
protected readonly ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger;
|
||||
|
||||
protected BasePeriodicWebSocketListener(ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> logger)
|
||||
{
|
||||
@@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Net
|
||||
/// Starts sending messages over a web socket.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
private void Start(WebSocketMessageInfo message)
|
||||
protected virtual void Start(WebSocketMessageInfo message)
|
||||
{
|
||||
var vals = message.Data.Split(',');
|
||||
|
||||
@@ -169,9 +169,8 @@ namespace MediaBrowser.Controller.Net
|
||||
if (data is not null)
|
||||
{
|
||||
await connection.SendAsync(
|
||||
new WebSocketMessage<TReturnDataType>
|
||||
new OutboundWebSocketMessage<TReturnDataType>
|
||||
{
|
||||
MessageId = Guid.NewGuid(),
|
||||
MessageType = Type,
|
||||
Data = data
|
||||
},
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for WebSocket connections.
|
||||
/// </summary>
|
||||
public interface IWebSocketConnection : IAsyncDisposable, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
@@ -40,12 +41,26 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <value>The state.</value>
|
||||
WebSocketState State { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authorization information.
|
||||
/// </summary>
|
||||
public AuthorizationInfo AuthorizationInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the remote end point.
|
||||
/// </summary>
|
||||
/// <value>The remote end point.</value>
|
||||
IPAddress? RemoteEndPoint { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">The message is null.</exception>
|
||||
Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
/// </summary>
|
||||
@@ -54,8 +69,13 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">The message is null.</exception>
|
||||
Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken);
|
||||
Task SendAsync<T>(OutboundWebSocketMessage<T> message, CancellationToken cancellationToken);
|
||||
|
||||
Task ProcessAsync(CancellationToken cancellationToken = default);
|
||||
/// <summary>
|
||||
/// Receives a message asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ReceiveAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
@@ -15,11 +14,6 @@ public abstract class WebSocketMessage
|
||||
/// </summary>
|
||||
public virtual SessionMessageType MessageType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message id.
|
||||
/// </summary>
|
||||
public Guid MessageId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server id.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#nullable disable
|
||||
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
/// <summary>
|
||||
/// Class WebSocketMessageInfo.
|
||||
/// </summary>
|
||||
public class WebSocketMessageInfo : WebSocketMessage<string>
|
||||
public class WebSocketMessageInfo : InboundWebSocketMessage<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the connection.
|
||||
|
||||
@@ -6,13 +6,12 @@ namespace MediaBrowser.Controller.Net;
|
||||
/// Class WebSocketMessage.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data.</typeparam>
|
||||
// TODO make this abstract, remove empty ctor.
|
||||
public class WebSocketMessage<T> : WebSocketMessage
|
||||
public abstract class WebSocketMessage<T> : WebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebSocketMessage{T}"/> class.
|
||||
/// </summary>
|
||||
public WebSocketMessage()
|
||||
protected WebSocketMessage()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
|
||||
/// <summary>
|
||||
/// Activity log entry start message.
|
||||
/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
|
||||
/// </summary>
|
||||
public class ActivityLogEntryStartMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage
|
||||
public class ActivityLogEntryStartMessage : InboundWebSocketMessage<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityLogEntryStartMessage"/> class.
|
||||
/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
|
||||
/// </summary>
|
||||
/// <param name="data">Collection of activity log entries.</param>
|
||||
public ActivityLogEntryStartMessage(IReadOnlyCollection<ActivityLogEntry> data)
|
||||
/// <param name="data">The timing data encoded as "$initialDelay,$interval".</param>
|
||||
public ActivityLogEntryStartMessage(string data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
@@ -8,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
/// <summary>
|
||||
/// Activity log entry stop message.
|
||||
/// </summary>
|
||||
public class ActivityLogEntryStopMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage
|
||||
public class ActivityLogEntryStopMessage : InboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityLogEntryStopMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Collection of activity log entries.</param>
|
||||
public ActivityLogEntryStopMessage(IReadOnlyCollection<ActivityLogEntry> data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.ActivityLogEntryStop)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.ActivityLogEntryStop;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
|
||||
/// <summary>
|
||||
/// Keep alive websocket messages.
|
||||
/// </summary>
|
||||
public class InboundKeepAliveMessage : InboundWebSocketMessage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.KeepAlive)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
|
||||
/// <summary>
|
||||
/// Scheduled tasks info start message.
|
||||
/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
|
||||
/// </summary>
|
||||
public class ScheduledTasksInfoStartMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage
|
||||
public class ScheduledTasksInfoStartMessage : InboundWebSocketMessage<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTasksInfoStartMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Collection of task info.</param>
|
||||
public ScheduledTasksInfoStartMessage(IReadOnlyCollection<TaskInfo> data)
|
||||
/// <param name="data">The timing data encoded as $initialDelay,$interval.</param>
|
||||
public ScheduledTasksInfoStartMessage(string data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,24 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
|
||||
/// <summary>
|
||||
/// Scheduled tasks info stop message.
|
||||
/// </summary>
|
||||
public class ScheduledTasksInfoStopMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage
|
||||
public class ScheduledTasksInfoStopMessage : InboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTasksInfoStopMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Collection of task info.</param>
|
||||
public ScheduledTasksInfoStopMessage(IReadOnlyCollection<TaskInfo> data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.ScheduledTasksInfoStop)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.ScheduledTasksInfoStop;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
|
||||
/// <summary>
|
||||
/// Sessions start message.
|
||||
/// Data is the timing data encoded as "$initialDelay,$interval" in ms.
|
||||
/// </summary>
|
||||
public class SessionsStartMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage
|
||||
public class SessionsStartMessage : InboundWebSocketMessage<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionsStartMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Session info.</param>
|
||||
public SessionsStartMessage(SessionInfo data)
|
||||
/// <param name="data">The timing data encoded as $initialDelay,$interval.</param>
|
||||
public SessionsStartMessage(string data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
@@ -7,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound;
|
||||
/// <summary>
|
||||
/// Sessions stop message.
|
||||
/// </summary>
|
||||
public class SessionsStopMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage
|
||||
public class SessionsStopMessage : InboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionsStopMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Session info.</param>
|
||||
public SessionsStopMessage(SessionInfo data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.SessionsStop)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.SessionsStop;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Class representing the list of outbound websocket message types.
|
||||
/// Only used in openapi generation.
|
||||
/// Inbound websocket message.
|
||||
/// </summary>
|
||||
public class InboundWebSocketMessage : WebSocketMessage
|
||||
public class InboundWebSocketMessage : WebSocketMessage, IInboundWebSocketMessage
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma warning disable SA1649 // File name must equal class name.
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Inbound websocket message with data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data type.</typeparam>
|
||||
public class InboundWebSocketMessage<T> : WebSocketMessage<T>, IInboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class.
|
||||
/// </summary>
|
||||
public InboundWebSocketMessage()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to send.</param>
|
||||
protected InboundWebSocketMessage(T data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Activity log created message.
|
||||
/// </summary>
|
||||
public class ActivityLogEntryMessage : WebSocketMessage<IReadOnlyList<ActivityLogEntry>>, IOutboundWebSocketMessage
|
||||
public class ActivityLogEntryMessage : OutboundWebSocketMessage<IReadOnlyList<ActivityLogEntry>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ActivityLogEntryMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Force keep alive websocket messages.
|
||||
/// </summary>
|
||||
public class ForceKeepAliveMessage : WebSocketMessage<int>, IOutboundWebSocketMessage
|
||||
public class ForceKeepAliveMessage : OutboundWebSocketMessage<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ForceKeepAliveMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// General command websocket message.
|
||||
/// </summary>
|
||||
public class GeneralCommandMessage : WebSocketMessage<GeneralCommand>, IOutboundWebSocketMessage
|
||||
public class GeneralCommandMessage : OutboundWebSocketMessage<GeneralCommand>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GeneralCommandMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Library changed message.
|
||||
/// </summary>
|
||||
public class LibraryChangedMessage : WebSocketMessage<LibraryUpdateInfo>, IOutboundWebSocketMessage
|
||||
public class LibraryChangedMessage : OutboundWebSocketMessage<LibraryUpdateInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LibraryChangedMessage"/> class.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
|
||||
/// <summary>
|
||||
/// Keep alive websocket messages.
|
||||
/// </summary>
|
||||
public class OutboundKeepAliveMessage : OutboundWebSocketMessage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.KeepAlive)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Play command websocket message.
|
||||
/// </summary>
|
||||
public class PlayMessage : WebSocketMessage<PlayRequest>, IOutboundWebSocketMessage
|
||||
public class PlayMessage : OutboundWebSocketMessage<PlayRequest>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlayMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Playstate message.
|
||||
/// </summary>
|
||||
public class PlaystateMessage : WebSocketMessage<PlaystateRequest>, IOutboundWebSocketMessage
|
||||
public class PlaystateMessage : OutboundWebSocketMessage<PlaystateRequest>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PlaystateMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Plugin installation cancelled message.
|
||||
/// </summary>
|
||||
public class PluginInstallationCancelledMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
|
||||
public class PluginInstallationCancelledMessage : OutboundWebSocketMessage<InstallationInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationCancelledMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Plugin installation completed message.
|
||||
/// </summary>
|
||||
public class PluginInstallationCompletedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
|
||||
public class PluginInstallationCompletedMessage : OutboundWebSocketMessage<InstallationInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationCompletedMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Plugin installation failed message.
|
||||
/// </summary>
|
||||
public class PluginInstallationFailedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
|
||||
public class PluginInstallationFailedMessage : OutboundWebSocketMessage<InstallationInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallationFailedMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Package installing message.
|
||||
/// </summary>
|
||||
public class PluginInstallingMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage
|
||||
public class PluginInstallingMessage : OutboundWebSocketMessage<InstallationInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginInstallingMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Plugin uninstalled message.
|
||||
/// </summary>
|
||||
public class PluginUninstalledMessage : WebSocketMessage<PluginInfo>, IOutboundWebSocketMessage
|
||||
public class PluginUninstalledMessage : OutboundWebSocketMessage<PluginInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PluginUninstalledMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Refresh progress message.
|
||||
/// </summary>
|
||||
public class RefreshProgressMessage : WebSocketMessage<Dictionary<string, string>>, IOutboundWebSocketMessage
|
||||
public class RefreshProgressMessage : OutboundWebSocketMessage<Dictionary<string, string>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RefreshProgressMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Restart required.
|
||||
/// </summary>
|
||||
public class RestartRequiredMessage : WebSocketMessage, IOutboundWebSocketMessage
|
||||
public class RestartRequiredMessage : OutboundWebSocketMessage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.RestartRequired)]
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Scheduled task ended message.
|
||||
/// </summary>
|
||||
public class ScheduledTaskEndedMessage : WebSocketMessage<TaskResult>, IOutboundWebSocketMessage
|
||||
public class ScheduledTaskEndedMessage : OutboundWebSocketMessage<TaskResult>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTaskEndedMessage"/> class.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Scheduled tasks info message.
|
||||
/// </summary>
|
||||
public class ScheduledTasksInfoMessage : WebSocketMessage<IReadOnlyList<TaskInfo>>, IOutboundWebSocketMessage
|
||||
public class ScheduledTasksInfoMessage : OutboundWebSocketMessage<IReadOnlyList<TaskInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledTasksInfoMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Series timer cancelled message.
|
||||
/// </summary>
|
||||
public class SeriesTimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
|
||||
public class SeriesTimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeriesTimerCancelledMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Series timer created message.
|
||||
/// </summary>
|
||||
public class SeriesTimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
|
||||
public class SeriesTimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SeriesTimerCreatedMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Server restarting down message.
|
||||
/// </summary>
|
||||
public class ServerRestartingMessage : WebSocketMessage, IOutboundWebSocketMessage
|
||||
public class ServerRestartingMessage : OutboundWebSocketMessage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.ServerRestarting)]
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Server shutting down message.
|
||||
/// </summary>
|
||||
public class ServerShuttingDownMessage : WebSocketMessage, IOutboundWebSocketMessage
|
||||
public class ServerShuttingDownMessage : OutboundWebSocketMessage
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.ServerShuttingDown)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Session;
|
||||
@@ -7,13 +8,13 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Sessions message.
|
||||
/// </summary>
|
||||
public class SessionsMessage : WebSocketMessage<SessionInfo>, IOutboundWebSocketMessage
|
||||
public class SessionsMessage : OutboundWebSocketMessage<IReadOnlyList<SessionInfo>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionsMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Session info.</param>
|
||||
public SessionsMessage(SessionInfo data)
|
||||
public SessionsMessage(IReadOnlyList<SessionInfo> data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Sync play command.
|
||||
/// </summary>
|
||||
public class SyncPlayCommandMessage : WebSocketMessage<SendCommand>, IOutboundWebSocketMessage
|
||||
public class SyncPlayCommandMessage : OutboundWebSocketMessage<SendCommand>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayCommandMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Untyped sync play command.
|
||||
/// </summary>
|
||||
public class SyncPlayGroupUpdateCommandMessage : WebSocketMessage<GroupUpdate>, IOutboundWebSocketMessage
|
||||
public class SyncPlayGroupUpdateCommandMessage : OutboundWebSocketMessage<GroupUpdate>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandMessage"/> class.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// Sync play group update command with group info.
|
||||
/// GroupUpdateTypes: GroupJoined.
|
||||
/// </summary>
|
||||
public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : WebSocketMessage<GroupUpdate<GroupInfoDto>>, IOutboundWebSocketMessage
|
||||
public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : OutboundWebSocketMessage<GroupUpdate<GroupInfoDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupInfoMessage"/> class.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// Sync play group update command with group state update.
|
||||
/// GroupUpdateTypes: StateUpdate.
|
||||
/// </summary>
|
||||
public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : WebSocketMessage<GroupUpdate<GroupStateUpdate>>, IOutboundWebSocketMessage
|
||||
public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : OutboundWebSocketMessage<GroupUpdate<GroupStateUpdate>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage"/> class.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// Sync play group update command with play queue update.
|
||||
/// GroupUpdateTypes: PlayQueue.
|
||||
/// </summary>
|
||||
public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : WebSocketMessage<GroupUpdate<PlayQueueUpdate>>, IOutboundWebSocketMessage
|
||||
public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : OutboundWebSocketMessage<GroupUpdate<PlayQueueUpdate>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage"/> class.
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// Sync play group update command with string.
|
||||
/// GroupUpdateTypes: GroupDoesNotExist (error), LibraryAccessDenied (error), NotInGroup (error), GroupLeft (groupId), UserJoined (username), UserLeft (username).
|
||||
/// </summary>
|
||||
public class SyncPlayGroupUpdateCommandOfStringMessage : WebSocketMessage<GroupUpdate<string>>, IOutboundWebSocketMessage
|
||||
public class SyncPlayGroupUpdateCommandOfStringMessage : OutboundWebSocketMessage<GroupUpdate<string>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfStringMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Timer cancelled message.
|
||||
/// </summary>
|
||||
public class TimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
|
||||
public class TimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TimerCancelledMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Timer created message.
|
||||
/// </summary>
|
||||
public class TimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage
|
||||
public class TimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TimerCreatedMessage"/> class.
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// User data changed message.
|
||||
/// </summary>
|
||||
public class UserDataChangedMessage : WebSocketMessage<UserDataChangeInfo>, IOutboundWebSocketMessage
|
||||
public class UserDataChangedMessage : OutboundWebSocketMessage<UserDataChangeInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDataChangedMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// User deleted message.
|
||||
/// </summary>
|
||||
public class UserDeletedMessage : WebSocketMessage<Guid>, IOutboundWebSocketMessage
|
||||
public class UserDeletedMessage : OutboundWebSocketMessage<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserDeletedMessage"/> class.
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// User updated message.
|
||||
/// </summary>
|
||||
public class UserUpdatedMessage : WebSocketMessage<UserDto>, IOutboundWebSocketMessage
|
||||
public class UserUpdatedMessage : OutboundWebSocketMessage<UserDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserUpdatedMessage"/> class.
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Class representing the list of outbound websocket message types.
|
||||
/// Only used in openapi generation.
|
||||
/// Outbound websocket message.
|
||||
/// </summary>
|
||||
public class OutboundWebSocketMessage : WebSocketMessage
|
||||
public class OutboundWebSocketMessage : WebSocketMessage, IOutboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the message id.
|
||||
/// </summary>
|
||||
public Guid MessageId { get; set; } = Guid.NewGuid();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma warning disable SA1649 // File name must equal class name.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages;
|
||||
|
||||
/// <summary>
|
||||
/// Outbound websocket message with data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data type.</typeparam>
|
||||
public class OutboundWebSocketMessage<T> : WebSocketMessage<T>, IOutboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class.
|
||||
/// </summary>
|
||||
public OutboundWebSocketMessage()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to send.</param>
|
||||
protected OutboundWebSocketMessage(T data)
|
||||
{
|
||||
Data = data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message id.
|
||||
/// </summary>
|
||||
public Guid MessageId { get; set; } = Guid.NewGuid();
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Shared;
|
||||
|
||||
/// <summary>
|
||||
/// Keep alive websocket messages.
|
||||
/// </summary>
|
||||
public class KeepAliveMessage : WebSocketMessage<int>, IInboundWebSocketMessage, IOutboundWebSocketMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeepAliveMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">The seconds to keep alive for.</param>
|
||||
public KeepAliveMessage(int data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DefaultValue(SessionMessageType.KeepAlive)]
|
||||
public override SessionMessageType MessageType => SessionMessageType.KeepAlive;
|
||||
}
|
||||
@@ -44,6 +44,12 @@ namespace MediaBrowser.Controller.Playlists
|
||||
/// <summary>
|
||||
/// Gets the playlists folder.
|
||||
/// </summary>
|
||||
/// <returns>Folder.</returns>
|
||||
Folder GetPlaylistsFolder();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the playlists folder for a user.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user identifier.</param>
|
||||
/// <returns>Folder.</returns>
|
||||
Folder GetPlaylistsFolder(Guid userId);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Events;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>BaseItem.</returns>
|
||||
BaseItem ResolvePath(ItemResolveArgs args);
|
||||
BaseItem? ResolvePath(ItemResolveArgs args);
|
||||
}
|
||||
|
||||
public interface IMultiItemResolver
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
@@ -23,7 +21,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>`0.</returns>
|
||||
protected internal virtual T Resolve(ItemResolveArgs args)
|
||||
protected internal virtual T? Resolve(ItemResolveArgs args)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -42,7 +40,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns>BaseItem.</returns>
|
||||
public BaseItem ResolvePath(ItemResolveArgs args)
|
||||
public BaseItem? ResolvePath(ItemResolveArgs args)
|
||||
{
|
||||
var item = Resolve(args);
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.Security
|
||||
|
||||
@@ -232,20 +232,6 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <returns>Task.</returns>
|
||||
Task SendRestartRequiredNotification(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the server shutdown notification.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendServerShutdownNotification(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the server restart notification.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task SendServerRestartNotification(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the additional user.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace MediaBrowser.Controller.Subtitles
|
||||
|
||||
public bool IsForced { get; set; }
|
||||
|
||||
public bool IsHearingImpaired { get; set; }
|
||||
|
||||
public Stream Stream { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user