mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-04-22 01:54:42 +01:00
Merge remote-tracking branch 'jellyfinorigin/master' into feature/EFUserData
This commit is contained in:
@@ -1,20 +1,31 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Controller.Authentication
|
||||
namespace MediaBrowser.Controller.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// A class representing an authentication result.
|
||||
/// </summary>
|
||||
public class AuthenticationResult
|
||||
{
|
||||
public class AuthenticationResult
|
||||
{
|
||||
public UserDto User { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the user.
|
||||
/// </summary>
|
||||
public UserDto User { get; set; }
|
||||
|
||||
public SessionInfo SessionInfo { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the session info.
|
||||
/// </summary>
|
||||
public SessionInfoDto SessionInfo { get; set; }
|
||||
|
||||
public string AccessToken { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the access token.
|
||||
/// </summary>
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
public string ServerId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the server id.
|
||||
/// </summary>
|
||||
public string ServerId { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,81 +1,117 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Dtos;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Entities.Security;
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Queries;
|
||||
using MediaBrowser.Model.Devices;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Devices
|
||||
namespace MediaBrowser.Controller.Devices;
|
||||
|
||||
/// <summary>
|
||||
/// Device manager interface.
|
||||
/// </summary>
|
||||
public interface IDeviceManager
|
||||
{
|
||||
public interface IDeviceManager
|
||||
{
|
||||
event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||
/// <summary>
|
||||
/// Event handler for updated device options.
|
||||
/// </summary>
|
||||
event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new device.
|
||||
/// </summary>
|
||||
/// <param name="device">The device to create.</param>
|
||||
/// <returns>A <see cref="Task{Device}"/> representing the creation of the device.</returns>
|
||||
Task<Device> CreateDevice(Device device);
|
||||
/// <summary>
|
||||
/// Creates a new device.
|
||||
/// </summary>
|
||||
/// <param name="device">The device to create.</param>
|
||||
/// <returns>A <see cref="Task{Device}"/> representing the creation of the device.</returns>
|
||||
Task<Device> CreateDevice(Device device);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="capabilities">The capabilities.</param>
|
||||
void SaveCapabilities(string deviceId, ClientCapabilities capabilities);
|
||||
/// <summary>
|
||||
/// Saves the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="capabilities">The capabilities.</param>
|
||||
void SaveCapabilities(string deviceId, ClientCapabilities capabilities);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <returns>ClientCapabilities.</returns>
|
||||
ClientCapabilities GetCapabilities(string deviceId);
|
||||
/// <summary>
|
||||
/// Gets the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <returns>ClientCapabilities.</returns>
|
||||
ClientCapabilities GetCapabilities(string? deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device information.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>DeviceInfo.</returns>
|
||||
DeviceInfo GetDevice(string id);
|
||||
/// <summary>
|
||||
/// Gets the device information.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>DeviceInfoDto.</returns>
|
||||
DeviceInfoDto? GetDevice(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets devices based on the provided query.
|
||||
/// </summary>
|
||||
/// <param name="query">The device query.</param>
|
||||
/// <returns>A <see cref="Task{QueryResult}"/> representing the retrieval of the devices.</returns>
|
||||
QueryResult<Device> GetDevices(DeviceQuery query);
|
||||
/// <summary>
|
||||
/// Gets devices based on the provided query.
|
||||
/// </summary>
|
||||
/// <param name="query">The device query.</param>
|
||||
/// <returns>A <see cref="Task{QueryResult}"/> representing the retrieval of the devices.</returns>
|
||||
QueryResult<Device> GetDevices(DeviceQuery query);
|
||||
|
||||
QueryResult<DeviceInfo> GetDeviceInfos(DeviceQuery query);
|
||||
/// <summary>
|
||||
/// Gets device infromation based on the provided query.
|
||||
/// </summary>
|
||||
/// <param name="query">The device query.</param>
|
||||
/// <returns>A <see cref="Task{QueryResult}"/> representing the retrieval of the device information.</returns>
|
||||
QueryResult<DeviceInfo> GetDeviceInfos(DeviceQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the devices.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id, or <c>null</c>.</param>
|
||||
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
||||
QueryResult<DeviceInfo> GetDevicesForUser(Guid? userId);
|
||||
/// <summary>
|
||||
/// Gets the device information.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's id, or <c>null</c>.</param>
|
||||
/// <returns>IEnumerable<DeviceInfoDto>.</returns>
|
||||
QueryResult<DeviceInfoDto> GetDevicesForUser(Guid? userId);
|
||||
|
||||
Task DeleteDevice(Device device);
|
||||
/// <summary>
|
||||
/// Deletes a device.
|
||||
/// </summary>
|
||||
/// <param name="device">The device.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the deletion of the device.</returns>
|
||||
Task DeleteDevice(Device device);
|
||||
|
||||
Task UpdateDevice(Device device);
|
||||
/// <summary>
|
||||
/// Updates a device.
|
||||
/// </summary>
|
||||
/// <param name="device">The device.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the update of the device.</returns>
|
||||
Task UpdateDevice(Device device);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance [can access device] the specified user identifier.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to test.</param>
|
||||
/// <param name="deviceId">The device id to test.</param>
|
||||
/// <returns>Whether the user can access the device.</returns>
|
||||
bool CanAccessDevice(User user, string deviceId);
|
||||
/// <summary>
|
||||
/// Determines whether this instance [can access device] the specified user identifier.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to test.</param>
|
||||
/// <param name="deviceId">The device id to test.</param>
|
||||
/// <returns>Whether the user can access the device.</returns>
|
||||
bool CanAccessDevice(User user, string deviceId);
|
||||
|
||||
Task UpdateDeviceOptions(string deviceId, string deviceName);
|
||||
/// <summary>
|
||||
/// Updates the options of a device.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="deviceName">The device name.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the update of the device options.</returns>
|
||||
Task UpdateDeviceOptions(string deviceId, string? deviceName);
|
||||
|
||||
DeviceOptions GetDeviceOptions(string deviceId);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the options of a device.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <returns><see cref="DeviceOptions"/> of the device.</returns>
|
||||
DeviceOptionsDto? GetDeviceOptions(string deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the dto for client capabilites.
|
||||
/// </summary>
|
||||
/// <param name="capabilities">The client capabilities.</param>
|
||||
/// <returns><see cref="ClientCapabilitiesDto"/> of the device.</returns>
|
||||
ClientCapabilitiesDto ToClientCapabilitiesDto(ClientCapabilities capabilities);
|
||||
}
|
||||
|
||||
@@ -1087,12 +1087,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
return 1;
|
||||
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
|
||||
.ThenByDescending(i =>
|
||||
{
|
||||
var stream = i.VideoStream;
|
||||
|
||||
return stream is null || stream.Width is null ? 0 : stream.Width.Value;
|
||||
})
|
||||
.ThenByDescending(i => i, new MediaSourceWidthComparator())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@@ -1185,28 +1180,29 @@ namespace MediaBrowser.Controller.Entities
|
||||
return info;
|
||||
}
|
||||
|
||||
private string GetMediaSourceName(BaseItem item)
|
||||
internal string GetMediaSourceName(BaseItem item)
|
||||
{
|
||||
var terms = new List<string>();
|
||||
|
||||
var path = item.Path;
|
||||
if (item.IsFileProtocol && !string.IsNullOrEmpty(path))
|
||||
{
|
||||
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
if (HasLocalAlternateVersions)
|
||||
{
|
||||
var displayName = System.IO.Path.GetFileNameWithoutExtension(path)
|
||||
.Replace(System.IO.Path.GetFileName(ContainingFolderPath), string.Empty, StringComparison.OrdinalIgnoreCase)
|
||||
.TrimStart(new char[] { ' ', '-' });
|
||||
|
||||
if (!string.IsNullOrEmpty(displayName))
|
||||
var containingFolderName = System.IO.Path.GetFileName(ContainingFolderPath);
|
||||
if (displayName.Length > containingFolderName.Length && displayName.StartsWith(containingFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
terms.Add(displayName);
|
||||
var name = displayName.AsSpan(containingFolderName.Length).TrimStart([' ', '-']);
|
||||
if (!name.IsWhiteSpace())
|
||||
{
|
||||
terms.Add(name.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (terms.Count == 0)
|
||||
{
|
||||
var displayName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||||
terms.Add(displayName);
|
||||
}
|
||||
}
|
||||
@@ -1612,7 +1608,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
var parent = GetParents().FirstOrDefault() ?? this;
|
||||
if (parent is UserRootFolder or AggregateFolder)
|
||||
if (parent is UserRootFolder or AggregateFolder or UserView)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Compare MediaSource of the same file by Video width <see cref="IComparer{T}" />.
|
||||
/// </summary>
|
||||
public class MediaSourceWidthComparator : IComparer<MediaSourceInfo>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public int Compare(MediaSourceInfo? x, MediaSourceInfo? y)
|
||||
{
|
||||
if (x is null && y is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (x is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (y is null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (string.Equals(x.Path, y.Path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (x.VideoStream is null && y.VideoStream is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (x.VideoStream is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (y.VideoStream is null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var xWidth = x.VideoStream.Width ?? 0;
|
||||
var yWidth = y.VideoStream.Width ?? 0;
|
||||
|
||||
return xWidth - yWidth;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -180,10 +180,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
|
||||
public string FindSeriesPresentationUniqueKey()
|
||||
{
|
||||
var series = Series;
|
||||
return series is null ? null : series.PresentationUniqueKey;
|
||||
}
|
||||
=> Series?.PresentationUniqueKey;
|
||||
|
||||
public string FindSeasonName()
|
||||
{
|
||||
|
||||
@@ -430,8 +430,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
InternalItemsQuery query,
|
||||
ILibraryManager libraryManager)
|
||||
{
|
||||
var user = query.User;
|
||||
|
||||
// This must be the last filter
|
||||
if (!query.AdjacentTo.IsNullOrEmpty())
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
|
||||
namespace MediaBrowser.Controller.Events.Authentication;
|
||||
@@ -29,7 +28,7 @@ public class AuthenticationResultEventArgs : EventArgs
|
||||
/// <summary>
|
||||
/// Gets or sets the session information.
|
||||
/// </summary>
|
||||
public SessionInfo? SessionInfo { get; set; }
|
||||
public SessionInfoDto? SessionInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server id.
|
||||
|
||||
@@ -39,6 +39,11 @@ namespace MediaBrowser.Controller.Extensions
|
||||
/// </summary>
|
||||
public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration";
|
||||
|
||||
/// <summary>
|
||||
/// The key for the FFmpeg image extraction performance tradeoff option.
|
||||
/// </summary>
|
||||
public const string FfmpegImgExtractPerfTradeoffKey = "FFmpeg:imgExtractPerfTradeoff";
|
||||
|
||||
/// <summary>
|
||||
/// The key for the FFmpeg path option.
|
||||
/// </summary>
|
||||
@@ -69,6 +74,11 @@ namespace MediaBrowser.Controller.Extensions
|
||||
/// </summary>
|
||||
public const string SqliteCacheSizeKey = "sqlite:cacheSize";
|
||||
|
||||
/// <summary>
|
||||
/// The key for a setting that indicates whether the application should detect network status change.
|
||||
/// </summary>
|
||||
public const string DetectNetworkChangeKey = "DetectNetworkChange";
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the application should host static web content from the <see cref="IConfiguration"/>.
|
||||
/// </summary>
|
||||
@@ -102,6 +112,14 @@ namespace MediaBrowser.Controller.Extensions
|
||||
public static bool GetFFmpegSkipValidation(this IConfiguration configuration)
|
||||
=> configuration.GetValue<bool>(FfmpegSkipValidationKey);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the server should trade off for performance during FFmpeg image extraction.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration to read the setting from.</param>
|
||||
/// <returns><c>true</c> if the server should trade off for performance during FFmpeg image extraction, otherwise <c>false</c>.</returns>
|
||||
public static bool GetFFmpegImgExtractPerfTradeoff(this IConfiguration configuration)
|
||||
=> configuration.GetValue<bool>(FfmpegImgExtractPerfTradeoffKey);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -193,6 +193,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
public bool EnableAudioVbrEncoding { get; set; }
|
||||
|
||||
public bool AlwaysBurnInSubtitleWhenTranscoding { get; set; }
|
||||
|
||||
public string GetOption(string qualifier, string name)
|
||||
{
|
||||
var value = GetOption(qualifier + "-" + name);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -305,7 +305,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
if (BaseRequest.Static
|
||||
|| EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream is null ? null : (VideoStream.AverageFrameRate ?? VideoStream.RealFrameRate);
|
||||
return VideoStream?.ReferenceFrameRate;
|
||||
}
|
||||
|
||||
return BaseRequest.MaxFramerate ?? BaseRequest.Framerate;
|
||||
|
||||
@@ -44,5 +44,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
Task<string> GetSubtitleFileCharacterSet(MediaStream subtitleStream, string language, MediaSourceInfo mediaSource, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to a subtitle file.
|
||||
/// </summary>
|
||||
/// <param name="subtitleStream">The subtitle stream.</param>
|
||||
/// <param name="mediaSource">The media source.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
Task<string> GetSubtitleFilePath(MediaStream subtitleStream, MediaSourceInfo mediaSource, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
@@ -13,6 +14,15 @@ namespace MediaBrowser.Controller;
|
||||
/// </summary>
|
||||
public interface IMediaSegmentManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses all segment providers enabled for the <see cref="BaseItem"/>'s library to get the Media Segments.
|
||||
/// </summary>
|
||||
/// <param name="baseItem">The Item to evaluate.</param>
|
||||
/// <param name="overwrite">If set, will remove existing segments and replace it with new ones otherwise will check for existing segments and if found any, stops.</param>
|
||||
/// <param name="cancellationToken">stop request token.</param>
|
||||
/// <returns>A task that indicates the Operation is finished.</returns>
|
||||
Task RunSegmentPluginProviders(BaseItem baseItem, bool overwrite, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Returns if this item supports media segments.
|
||||
/// </summary>
|
||||
@@ -50,4 +60,11 @@ public interface IMediaSegmentManager
|
||||
/// <returns>True if there are any segments stored for the item, otherwise false.</returns>
|
||||
/// TODO: this should be async but as the only caller BaseItem.GetVersionInfo isn't async, this is also not. Venson.
|
||||
bool HasSegments(Guid itemId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all registered Segment Providers and their IDs.
|
||||
/// </summary>
|
||||
/// <param name="item">The media item that should be tested for providers.</param>
|
||||
/// <returns>A list of all providers for the tested item.</returns>
|
||||
IEnumerable<(string Name, string Id)> GetSupportedProviders(BaseItem item);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model;
|
||||
using MediaBrowser.Model.MediaSegments;
|
||||
|
||||
namespace MediaBrowser.Controller;
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods for Obtaining the Media Segments from an Item.
|
||||
/// </summary>
|
||||
public interface IMediaSegmentProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the provider name.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all Media Segments from an Media Item.
|
||||
/// </summary>
|
||||
/// <param name="request">Arguments to enumerate MediaSegments.</param>
|
||||
/// <param name="cancellationToken">Abort token.</param>
|
||||
/// <returns>A list of all MediaSegments found from this provider.</returns>
|
||||
Task<IReadOnlyList<MediaSegmentDto>> GetMediaSegments(MediaSegmentGenerationRequest request, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Should return support state for the given item.
|
||||
/// </summary>
|
||||
/// <param name="item">The base item to extract segments from.</param>
|
||||
/// <returns>True if item is supported, otherwise false.</returns>
|
||||
ValueTask<bool> Supports(BaseItem item);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Session;
|
||||
|
||||
namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
@@ -8,13 +9,13 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
|
||||
/// <summary>
|
||||
/// Sessions message.
|
||||
/// </summary>
|
||||
public class SessionsMessage : OutboundWebSocketMessage<IReadOnlyList<SessionInfo>>
|
||||
public class SessionsMessage : OutboundWebSocketMessage<IReadOnlyList<SessionInfoDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionsMessage"/> class.
|
||||
/// </summary>
|
||||
/// <param name="data">Session info.</param>
|
||||
public SessionsMessage(IReadOnlyList<SessionInfo> data)
|
||||
public SessionsMessage(IReadOnlyList<SessionInfoDto> data)
|
||||
: base(data)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace MediaBrowser.Controller.Providers
|
||||
IsAutomated = copy.IsAutomated;
|
||||
ImageRefreshMode = copy.ImageRefreshMode;
|
||||
ReplaceAllImages = copy.ReplaceAllImages;
|
||||
RegenerateTrickplay = copy.RegenerateTrickplay;
|
||||
ReplaceImages = copy.ReplaceImages;
|
||||
SearchResult = copy.SearchResult;
|
||||
RemoveOldMetadata = copy.RemoveOldMetadata;
|
||||
@@ -47,6 +48,12 @@ namespace MediaBrowser.Controller.Providers
|
||||
/// </summary>
|
||||
public bool ReplaceAllMetadata { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether all existing trickplay images should be overwritten
|
||||
/// when paired with MetadataRefreshMode=FullRefresh.
|
||||
/// </summary>
|
||||
public bool RegenerateTrickplay { get; set; }
|
||||
|
||||
public MetadataRefreshMode MetadataRefreshMode { get; set; }
|
||||
|
||||
public RemoteSearchResult SearchResult { get; set; }
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities.Security;
|
||||
using MediaBrowser.Controller.Authentication;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Session;
|
||||
using MediaBrowser.Model.SyncPlay;
|
||||
|
||||
@@ -292,6 +293,17 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <returns>SessionInfo.</returns>
|
||||
SessionInfo GetSession(string deviceId, string client, string version);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all sessions available to a user.
|
||||
/// </summary>
|
||||
/// <param name="userId">The session identifier.</param>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="activeWithinSeconds">Active within session limit.</param>
|
||||
/// <param name="controllableUserToCheck">Filter for sessions remote controllable for this user.</param>
|
||||
/// <param name="isApiKey">Is the request authenticated with API key.</param>
|
||||
/// <returns>IReadOnlyList{SessionInfoDto}.</returns>
|
||||
IReadOnlyList<SessionInfoDto> GetSessions(Guid userId, string deviceId, int? activeWithinSeconds, Guid? controllableUserToCheck, bool isApiKey);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the session by authentication token.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -27,28 +25,45 @@ namespace MediaBrowser.Controller.Session
|
||||
private readonly ISessionManager _sessionManager;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private readonly object _progressLock = new object();
|
||||
private readonly object _progressLock = new();
|
||||
private Timer _progressTimer;
|
||||
private PlaybackProgressInfo _lastProgressInfo;
|
||||
|
||||
private bool _disposed = false;
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SessionInfo"/> class.
|
||||
/// </summary>
|
||||
/// <param name="sessionManager">Instance of <see cref="ISessionManager"/> interface.</param>
|
||||
/// <param name="logger">Instance of <see cref="ILogger"/> interface.</param>
|
||||
public SessionInfo(ISessionManager sessionManager, ILogger logger)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
_logger = logger;
|
||||
|
||||
AdditionalUsers = Array.Empty<SessionUserInfo>();
|
||||
AdditionalUsers = [];
|
||||
PlayState = new PlayerStateInfo();
|
||||
SessionControllers = Array.Empty<ISessionController>();
|
||||
NowPlayingQueue = Array.Empty<QueueItem>();
|
||||
NowPlayingQueueFullItems = Array.Empty<BaseItemDto>();
|
||||
SessionControllers = [];
|
||||
NowPlayingQueue = [];
|
||||
NowPlayingQueueFullItems = [];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the play state.
|
||||
/// </summary>
|
||||
/// <value>The play state.</value>
|
||||
public PlayerStateInfo PlayState { get; set; }
|
||||
|
||||
public SessionUserInfo[] AdditionalUsers { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the additional users.
|
||||
/// </summary>
|
||||
/// <value>The additional users.</value>
|
||||
public IReadOnlyList<SessionUserInfo> AdditionalUsers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the client capabilities.
|
||||
/// </summary>
|
||||
/// <value>The client capabilities.</value>
|
||||
public ClientCapabilities Capabilities { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -67,7 +82,7 @@ namespace MediaBrowser.Controller.Session
|
||||
{
|
||||
if (Capabilities is null)
|
||||
{
|
||||
return Array.Empty<MediaType>();
|
||||
return [];
|
||||
}
|
||||
|
||||
return Capabilities.PlayableMediaTypes;
|
||||
@@ -134,9 +149,17 @@ namespace MediaBrowser.Controller.Session
|
||||
/// <value>The now playing item.</value>
|
||||
public BaseItemDto NowPlayingItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the now playing queue full items.
|
||||
/// </summary>
|
||||
/// <value>The now playing queue full items.</value>
|
||||
[JsonIgnore]
|
||||
public BaseItem FullNowPlayingItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the now viewing item.
|
||||
/// </summary>
|
||||
/// <value>The now viewing item.</value>
|
||||
public BaseItemDto NowViewingItem { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -156,8 +179,12 @@ namespace MediaBrowser.Controller.Session
|
||||
/// </summary>
|
||||
/// <value>The session controller.</value>
|
||||
[JsonIgnore]
|
||||
public ISessionController[] SessionControllers { get; set; }
|
||||
public IReadOnlyList<ISessionController> SessionControllers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the transcoding info.
|
||||
/// </summary>
|
||||
/// <value>The transcoding info.</value>
|
||||
public TranscodingInfo TranscodingInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -177,7 +204,7 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
if (controllers.Length > 0)
|
||||
if (controllers.Count > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -186,6 +213,10 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the session supports media control.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this session supports media control; otherwise, <c>false</c>.</value>
|
||||
public bool SupportsMediaControl
|
||||
{
|
||||
get
|
||||
@@ -208,6 +239,10 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the session supports remote control.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this session supports remote control; otherwise, <c>false</c>.</value>
|
||||
public bool SupportsRemoteControl
|
||||
{
|
||||
get
|
||||
@@ -230,16 +265,40 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the now playing queue.
|
||||
/// </summary>
|
||||
/// <value>The now playing queue.</value>
|
||||
public IReadOnlyList<QueueItem> NowPlayingQueue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the now playing queue full items.
|
||||
/// </summary>
|
||||
/// <value>The now playing queue full items.</value>
|
||||
public IReadOnlyList<BaseItemDto> NowPlayingQueueFullItems { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the session has a custom device name.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this session has a custom device name; otherwise, <c>false</c>.</value>
|
||||
public bool HasCustomDeviceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the playlist item id.
|
||||
/// </summary>
|
||||
/// <value>The splaylist item id.</value>
|
||||
public string PlaylistItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server id.
|
||||
/// </summary>
|
||||
/// <value>The server id.</value>
|
||||
public string ServerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user primary image tag.
|
||||
/// </summary>
|
||||
/// <value>The user primary image tag.</value>
|
||||
public string UserPrimaryImageTag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -247,8 +306,14 @@ namespace MediaBrowser.Controller.Session
|
||||
/// </summary>
|
||||
/// <value>The supported commands.</value>
|
||||
public IReadOnlyList<GeneralCommandType> SupportedCommands
|
||||
=> Capabilities is null ? Array.Empty<GeneralCommandType>() : Capabilities.SupportedCommands;
|
||||
=> Capabilities is null ? [] : Capabilities.SupportedCommands;
|
||||
|
||||
/// <summary>
|
||||
/// Ensures a controller of type exists.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Class to register.</typeparam>
|
||||
/// <param name="factory">The factory.</param>
|
||||
/// <returns>Tuple{ISessionController, bool}.</returns>
|
||||
public Tuple<ISessionController, bool> EnsureController<T>(Func<SessionInfo, ISessionController> factory)
|
||||
{
|
||||
var controllers = SessionControllers.ToList();
|
||||
@@ -261,18 +326,27 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
|
||||
var newController = factory(this);
|
||||
_logger.LogDebug("Creating new {0}", newController.GetType().Name);
|
||||
_logger.LogDebug("Creating new {Factory}", newController.GetType().Name);
|
||||
controllers.Add(newController);
|
||||
|
||||
SessionControllers = controllers.ToArray();
|
||||
SessionControllers = [.. controllers];
|
||||
return new Tuple<ISessionController, bool>(newController, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a controller to the session.
|
||||
/// </summary>
|
||||
/// <param name="controller">The controller.</param>
|
||||
public void AddController(ISessionController controller)
|
||||
{
|
||||
SessionControllers = [..SessionControllers, controller];
|
||||
SessionControllers = [.. SessionControllers, controller];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the session contains a user.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user id to check.</param>
|
||||
/// <returns><c>true</c> if this session contains the user; otherwise, <c>false</c>.</returns>
|
||||
public bool ContainsUser(Guid userId)
|
||||
{
|
||||
if (UserId.Equals(userId))
|
||||
@@ -291,6 +365,11 @@ namespace MediaBrowser.Controller.Session
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts automatic progressing.
|
||||
/// </summary>
|
||||
/// <param name="progressInfo">The playback progress info.</param>
|
||||
/// <value>The supported commands.</value>
|
||||
public void StartAutomaticProgress(PlaybackProgressInfo progressInfo)
|
||||
{
|
||||
if (_disposed)
|
||||
@@ -359,6 +438,9 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops automatic progressing.
|
||||
/// </summary>
|
||||
public void StopAutomaticProgress()
|
||||
{
|
||||
lock (_progressLock)
|
||||
@@ -373,6 +455,10 @@ namespace MediaBrowser.Controller.Session
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the instance async.
|
||||
/// </summary>
|
||||
/// <returns>ValueTask.</returns>
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
_disposed = true;
|
||||
@@ -380,7 +466,7 @@ namespace MediaBrowser.Controller.Session
|
||||
StopAutomaticProgress();
|
||||
|
||||
var controllers = SessionControllers.ToList();
|
||||
SessionControllers = Array.Empty<ISessionController>();
|
||||
SessionControllers = [];
|
||||
|
||||
foreach (var controller in controllers)
|
||||
{
|
||||
|
||||
@@ -18,9 +18,10 @@ public interface ITrickplayManager
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="replace">Whether or not existing data should be replaced.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task RefreshTrickplayDataAsync(Video video, bool replace, CancellationToken cancellationToken);
|
||||
Task RefreshTrickplayDataAsync(Video video, bool replace, LibraryOptions? libraryOptions, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Creates trickplay tiles out of individual thumbnails.
|
||||
@@ -33,7 +34,7 @@ public interface ITrickplayManager
|
||||
/// <remarks>
|
||||
/// The output directory will be DELETED and replaced if it already exists.
|
||||
/// </remarks>
|
||||
TrickplayInfo CreateTiles(List<string> images, int width, TrickplayOptions options, string outputDir);
|
||||
TrickplayInfo CreateTiles(IReadOnlyList<string> images, int width, TrickplayOptions options, string outputDir);
|
||||
|
||||
/// <summary>
|
||||
/// Get available trickplay resolutions and corresponding info.
|
||||
@@ -42,6 +43,14 @@ public interface ITrickplayManager
|
||||
/// <returns>Map of width resolutions to trickplay tiles info.</returns>
|
||||
Task<Dictionary<int, TrickplayInfo>> GetTrickplayResolutions(Guid itemId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the item ids of all items with trickplay info.
|
||||
/// </summary>
|
||||
/// <param name="limit">The limit of items to return.</param>
|
||||
/// <param name="offset">The offset to start the query at.</param>
|
||||
/// <returns>The list of item ids that have trickplay info.</returns>
|
||||
Task<IReadOnlyList<TrickplayInfo>> GetTrickplayItemsAsync(int limit, int offset);
|
||||
|
||||
/// <summary>
|
||||
/// Saves trickplay info.
|
||||
/// </summary>
|
||||
@@ -62,8 +71,29 @@ public interface ITrickplayManager
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="width">The width of a single thumbnail.</param>
|
||||
/// <param name="index">The tile's index.</param>
|
||||
/// <param name="saveWithMedia">Whether or not the tile should be saved next to the media file.</param>
|
||||
/// <returns>The absolute path.</returns>
|
||||
string GetTrickplayTilePath(BaseItem item, int width, int index);
|
||||
Task<string> GetTrickplayTilePathAsync(BaseItem item, int width, int index, bool saveWithMedia);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to a trickplay tile image.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="tileWidth">The amount of images for the tile width.</param>
|
||||
/// <param name="tileHeight">The amount of images for the tile height.</param>
|
||||
/// <param name="width">The width of a single thumbnail.</param>
|
||||
/// <param name="saveWithMedia">Whether or not the tile should be saved next to the media file.</param>
|
||||
/// <returns>The absolute path.</returns>
|
||||
string GetTrickplayDirectory(BaseItem item, int tileWidth, int tileHeight, int width, bool saveWithMedia = false);
|
||||
|
||||
/// <summary>
|
||||
/// Migrates trickplay images between local and media directories.
|
||||
/// </summary>
|
||||
/// <param name="video">The video.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task MoveGeneratedTrickplayDataAsync(Video video, LibraryOptions? libraryOptions, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trickplay HLS playlist.
|
||||
|
||||
Reference in New Issue
Block a user