mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-01 05:18:27 +01:00
Merge branch 'master' into comparisons
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@@ -16,7 +15,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
{
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
|
||||
private int _metadataRefreshConcurrency = 0;
|
||||
private int _metadataRefreshConcurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseItemManager"/> class.
|
||||
@@ -56,12 +55,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
return typeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (!libraryOptions.EnableInternetProviders)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return itemConfig == null || !itemConfig.DisabledMetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -87,12 +81,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
return typeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (!libraryOptions.EnableInternetProviders)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return itemConfig == null || !itemConfig.DisabledImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
@@ -101,7 +90,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
/// Called when the configuration is updated.
|
||||
/// It will refresh the metadata throttler if the relevant config changed.
|
||||
/// </summary>
|
||||
private void OnConfigurationUpdated(object sender, EventArgs e)
|
||||
private void OnConfigurationUpdated(object? sender, EventArgs e)
|
||||
{
|
||||
int newMetadataRefreshConcurrency = GetMetadataRefreshConcurrency();
|
||||
if (_metadataRefreshConcurrency != newMetadataRefreshConcurrency)
|
||||
@@ -114,6 +103,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
/// <summary>
|
||||
/// Creates the metadata refresh throttler.
|
||||
/// </summary>
|
||||
[MemberNotNull(nameof(MetadataRefreshThrottler))]
|
||||
private void SetupMetadataThrottler()
|
||||
{
|
||||
MetadataRefreshThrottler = new SemaphoreSlim(_metadataRefreshConcurrency);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
@@ -34,4 +32,4 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
/// <returns><c>true</c> if image fetcher is enabled, else false.</returns>
|
||||
bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class Channel : Folder
|
||||
{
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override SourceType SourceType => SourceType.Channel;
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
var blockedChannelsPreference = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedChannels);
|
||||
@@ -39,12 +45,6 @@ namespace MediaBrowser.Controller.Channels
|
||||
return base.IsVisible(user);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override SourceType SourceType => SourceType.Channel;
|
||||
|
||||
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
@@ -10,10 +9,10 @@ namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public ChannelItemResult()
|
||||
{
|
||||
Items = new List<ChannelItemInfo>();
|
||||
Items = Array.Empty<ChannelItemInfo>();
|
||||
}
|
||||
|
||||
public List<ChannelItemInfo> Items { get; set; }
|
||||
public IReadOnlyList<ChannelItemInfo> Items { get; set; }
|
||||
|
||||
public int? TotalRecordCount { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Channels;
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace MediaBrowser.Controller.Chapters
|
||||
/// <summary>
|
||||
/// Saves the chapters.
|
||||
/// </summary>
|
||||
/// <param name="itemId">The item.</param>
|
||||
/// <param name="chapters">The set of chapters.</param>
|
||||
void SaveChapters(Guid itemId, IReadOnlyList<ChapterInfo> chapters);
|
||||
}
|
||||
}
|
||||
|
||||
31
MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs
Normal file
31
MediaBrowser.Controller/ClientEvent/ClientEventLogger.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.ClientEvent
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public class ClientEventLogger : IClientEventLogger
|
||||
{
|
||||
private readonly IServerApplicationPaths _applicationPaths;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ClientEventLogger"/> class.
|
||||
/// </summary>
|
||||
/// <param name="applicationPaths">Instance of the <see cref="IServerApplicationPaths"/> interface.</param>
|
||||
public ClientEventLogger(IServerApplicationPaths applicationPaths)
|
||||
{
|
||||
_applicationPaths = applicationPaths;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> WriteDocumentAsync(string clientName, string clientVersion, Stream fileContents)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs
Normal file
23
MediaBrowser.Controller/ClientEvent/IClientEventLogger.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MediaBrowser.Controller.ClientEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// The client event logger.
|
||||
/// </summary>
|
||||
public interface IClientEventLogger
|
||||
{
|
||||
/// <summary>
|
||||
/// Writes a file to the log directory.
|
||||
/// </summary>
|
||||
/// <param name="clientName">The client name writing the document.</param>
|
||||
/// <param name="clientVersion">The client version writing the document.</param>
|
||||
/// <param name="fileContents">The file contents to write.</param>
|
||||
/// <returns>The created file name.</returns>
|
||||
Task<string> WriteDocumentAsync(
|
||||
string clientName,
|
||||
string clientVersion,
|
||||
Stream fileContents);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -16,22 +14,23 @@ namespace MediaBrowser.Controller.Collections
|
||||
/// <summary>
|
||||
/// Occurs when [collection created].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
|
||||
event EventHandler<CollectionCreatedEventArgs>? CollectionCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [items added to collection].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
|
||||
event EventHandler<CollectionModifiedEventArgs>? ItemsAddedToCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [items removed from collection].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
|
||||
event EventHandler<CollectionModifiedEventArgs>? ItemsRemovedFromCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the collection.
|
||||
/// </summary>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>BoxSet wrapped in an awaitable task.</returns>
|
||||
Task<BoxSet> CreateCollectionAsync(CollectionCreationOptions options);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Entities.Security;
|
||||
using Jellyfin.Data.Events;
|
||||
using Jellyfin.Data.Queries;
|
||||
using MediaBrowser.Model.Devices;
|
||||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Session;
|
||||
@@ -15,33 +18,52 @@ namespace MediaBrowser.Controller.Devices
|
||||
{
|
||||
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>
|
||||
/// Saves the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="reportedId">The reported identifier.</param>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <param name="capabilities">The capabilities.</param>
|
||||
void SaveCapabilities(string reportedId, ClientCapabilities capabilities);
|
||||
void SaveCapabilities(string deviceId, ClientCapabilities capabilities);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the capabilities.
|
||||
/// </summary>
|
||||
/// <param name="reportedId">The reported identifier.</param>
|
||||
/// <param name="deviceId">The device id.</param>
|
||||
/// <returns>ClientCapabilities.</returns>
|
||||
ClientCapabilities GetCapabilities(string reportedId);
|
||||
ClientCapabilities GetCapabilities(string deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device information.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>DeviceInfo.</returns>
|
||||
DeviceInfo GetDevice(string id);
|
||||
Task<DeviceInfo> 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>
|
||||
Task<QueryResult<Device>> GetDevices(DeviceQuery query);
|
||||
|
||||
Task<QueryResult<DeviceInfo>> GetDeviceInfos(DeviceQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the devices.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="userId">The user's id, or <c>null</c>.</param>
|
||||
/// <param name="supportsSync">A value indicating whether the device supports sync, or <c>null</c>.</param>
|
||||
/// <returns>IEnumerable<DeviceInfo>.</returns>
|
||||
QueryResult<DeviceInfo> GetDevices(DeviceQuery query);
|
||||
Task<QueryResult<DeviceInfo>> GetDevicesForUser(Guid? userId, bool? supportsSync);
|
||||
|
||||
Task DeleteDevice(Device device);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance [can access device] the specified user identifier.
|
||||
@@ -51,8 +73,8 @@ namespace MediaBrowser.Controller.Devices
|
||||
/// <returns>Whether the user can access the device.</returns>
|
||||
bool CanAccessDevice(User user, string deviceId);
|
||||
|
||||
void UpdateDeviceOptions(string deviceId, DeviceOptions options);
|
||||
Task UpdateDeviceOptions(string deviceId, string deviceName);
|
||||
|
||||
DeviceOptions GetDeviceOptions(string deviceId);
|
||||
Task<DeviceOptions> GetDeviceOptions(string deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -22,7 +20,7 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// </summary>
|
||||
/// <param name="headers">The headers.</param>
|
||||
/// <returns>DeviceProfile.</returns>
|
||||
DeviceProfile GetProfile(IHeaderDictionary headers);
|
||||
DeviceProfile? GetProfile(IHeaderDictionary headers);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default profile.
|
||||
@@ -39,8 +37,9 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// <summary>
|
||||
/// Updates the profile.
|
||||
/// </summary>
|
||||
/// <param name="profileId">The profile id.</param>
|
||||
/// <param name="profile">The profile.</param>
|
||||
void UpdateProfile(DeviceProfile profile);
|
||||
void UpdateProfile(string profileId, DeviceProfile profile);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the profile.
|
||||
@@ -53,14 +52,14 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>DeviceProfile.</returns>
|
||||
DeviceProfile GetProfile(string id);
|
||||
DeviceProfile? GetProfile(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile.
|
||||
/// </summary>
|
||||
/// <param name="deviceInfo">The device information.</param>
|
||||
/// <returns>DeviceProfile.</returns>
|
||||
DeviceProfile GetProfile(DeviceIdentification deviceInfo);
|
||||
DeviceProfile? GetProfile(DeviceIdentification deviceInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the server description XML.
|
||||
@@ -76,6 +75,6 @@ namespace MediaBrowser.Controller.Dlna
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>DlnaIconResponse.</returns>
|
||||
ImageStream GetIcon(string filename);
|
||||
ImageStream? GetIcon(string filename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,15 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <summary>
|
||||
/// Encode an image.
|
||||
/// </summary>
|
||||
/// <param name="inputPath">Input path of image.</param>
|
||||
/// <param name="dateModified">Date modified.</param>
|
||||
/// <param name="outputPath">Output path of image.</param>
|
||||
/// <param name="autoOrient">Auto-orient image.</param>
|
||||
/// <param name="orientation">Desired orientation of image.</param>
|
||||
/// <param name="quality">Quality of encoded image.</param>
|
||||
/// <param name="options">Image processing options.</param>
|
||||
/// <param name="outputFormat">Image format of output.</param>
|
||||
/// <returns>Path of encoded image.</returns>
|
||||
string EncodeImage(string inputPath, DateTime dateModified, string outputPath, bool autoOrient, ImageOrientation? orientation, int quality, ImageProcessingOptions options, ImageFormat outputFormat);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Drawing
|
||||
/// <returns>Guid.</returns>
|
||||
string GetImageCacheTag(BaseItem item, ItemImageInfo image);
|
||||
|
||||
string GetImageCacheTag(BaseItem item, ChapterInfo info);
|
||||
string GetImageCacheTag(BaseItem item, ChapterInfo chapter);
|
||||
|
||||
string? GetImageCacheTag(User user);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1711, CS1591
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
@@ -8,11 +8,16 @@ namespace MediaBrowser.Controller.Drawing
|
||||
{
|
||||
public class ImageStream : IDisposable
|
||||
{
|
||||
public ImageStream(Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the stream.
|
||||
/// Gets the stream.
|
||||
/// </summary>
|
||||
/// <value>The stream.</value>
|
||||
public Stream? Stream { get; set; }
|
||||
public Stream Stream { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#nullable disable
|
||||
#pragma warning disable CA1002
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Data.Entities;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -18,32 +18,23 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Specialized folder that can have items added to it's children by external entities.
|
||||
/// Used for our RootFolder so plug-ins can add items.
|
||||
/// Used for our RootFolder so plugins can add items.
|
||||
/// </summary>
|
||||
public class AggregateFolder : Folder
|
||||
{
|
||||
private bool _requiresRefresh;
|
||||
|
||||
public AggregateFolder()
|
||||
{
|
||||
PhysicalLocationsList = Array.Empty<string>();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPhysicalRoot => true;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
private readonly object _childIdsLock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// The _virtual children.
|
||||
/// </summary>
|
||||
private readonly ConcurrentBag<BaseItem> _virtualChildren = new ConcurrentBag<BaseItem>();
|
||||
private bool _requiresRefresh;
|
||||
private Guid[] _childrenIds = null;
|
||||
|
||||
public AggregateFolder()
|
||||
{
|
||||
PhysicalLocationsList = Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the virtual children.
|
||||
@@ -51,19 +42,27 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The virtual children.</value>
|
||||
public ConcurrentBag<BaseItem> VirtualChildren => _virtualChildren;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPhysicalRoot => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string[] PhysicalLocations => PhysicalLocationsList;
|
||||
|
||||
public string[] PhysicalLocationsList { get; set; }
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
|
||||
{
|
||||
return CreateResolveArgs(directoryService, true).FileSystemChildren;
|
||||
}
|
||||
|
||||
private Guid[] _childrenIds = null;
|
||||
private readonly object _childIdsLock = new object();
|
||||
|
||||
protected override List<BaseItem> LoadChildren()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
@@ -169,7 +168,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Adds the virtual child.
|
||||
/// </summary>
|
||||
/// <param name="child">The child.</param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentNullException">Throws if child is null.</exception>
|
||||
public void AddVirtualChild(BaseItem child)
|
||||
{
|
||||
if (child == null)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA1724, CA1826, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,10 +8,8 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
@@ -25,6 +23,12 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
IHasLookupInfo<SongInfo>,
|
||||
IHasMediaSources
|
||||
{
|
||||
public Audio()
|
||||
{
|
||||
Artists = Array.Empty<string>();
|
||||
AlbumArtists = Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public IReadOnlyList<string> Artists { get; set; }
|
||||
@@ -33,22 +37,11 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public IReadOnlyList<string> AlbumArtists { get; set; }
|
||||
|
||||
public Audio()
|
||||
{
|
||||
Artists = Array.Empty<string>();
|
||||
AlbumArtists = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
public override bool SupportsPeople => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAddingToPlaylist => true;
|
||||
@@ -62,11 +55,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public override Folder LatestItemsIndexContainer => AlbumEntity;
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
return IsFileProtocol;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public MusicAlbum AlbumEntity => FindParent<MusicAlbum>();
|
||||
|
||||
@@ -77,6 +65,16 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public override string MediaType => Model.Entities.MediaType.Audio;
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
return IsFileProtocol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the name of the sort.
|
||||
/// </summary>
|
||||
@@ -126,15 +124,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return base.GetBlockUnratedType();
|
||||
}
|
||||
|
||||
public List<MediaStream> GetMediaStreams(MediaStreamType type)
|
||||
{
|
||||
return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
|
||||
{
|
||||
ItemId = Id,
|
||||
Type = type
|
||||
});
|
||||
}
|
||||
|
||||
public SongInfo GetLookupInfo()
|
||||
{
|
||||
var info = GetItemLookupInfo<SongInfo>();
|
||||
@@ -146,11 +135,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return info;
|
||||
}
|
||||
|
||||
protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
|
||||
{
|
||||
var list = new List<Tuple<BaseItem, MediaSourceType>>();
|
||||
list.Add(new Tuple<BaseItem, MediaSourceType>(this, MediaSourceType.Default));
|
||||
return list;
|
||||
}
|
||||
protected override IEnumerable<(BaseItem, MediaSourceType)> GetAllItemsForMediaSources()
|
||||
=> new[] { ((BaseItem)this, MediaSourceType.Default) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1721, CA1826, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -23,18 +23,18 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// </summary>
|
||||
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> Artists { get; set; }
|
||||
|
||||
public MusicAlbum()
|
||||
{
|
||||
Artists = Array.Empty<string>();
|
||||
AlbumArtists = Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> AlbumArtists { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> Artists { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAddingToPlaylist => true;
|
||||
|
||||
@@ -44,6 +44,25 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public MusicArtist MusicArtist => GetMusicArtist(new DtoOptions(true));
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsCumulativeRunTimeTicks => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public string AlbumArtist => AlbumArtists.FirstOrDefault();
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
/// </summary>
|
||||
/// <value>The tracks.</value>
|
||||
[JsonIgnore]
|
||||
public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
|
||||
|
||||
public MusicArtist GetMusicArtist(DtoOptions options)
|
||||
{
|
||||
var parents = GetParents();
|
||||
@@ -64,25 +83,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return null;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsCumulativeRunTimeTicks => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public string AlbumArtist => AlbumArtists.FirstOrDefault();
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracks.
|
||||
/// </summary>
|
||||
/// <value>The tracks.</value>
|
||||
[JsonIgnore]
|
||||
public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
|
||||
|
||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||
{
|
||||
return Tracks;
|
||||
|
||||
@@ -8,9 +8,9 @@ using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Diacritics.Extensions;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -44,6 +44,36 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
[JsonIgnore]
|
||||
public override IEnumerable<BaseItem> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
return base.Children;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public static string GetPath(string name)
|
||||
{
|
||||
return GetPath(name, true);
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
return 1;
|
||||
@@ -58,27 +88,13 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
{
|
||||
if (query.IncludeItemTypes.Length == 0)
|
||||
{
|
||||
query.IncludeItemTypes = new[] { nameof(Audio), nameof(MusicVideo), nameof(MusicAlbum) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Audio, BaseItemKind.MusicVideo, BaseItemKind.MusicAlbum };
|
||||
query.ArtistIds = new[] { Id };
|
||||
}
|
||||
|
||||
return LibraryManager.GetItemList(query);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override IEnumerable<BaseItem> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
return base.Children;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetChildCount(User user)
|
||||
{
|
||||
return IsAccessedByName ? 0 : base.GetChildCount(user);
|
||||
@@ -113,14 +129,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user data key.
|
||||
/// </summary>
|
||||
@@ -167,14 +175,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return info;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public static string GetPath(string name)
|
||||
{
|
||||
return GetPath(name, true);
|
||||
}
|
||||
|
||||
public static string GetPath(string name, bool normalizeName)
|
||||
{
|
||||
// Trim the period at the end because windows will have a hard time with that
|
||||
@@ -208,6 +208,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <param name="replaceAllMetadata">Option to replace metadata.</param>
|
||||
/// <returns>True if metadata changed.</returns>
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using Diacritics.Extensions;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Audio
|
||||
@@ -15,19 +16,6 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// </summary>
|
||||
public class MusicGenre : BaseItem, IItemByName
|
||||
{
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||
return list;
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
return GetUserDataKeys()[0];
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAddingToPlaylist => true;
|
||||
|
||||
@@ -45,6 +33,22 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||
return list;
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
return GetUserDataKeys()[0];
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
return 1;
|
||||
@@ -60,13 +64,10 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
return true;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||
{
|
||||
query.GenreIds = new[] { Id };
|
||||
query.IncludeItemTypes = new[] { nameof(MusicVideo), nameof(Audio), nameof(MusicAlbum), nameof(MusicArtist) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.MusicVideo, BaseItemKind.Audio, BaseItemKind.MusicAlbum, BaseItemKind.MusicArtist };
|
||||
|
||||
return LibraryManager.GetItemList(query);
|
||||
}
|
||||
@@ -106,6 +107,8 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <param name="replaceAllMetadata">Option to replace metadata.</param>
|
||||
/// <returns>True if metadata changed.</returns>
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1724, CS1591
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="file">The file.</param>
|
||||
public static void SetImagePath(this BaseItem item, ImageType imageType, string file)
|
||||
{
|
||||
if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
|
||||
if (file.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
item.SetImage(
|
||||
new ItemImageInfo
|
||||
@@ -64,6 +64,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <param name="dest">The destination object.</param>
|
||||
/// <typeparam name="T">Source type.</typeparam>
|
||||
/// <typeparam name="TU">Destination type.</typeparam>
|
||||
public static void DeepCopy<T, TU>(this T source, TU dest)
|
||||
where T : BaseItem
|
||||
where TU : BaseItem
|
||||
@@ -109,6 +111,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Copies all properties on newly created object. Skips properties that do not exist.
|
||||
/// </summary>
|
||||
/// <param name="source">The source object.</param>
|
||||
/// <typeparam name="T">Source type.</typeparam>
|
||||
/// <typeparam name="TU">Destination type.</typeparam>
|
||||
/// <returns>Destination object.</returns>
|
||||
public static TU DeepCopy<T, TU>(this T source)
|
||||
where T : BaseItem
|
||||
where TU : BaseItem, new()
|
||||
|
||||
@@ -15,6 +15,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public virtual string CollectionType => null;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
@@ -24,11 +30,5 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Common.Json;
|
||||
using Jellyfin.Extensions.Json;
|
||||
using MediaBrowser.Controller.IO;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
@@ -41,6 +41,23 @@ namespace MediaBrowser.Controller.Entities
|
||||
PhysicalFolderIds = Array.Empty<Guid>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display preferences id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Allow different display preferences for each collection folder.
|
||||
/// </remarks>
|
||||
/// <value>The display prefs id.</value>
|
||||
[JsonIgnore]
|
||||
public override Guid DisplayPreferencesId => Id;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string[] PhysicalLocations => PhysicalLocationsList;
|
||||
|
||||
public string[] PhysicalLocationsList { get; set; }
|
||||
|
||||
public Guid[] PhysicalFolderIds { get; set; }
|
||||
|
||||
public static IXmlSerializer XmlSerializer { get; set; }
|
||||
|
||||
public static IServerApplicationHost ApplicationHost { get; set; }
|
||||
@@ -63,6 +80,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override IEnumerable<BaseItem> Children => GetActualChildren();
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
@@ -77,8 +97,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
|
||||
if (result == null)
|
||||
if (XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) is not LibraryOptions result)
|
||||
{
|
||||
return new LibraryOptions();
|
||||
}
|
||||
@@ -160,23 +179,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display preferences id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Allow different display preferences for each collection folder.
|
||||
/// </remarks>
|
||||
/// <value>The display prefs id.</value>
|
||||
[JsonIgnore]
|
||||
public override Guid DisplayPreferencesId => Id;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string[] PhysicalLocations => PhysicalLocationsList;
|
||||
|
||||
public string[] PhysicalLocationsList { get; set; }
|
||||
|
||||
public Guid[] PhysicalFolderIds { get; set; }
|
||||
|
||||
public override bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
return true;
|
||||
@@ -373,8 +375,5 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
@@ -15,6 +15,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Adds the trailer URL.
|
||||
/// </summary>
|
||||
/// <param name="item">Media item.</param>
|
||||
/// <param name="url">Trailer URL.</param>
|
||||
public static void AddTrailerUrl(this BaseItem item, string url)
|
||||
{
|
||||
if (string.IsNullOrEmpty(url))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA1721, CA1819, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -165,6 +165,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public static ICollectionManager CollectionManager { get; set; }
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
if (IsRoot)
|
||||
@@ -206,9 +208,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Adds the child.
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <exception cref="InvalidOperationException">Unable to add + item.Name.</exception>
|
||||
public void AddChild(BaseItem item, CancellationToken cancellationToken)
|
||||
public void AddChild(BaseItem item)
|
||||
{
|
||||
item.SetParent(this);
|
||||
|
||||
@@ -232,7 +233,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
if (this is ICollectionFolder && !(this is BasePluginFolder))
|
||||
if (this is ICollectionFolder && this is not BasePluginFolder)
|
||||
{
|
||||
var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders);
|
||||
if (blockedMediaFolders.Length > 0)
|
||||
@@ -259,6 +260,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Loads our children. Validation will occur externally.
|
||||
/// We want this synchronous.
|
||||
/// </summary>
|
||||
/// <returns>Returns children.</returns>
|
||||
protected virtual List<BaseItem> LoadChildren()
|
||||
{
|
||||
// logger.LogDebug("Loading children from {0} {1} {2}", GetType().Name, Id, Path);
|
||||
@@ -301,7 +303,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
if (dictionary.ContainsKey(id))
|
||||
{
|
||||
Logger.LogError(
|
||||
"Found folder containing items with duplicate id. Path: {path}, Child Name: {ChildName}",
|
||||
"Found folder containing items with duplicate id. Path: {Path}, Child Name: {ChildName}",
|
||||
Path ?? Name,
|
||||
child.Path ?? child.Name);
|
||||
}
|
||||
@@ -423,7 +425,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (item.IsFileProtocol)
|
||||
{
|
||||
Logger.LogDebug("Removed item: " + item.Path);
|
||||
Logger.LogDebug("Removed item: {Path}", item.Path);
|
||||
|
||||
item.SetParent(null);
|
||||
LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, this, false);
|
||||
@@ -643,6 +645,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Get the children of this folder from the actual file system.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
/// <param name="directoryService">The directory service to use for operation.</param>
|
||||
/// <returns>Returns set of base items.</returns>
|
||||
protected virtual IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
|
||||
{
|
||||
var collectionType = LibraryManager.GetContentType(this);
|
||||
@@ -669,7 +673,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (LinkedChildren.Length > 0)
|
||||
{
|
||||
if (!(this is ICollectionFolder))
|
||||
if (this is not ICollectionFolder)
|
||||
{
|
||||
return GetChildren(user, true).Count;
|
||||
}
|
||||
@@ -726,7 +730,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
return PostFilterAndSort(items, query, true);
|
||||
}
|
||||
|
||||
if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty)
|
||||
if (this is not UserRootFolder && this is not AggregateFolder && query.ParentId == Guid.Empty)
|
||||
{
|
||||
query.Parent = this;
|
||||
}
|
||||
@@ -788,7 +792,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
private bool RequiresPostFiltering2(InternalItemsQuery query)
|
||||
{
|
||||
if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase))
|
||||
if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.BoxSet)
|
||||
{
|
||||
Logger.LogDebug("Query requires post-filtering due to BoxSet query");
|
||||
return true;
|
||||
@@ -801,9 +805,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (LinkedChildren.Length > 0)
|
||||
{
|
||||
if (!(this is ICollectionFolder))
|
||||
if (this is not ICollectionFolder)
|
||||
{
|
||||
Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name);
|
||||
Logger.LogDebug("{Type}: Query requires post-filtering due to LinkedChildren.", GetType().Name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -878,7 +882,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
if (query.IsPlayed.HasValue)
|
||||
{
|
||||
if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(nameof(Series)))
|
||||
if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(BaseItemKind.Series))
|
||||
{
|
||||
Logger.LogDebug("Query requires post-filtering due to IsPlayed");
|
||||
return true;
|
||||
@@ -999,8 +1003,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return PostFilterAndSort(items, query, true);
|
||||
}
|
||||
|
||||
public static ICollectionManager CollectionManager { get; set; }
|
||||
|
||||
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query, bool enableSorting)
|
||||
{
|
||||
var user = query.User;
|
||||
@@ -1011,20 +1013,22 @@ namespace MediaBrowser.Controller.Entities
|
||||
items = CollapseBoxSetItemsIfNeeded(items, query, this, user, ConfigurationManager, CollectionManager);
|
||||
}
|
||||
|
||||
#pragma warning disable CA1309
|
||||
if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater))
|
||||
{
|
||||
items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
|
||||
items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.InvariantCultureIgnoreCase) < 1);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query.NameStartsWith))
|
||||
{
|
||||
items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase));
|
||||
items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.InvariantCultureIgnoreCase));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(query.NameLessThan))
|
||||
{
|
||||
items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1);
|
||||
items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.InvariantCultureIgnoreCase) == 1);
|
||||
}
|
||||
#pragma warning restore CA1309
|
||||
|
||||
// This must be the last filter
|
||||
if (!string.IsNullOrEmpty(query.AdjacentTo))
|
||||
@@ -1097,7 +1101,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Movie", StringComparer.OrdinalIgnoreCase))
|
||||
if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(BaseItemKind.Movie))
|
||||
{
|
||||
param = true;
|
||||
}
|
||||
@@ -1385,18 +1389,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets allowed recursive children of an item.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
|
||||
/// <returns>IEnumerable{BaseItem}.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
|
||||
{
|
||||
return GetRecursiveChildren(user, null);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
|
||||
{
|
||||
if (user == null)
|
||||
@@ -1555,7 +1547,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var childOwner = child.GetOwner() ?? child;
|
||||
|
||||
if (childOwner != null && !(child is IItemByName))
|
||||
if (child is not IItemByName)
|
||||
{
|
||||
var childProtocol = childOwner.PathProtocol;
|
||||
if (!childProtocol.HasValue || childProtocol.Value != Model.MediaInfo.MediaProtocol.File)
|
||||
@@ -1679,7 +1671,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="datePlayed">The date played.</param>
|
||||
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
|
||||
/// <returns>Task.</returns>
|
||||
public override void MarkPlayed(
|
||||
User user,
|
||||
DateTime? datePlayed,
|
||||
@@ -1721,7 +1712,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Marks the unplayed.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task.</returns>
|
||||
public override void MarkUnplayed(User user)
|
||||
{
|
||||
var itemsResult = GetItemList(new InternalItemsQuery
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using Diacritics.Extensions;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
@@ -66,10 +66,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.GenreIds = new[] { Id };
|
||||
query.ExcludeItemTypes = new[]
|
||||
{
|
||||
nameof(MusicVideo),
|
||||
nameof(Entities.Audio.Audio),
|
||||
nameof(MusicAlbum),
|
||||
nameof(MusicArtist)
|
||||
BaseItemKind.MusicVideo,
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum,
|
||||
BaseItemKind.MusicArtist
|
||||
};
|
||||
|
||||
return LibraryManager.GetItemList(query);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
using System;
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Gets the media sources.
|
||||
/// </summary>
|
||||
/// <param name="enablePathSubstitution"><c>true</c> to enable path substitution, <c>false</c> to not.</param>
|
||||
/// <returns>A list of media sources.</returns>
|
||||
List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
|
||||
|
||||
List<MediaStream> GetMediaStreams();
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// The item has screenshots.
|
||||
/// </summary>
|
||||
public interface IHasScreenshots
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
public interface IHasSpecialFeatures
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the special feature ids.
|
||||
/// Gets the special feature ids.
|
||||
/// </summary>
|
||||
/// <value>The special feature ids.</value>
|
||||
IReadOnlyList<Guid> SpecialFeatureIds { get; set; }
|
||||
IReadOnlyList<Guid> SpecialFeatureIds { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
@@ -17,18 +16,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the local trailer ids.
|
||||
/// Gets the local trailers.
|
||||
/// </summary>
|
||||
/// <value>The local trailer ids.</value>
|
||||
IReadOnlyList<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the remote trailer ids.
|
||||
/// </summary>
|
||||
/// <value>The remote trailer ids.</value>
|
||||
IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
|
||||
|
||||
Guid Id { get; set; }
|
||||
/// <value>The local trailers.</value>
|
||||
IReadOnlyList<BaseItem> LocalTrailers { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -39,57 +30,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Gets the trailer count.
|
||||
/// </summary>
|
||||
/// <param name="item">Media item.</param>
|
||||
/// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
|
||||
public static int GetTrailerCount(this IHasTrailers item)
|
||||
=> item.LocalTrailerIds.Count + item.RemoteTrailerIds.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trailer ids.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
|
||||
public static IReadOnlyList<Guid> GetTrailerIds(this IHasTrailers item)
|
||||
{
|
||||
var localIds = item.LocalTrailerIds;
|
||||
var remoteIds = item.RemoteTrailerIds;
|
||||
|
||||
var all = new Guid[localIds.Count + remoteIds.Count];
|
||||
var index = 0;
|
||||
foreach (var id in localIds)
|
||||
{
|
||||
all[index++] = id;
|
||||
}
|
||||
|
||||
foreach (var id in remoteIds)
|
||||
{
|
||||
all[index++] = id;
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the trailers.
|
||||
/// </summary>
|
||||
/// <returns><see cref="IReadOnlyList{BaseItem}" />.</returns>
|
||||
public static IReadOnlyList<BaseItem> GetTrailers(this IHasTrailers item)
|
||||
{
|
||||
var localIds = item.LocalTrailerIds;
|
||||
var remoteIds = item.RemoteTrailerIds;
|
||||
var libraryManager = BaseItem.LibraryManager;
|
||||
|
||||
var all = new BaseItem[localIds.Count + remoteIds.Count];
|
||||
var index = 0;
|
||||
foreach (var id in localIds)
|
||||
{
|
||||
all[index++] = libraryManager.GetItemById(id);
|
||||
}
|
||||
|
||||
foreach (var id in remoteIds)
|
||||
{
|
||||
all[index++] = libraryManager.GetItemById(id);
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
=> item.LocalTrailers.Count + item.RemoteTrailers.Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1044, CA1819, CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -12,6 +12,55 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class InternalItemsQuery
|
||||
{
|
||||
public InternalItemsQuery()
|
||||
{
|
||||
AlbumArtistIds = Array.Empty<Guid>();
|
||||
AlbumIds = Array.Empty<Guid>();
|
||||
AncestorIds = Array.Empty<Guid>();
|
||||
ArtistIds = Array.Empty<Guid>();
|
||||
BlockUnratedItems = Array.Empty<UnratedItem>();
|
||||
BoxSetLibraryFolders = Array.Empty<Guid>();
|
||||
ChannelIds = Array.Empty<Guid>();
|
||||
ContributingArtistIds = Array.Empty<Guid>();
|
||||
DtoOptions = new DtoOptions();
|
||||
EnableTotalRecordCount = true;
|
||||
ExcludeArtistIds = Array.Empty<Guid>();
|
||||
ExcludeInheritedTags = Array.Empty<string>();
|
||||
ExcludeItemIds = Array.Empty<Guid>();
|
||||
ExcludeItemTypes = Array.Empty<BaseItemKind>();
|
||||
ExcludeTags = Array.Empty<string>();
|
||||
GenreIds = Array.Empty<Guid>();
|
||||
Genres = Array.Empty<string>();
|
||||
GroupByPresentationUniqueKey = true;
|
||||
ImageTypes = Array.Empty<ImageType>();
|
||||
IncludeItemTypes = Array.Empty<BaseItemKind>();
|
||||
ItemIds = Array.Empty<Guid>();
|
||||
MediaTypes = Array.Empty<string>();
|
||||
MinSimilarityScore = 20;
|
||||
OfficialRatings = Array.Empty<string>();
|
||||
OrderBy = Array.Empty<ValueTuple<string, SortOrder>>();
|
||||
PersonIds = Array.Empty<Guid>();
|
||||
PersonTypes = Array.Empty<string>();
|
||||
PresetViews = Array.Empty<string>();
|
||||
SeriesStatuses = Array.Empty<SeriesStatus>();
|
||||
SourceTypes = Array.Empty<SourceType>();
|
||||
StudioIds = Array.Empty<Guid>();
|
||||
Tags = Array.Empty<string>();
|
||||
TopParentIds = Array.Empty<Guid>();
|
||||
TrailerTypes = Array.Empty<TrailerType>();
|
||||
VideoTypes = Array.Empty<VideoType>();
|
||||
Years = Array.Empty<int>();
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User? user)
|
||||
: this()
|
||||
{
|
||||
if (user != null)
|
||||
{
|
||||
SetUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Recursive { get; set; }
|
||||
|
||||
public int? StartIndex { get; set; }
|
||||
@@ -38,9 +87,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public string[] MediaTypes { get; set; }
|
||||
|
||||
public string[] IncludeItemTypes { get; set; }
|
||||
public BaseItemKind[] IncludeItemTypes { get; set; }
|
||||
|
||||
public string[] ExcludeItemTypes { get; set; }
|
||||
public BaseItemKind[] ExcludeItemTypes { get; set; }
|
||||
|
||||
public string[] ExcludeTags { get; set; }
|
||||
|
||||
@@ -180,29 +229,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public Guid ParentId { get; set; }
|
||||
|
||||
public string? ParentType { get; set; }
|
||||
public BaseItemKind? ParentType { get; set; }
|
||||
|
||||
public Guid[] AncestorIds { get; set; }
|
||||
|
||||
public Guid[] TopParentIds { get; set; }
|
||||
|
||||
public BaseItem? Parent
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
ParentId = Guid.Empty;
|
||||
ParentType = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentId = value.Id;
|
||||
ParentType = value.GetType().Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string[] PresetViews { get; set; }
|
||||
|
||||
public TrailerType[] TrailerTypes { get; set; }
|
||||
@@ -270,72 +302,23 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public bool? DisplayAlbumFolders { get; set; }
|
||||
|
||||
public InternalItemsQuery()
|
||||
public BaseItem? Parent
|
||||
{
|
||||
AlbumArtistIds = Array.Empty<Guid>();
|
||||
AlbumIds = Array.Empty<Guid>();
|
||||
AncestorIds = Array.Empty<Guid>();
|
||||
ArtistIds = Array.Empty<Guid>();
|
||||
BlockUnratedItems = Array.Empty<UnratedItem>();
|
||||
BoxSetLibraryFolders = Array.Empty<Guid>();
|
||||
ChannelIds = Array.Empty<Guid>();
|
||||
ContributingArtistIds = Array.Empty<Guid>();
|
||||
DtoOptions = new DtoOptions();
|
||||
EnableTotalRecordCount = true;
|
||||
ExcludeArtistIds = Array.Empty<Guid>();
|
||||
ExcludeInheritedTags = Array.Empty<string>();
|
||||
ExcludeItemIds = Array.Empty<Guid>();
|
||||
ExcludeItemTypes = Array.Empty<string>();
|
||||
ExcludeTags = Array.Empty<string>();
|
||||
GenreIds = Array.Empty<Guid>();
|
||||
Genres = Array.Empty<string>();
|
||||
GroupByPresentationUniqueKey = true;
|
||||
ImageTypes = Array.Empty<ImageType>();
|
||||
IncludeItemTypes = Array.Empty<string>();
|
||||
ItemIds = Array.Empty<Guid>();
|
||||
MediaTypes = Array.Empty<string>();
|
||||
MinSimilarityScore = 20;
|
||||
OfficialRatings = Array.Empty<string>();
|
||||
OrderBy = Array.Empty<ValueTuple<string, SortOrder>>();
|
||||
PersonIds = Array.Empty<Guid>();
|
||||
PersonTypes = Array.Empty<string>();
|
||||
PresetViews = Array.Empty<string>();
|
||||
SeriesStatuses = Array.Empty<SeriesStatus>();
|
||||
SourceTypes = Array.Empty<SourceType>();
|
||||
StudioIds = Array.Empty<Guid>();
|
||||
Tags = Array.Empty<string>();
|
||||
TopParentIds = Array.Empty<Guid>();
|
||||
TrailerTypes = Array.Empty<TrailerType>();
|
||||
VideoTypes = Array.Empty<VideoType>();
|
||||
Years = Array.Empty<int>();
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User? user)
|
||||
: this()
|
||||
{
|
||||
if (user != null)
|
||||
set
|
||||
{
|
||||
SetUser(user);
|
||||
if (value == null)
|
||||
{
|
||||
ParentId = Guid.Empty;
|
||||
ParentType = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParentId = value.Id;
|
||||
ParentType = value.GetBaseItemKind();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUser(User user)
|
||||
{
|
||||
MaxParentalRating = user.MaxParentalAgeRating;
|
||||
|
||||
if (MaxParentalRating.HasValue)
|
||||
{
|
||||
string other = UnratedItem.Other.ToString();
|
||||
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
|
||||
.Where(i => i != other)
|
||||
.Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
|
||||
}
|
||||
|
||||
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
|
||||
|
||||
User = user;
|
||||
}
|
||||
|
||||
public Dictionary<string, string>? HasAnyProviderId { get; set; }
|
||||
|
||||
public Guid[] AlbumArtistIds { get; set; }
|
||||
@@ -361,5 +344,22 @@ namespace MediaBrowser.Controller.Entities
|
||||
public string? SearchTerm { get; set; }
|
||||
|
||||
public string? SeriesTimerId { get; set; }
|
||||
|
||||
public void SetUser(User user)
|
||||
{
|
||||
MaxParentalRating = user.MaxParentalAgeRating;
|
||||
|
||||
if (MaxParentalRating.HasValue)
|
||||
{
|
||||
string other = UnratedItem.Other.ToString();
|
||||
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
|
||||
.Where(i => i != other)
|
||||
.Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
|
||||
}
|
||||
|
||||
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
|
||||
|
||||
User = user;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1721, CA1819, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -9,7 +9,6 @@ using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Movies
|
||||
@@ -21,10 +20,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
{
|
||||
public BoxSet()
|
||||
{
|
||||
RemoteTrailers = Array.Empty<MediaUrl>();
|
||||
LocalTrailerIds = Array.Empty<Guid>();
|
||||
RemoteTrailerIds = Array.Empty<Guid>();
|
||||
|
||||
DisplayOrder = ItemSortBy.PremiereDate;
|
||||
}
|
||||
|
||||
@@ -38,10 +33,9 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
public override bool SupportsPeople => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
|
||||
public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
|
||||
.Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
|
||||
.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display order.
|
||||
@@ -49,6 +43,30 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
/// <value>The display order.</value>
|
||||
public string DisplayOrder { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
private bool IsLegacyBoxSet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LinkedChildren.Length > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
public Guid[] LibraryFolderIds { get; set; }
|
||||
|
||||
protected override bool GetBlockUnratedValue(User user)
|
||||
{
|
||||
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie);
|
||||
@@ -83,28 +101,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool IsLegacyBoxSet
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(Path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LinkedChildren.Length > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
public override bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
|
||||
{
|
||||
return true;
|
||||
@@ -191,8 +187,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
return IsVisible(user);
|
||||
}
|
||||
|
||||
public Guid[] LibraryFolderIds { get; set; }
|
||||
|
||||
private Guid[] GetLibraryFolderIds(User user)
|
||||
{
|
||||
return LibraryManager.GetUserRootFolder().GetChildren(user, true)
|
||||
|
||||
@@ -7,12 +7,9 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.Providers;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities.Movies
|
||||
@@ -22,22 +19,16 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
/// </summary>
|
||||
public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
|
||||
{
|
||||
public Movie()
|
||||
{
|
||||
SpecialFeatureIds = Array.Empty<Guid>();
|
||||
RemoteTrailers = Array.Empty<MediaUrl>();
|
||||
LocalTrailerIds = Array.Empty<Guid>();
|
||||
RemoteTrailerIds = Array.Empty<Guid>();
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> SpecialFeatureIds => GetExtras()
|
||||
.Where(extra => extra.ExtraType != null && extra is Video)
|
||||
.Select(extra => extra.Id)
|
||||
.ToArray();
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> SpecialFeatureIds { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
|
||||
public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
|
||||
.Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
|
||||
.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the TMDB collection.
|
||||
@@ -66,54 +57,6 @@ namespace MediaBrowser.Controller.Entities.Movies
|
||||
return 2.0 / 3;
|
||||
}
|
||||
|
||||
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Must have a parent to have special features
|
||||
// In other words, it must be part of the Parent/Child tree
|
||||
if (IsFileProtocol && SupportsOwnedItems && !IsInMixedFolder)
|
||||
{
|
||||
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (specialFeaturesChanged)
|
||||
{
|
||||
hasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
|
||||
var newItemIds = newItems.Select(i => i.Id).ToArray();
|
||||
|
||||
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
|
||||
|
||||
var ownerId = Id;
|
||||
|
||||
var tasks = newItems.Select(i =>
|
||||
{
|
||||
var subOptions = new MetadataRefreshOptions(options);
|
||||
|
||||
if (i.OwnerId != ownerId)
|
||||
{
|
||||
i.OwnerId = ownerId;
|
||||
subOptions.ForceSave = true;
|
||||
}
|
||||
|
||||
return RefreshMetadataForOwnedItem(i, false, subOptions, cancellationToken);
|
||||
});
|
||||
|
||||
await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
SpecialFeatureIds = newItemIds;
|
||||
|
||||
return itemsChanged;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using Diacritics.Extensions;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -16,6 +16,26 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class Person : BaseItem, IItemByName, IHasLookupInfo<PersonLookupInfo>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to enable alpha numeric sorting.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public override bool EnableAlphaNumericSorting => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
@@ -49,14 +69,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return LibraryManager.GetItemList(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
@@ -67,18 +79,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to enable alpha numeric sorting.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public override bool EnableAlphaNumericSorting => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
public static string GetPath(string name)
|
||||
{
|
||||
return GetPath(name, true);
|
||||
@@ -129,6 +129,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <param name="replaceAllMetadata"><c>true</c> to replace all metadata, <c>false</c> to not.</param>
|
||||
/// <returns><c>true</c> if changes were made, <c>false</c> if not.</returns>
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -36,6 +36,30 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public string CameraMake { get; set; }
|
||||
|
||||
public string CameraModel { get; set; }
|
||||
|
||||
public string Software { get; set; }
|
||||
|
||||
public double? ExposureTime { get; set; }
|
||||
|
||||
public double? FocalLength { get; set; }
|
||||
|
||||
public ImageOrientation? Orientation { get; set; }
|
||||
|
||||
public double? Aperture { get; set; }
|
||||
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
public double? Latitude { get; set; }
|
||||
|
||||
public double? Longitude { get; set; }
|
||||
|
||||
public double? Altitude { get; set; }
|
||||
|
||||
public int? IsoSpeedRating { get; set; }
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
return true;
|
||||
@@ -69,29 +93,5 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
return base.GetDefaultPrimaryImageAspectRatio();
|
||||
}
|
||||
|
||||
public string CameraMake { get; set; }
|
||||
|
||||
public string CameraModel { get; set; }
|
||||
|
||||
public string Software { get; set; }
|
||||
|
||||
public double? ExposureTime { get; set; }
|
||||
|
||||
public double? FocalLength { get; set; }
|
||||
|
||||
public ImageOrientation? Orientation { get; set; }
|
||||
|
||||
public double? Aperture { get; set; }
|
||||
|
||||
public double? ShutterSpeed { get; set; }
|
||||
|
||||
public double? Latitude { get; set; }
|
||||
|
||||
public double? Longitude { get; set; }
|
||||
|
||||
public double? Altitude { get; set; }
|
||||
|
||||
public int? IsoSpeedRating { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using Diacritics.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
@@ -15,19 +15,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class Studio : BaseItem, IItemByName
|
||||
{
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||
return list;
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
return GetUserDataKeys()[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
@@ -42,6 +29,22 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
|
||||
return list;
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
return GetUserDataKeys()[0];
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
double value = 16;
|
||||
@@ -67,9 +70,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return LibraryManager.GetItemList(query);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public static string GetPath(string name)
|
||||
{
|
||||
return GetPath(name, true);
|
||||
@@ -105,6 +105,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <param name="replaceAllMetadata"><c>true</c> to replace all metadata, <c>false</c> to not.</param>
|
||||
/// <returns><c>true</c> if changes were made, <c>false</c> if not.</returns>
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
|
||||
|
||||
@@ -20,18 +20,10 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// </summary>
|
||||
public class Episode : Video, IHasTrailers, IHasLookupInfo<EpisodeInfo>, IHasSeries
|
||||
{
|
||||
public Episode()
|
||||
{
|
||||
RemoteTrailers = Array.Empty<MediaUrl>();
|
||||
LocalTrailerIds = Array.Empty<Guid>();
|
||||
RemoteTrailerIds = Array.Empty<Guid>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
|
||||
public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
|
||||
.Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
|
||||
.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the season in which it aired.
|
||||
@@ -49,12 +41,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <value>The index number.</value>
|
||||
public int? IndexNumberEnd { get; set; }
|
||||
|
||||
public string FindSeriesSortName()
|
||||
{
|
||||
var series = Series;
|
||||
return series == null ? SeriesName : series.SortName;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
protected override bool SupportsOwnedItems => IsStacked || MediaSourceCount > 1;
|
||||
|
||||
@@ -76,45 +62,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
[JsonIgnore]
|
||||
protected override bool EnableDefaultVideoUserDataKeys => false;
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
// hack for tv plugins
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 16.0 / 9;
|
||||
}
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
var series = Series;
|
||||
if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
|
||||
{
|
||||
var seriesUserDataKeys = series.GetUserDataKeys();
|
||||
var take = seriesUserDataKeys.Count;
|
||||
if (seriesUserDataKeys.Count > 1)
|
||||
{
|
||||
take--;
|
||||
}
|
||||
|
||||
var newList = seriesUserDataKeys.GetRange(0, take);
|
||||
var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
|
||||
for (int i = 0; i < take; i++)
|
||||
{
|
||||
newList[i] = newList[i] + suffix;
|
||||
}
|
||||
|
||||
newList.AddRange(list);
|
||||
list = newList;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Episode's Series Instance.
|
||||
/// </summary>
|
||||
@@ -161,6 +108,74 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
[JsonIgnore]
|
||||
public string SeasonName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsRemoteImageDownloading
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsMissingEpisode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsMissingEpisode => LocationType == LocationType.Virtual;
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeasonId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public string FindSeriesSortName()
|
||||
{
|
||||
var series = Series;
|
||||
return series == null ? SeriesName : series.SortName;
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
// hack for tv plugins
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 16.0 / 9;
|
||||
}
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
var series = Series;
|
||||
if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
|
||||
{
|
||||
var seriesUserDataKeys = series.GetUserDataKeys();
|
||||
var take = seriesUserDataKeys.Count;
|
||||
if (seriesUserDataKeys.Count > 1)
|
||||
{
|
||||
take--;
|
||||
}
|
||||
|
||||
var newList = seriesUserDataKeys.GetRange(0, take);
|
||||
var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
|
||||
for (int i = 0; i < take; i++)
|
||||
{
|
||||
newList[i] = newList[i] + suffix;
|
||||
}
|
||||
|
||||
newList.AddRange(list);
|
||||
list = newList;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public string FindSeriesPresentationUniqueKey()
|
||||
{
|
||||
var series = Series;
|
||||
@@ -242,29 +257,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
return false;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsRemoteImageDownloading
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsMissingEpisode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsMissingEpisode => LocationType == LocationType.Virtual;
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeasonId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public Guid FindSeriesId()
|
||||
{
|
||||
var series = FindParent<Series>();
|
||||
|
||||
@@ -38,6 +38,50 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
[JsonIgnore]
|
||||
public override Guid DisplayParentId => SeriesId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets this Episode's Series Instance.
|
||||
/// </summary>
|
||||
/// <value>The series.</value>
|
||||
[JsonIgnore]
|
||||
public Series Series
|
||||
{
|
||||
get
|
||||
{
|
||||
var seriesId = SeriesId;
|
||||
if (seriesId == Guid.Empty)
|
||||
{
|
||||
seriesId = FindSeriesId();
|
||||
}
|
||||
|
||||
return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = Series;
|
||||
|
||||
if (series != null)
|
||||
{
|
||||
return series.Path;
|
||||
}
|
||||
|
||||
return System.IO.Path.GetDirectoryName(Path);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPresentationUniqueKey { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
double value = 2;
|
||||
@@ -80,41 +124,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets this Episode's Series Instance.
|
||||
/// </summary>
|
||||
/// <value>The series.</value>
|
||||
[JsonIgnore]
|
||||
public Series Series
|
||||
{
|
||||
get
|
||||
{
|
||||
var seriesId = SeriesId;
|
||||
if (seriesId == Guid.Empty)
|
||||
{
|
||||
seriesId = FindSeriesId();
|
||||
}
|
||||
|
||||
return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPath
|
||||
{
|
||||
get
|
||||
{
|
||||
var series = Series;
|
||||
|
||||
if (series != null)
|
||||
{
|
||||
return series.Path;
|
||||
}
|
||||
|
||||
return System.IO.Path.GetDirectoryName(Path);
|
||||
}
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
if (IndexNumber.HasValue)
|
||||
@@ -157,6 +166,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <summary>
|
||||
/// Gets the episodes.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="options">The options to use.</param>
|
||||
/// <returns>Set of episodes.</returns>
|
||||
public List<BaseItem> GetEpisodes(User user, DtoOptions options)
|
||||
{
|
||||
return GetEpisodes(Series, user, options);
|
||||
@@ -193,15 +205,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
return UnratedItem.Series;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesPresentationUniqueKey { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string SeriesName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public string FindSeriesPresentationUniqueKey()
|
||||
{
|
||||
var series = Series;
|
||||
@@ -241,6 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <param name="replaceAllMetadata"><c>true</c> to replace metdata, <c>false</c> to not.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
|
||||
@@ -27,9 +27,6 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
public Series()
|
||||
{
|
||||
RemoteTrailers = Array.Empty<MediaUrl>();
|
||||
LocalTrailerIds = Array.Empty<Guid>();
|
||||
RemoteTrailerIds = Array.Empty<Guid>();
|
||||
AirDays = Array.Empty<DayOfWeek>();
|
||||
}
|
||||
|
||||
@@ -53,10 +50,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
public override bool SupportsPeople => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
|
||||
public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
|
||||
.Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
|
||||
.ToArray();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display order.
|
||||
@@ -72,6 +68,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <value>The status.</value>
|
||||
public SeriesStatus? Status { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool StopRefreshIfLocalMetadataFound => false;
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
double value = 2;
|
||||
@@ -128,7 +127,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
AncestorWithPresentationUniqueKey = null,
|
||||
SeriesPresentationUniqueKey = seriesKey,
|
||||
IncludeItemTypes = new[] { nameof(Season) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Season },
|
||||
IsVirtualItem = false,
|
||||
Limit = 0,
|
||||
DtoOptions = new DtoOptions(false)
|
||||
@@ -156,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
if (query.IncludeItemTypes.Length == 0)
|
||||
{
|
||||
query.IncludeItemTypes = new[] { nameof(Episode) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Episode };
|
||||
}
|
||||
|
||||
query.IsVirtualItem = false;
|
||||
@@ -210,7 +209,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
query.AncestorWithPresentationUniqueKey = null;
|
||||
query.SeriesPresentationUniqueKey = seriesKey;
|
||||
query.IncludeItemTypes = new[] { nameof(Season) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Season };
|
||||
query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
|
||||
|
||||
if (user != null && !user.DisplayMissingEpisodes)
|
||||
@@ -236,7 +235,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
if (query.IncludeItemTypes.Length == 0)
|
||||
{
|
||||
query.IncludeItemTypes = new[] { nameof(Episode), nameof(Season) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season };
|
||||
}
|
||||
|
||||
query.IsVirtualItem = false;
|
||||
@@ -256,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
AncestorWithPresentationUniqueKey = null,
|
||||
SeriesPresentationUniqueKey = seriesKey,
|
||||
IncludeItemTypes = new[] { nameof(Episode), nameof(Season) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season },
|
||||
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
|
||||
DtoOptions = options
|
||||
};
|
||||
@@ -293,7 +292,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
// Refresh seasons
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (!(item is Season))
|
||||
if (item is not Season)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -360,7 +359,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
|
||||
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
|
||||
IncludeItemTypes = new[] { nameof(Episode) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode },
|
||||
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
|
||||
DtoOptions = options
|
||||
};
|
||||
@@ -394,6 +393,10 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <summary>
|
||||
/// Filters the episodes by season.
|
||||
/// </summary>
|
||||
/// <param name="episodes">The episodes.</param>
|
||||
/// <param name="parentSeason">The season.</param>
|
||||
/// <param name="includeSpecials"><c>true</c> to include special, <c>false</c> to not.</param>
|
||||
/// <returns>The set of episodes.</returns>
|
||||
public static IEnumerable<BaseItem> FilterEpisodesBySeason(IEnumerable<BaseItem> episodes, Season parentSeason, bool includeSpecials)
|
||||
{
|
||||
var seasonNumber = parentSeason.IndexNumber;
|
||||
@@ -424,6 +427,10 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// <summary>
|
||||
/// Filters the episodes by season.
|
||||
/// </summary>
|
||||
/// <param name="episodes">The episodes.</param>
|
||||
/// <param name="seasonNumber">The season.</param>
|
||||
/// <param name="includeSpecials"><c>true</c> to include special, <c>false</c> to not.</param>
|
||||
/// <returns>The set of episodes.</returns>
|
||||
public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, int seasonNumber, bool includeSpecials)
|
||||
{
|
||||
if (!includeSpecials || seasonNumber < 1)
|
||||
@@ -499,8 +506,5 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool StopRefreshIfLocalMetadataFound => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Jellyfin.Extensions;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
@@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
var current = item.Tags;
|
||||
|
||||
if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
|
||||
if (!current.Contains(name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (current.Length == 0)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1819, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -23,6 +23,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
TrailerTypes = Array.Empty<TrailerType>();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool StopRefreshIfLocalMetadataFound => false;
|
||||
|
||||
public TrailerType[] TrailerTypes { get; set; }
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
@@ -97,8 +100,5 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool StopRefreshIfLocalMetadataFound => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,13 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class UserItemData
|
||||
{
|
||||
public const double MinLikeValue = 6.5;
|
||||
|
||||
/// <summary>
|
||||
/// The _rating.
|
||||
/// </summary>
|
||||
private double? _rating;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the user id.
|
||||
/// </summary>
|
||||
@@ -24,11 +31,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The key.</value>
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The _rating.
|
||||
/// </summary>
|
||||
private double? _rating;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the users 0-10 rating.
|
||||
/// </summary>
|
||||
@@ -93,8 +95,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The index of the subtitle stream.</value>
|
||||
public int? SubtitleStreamIndex { get; set; }
|
||||
|
||||
public const double MinLikeValue = 6.5;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the item is liked or not.
|
||||
/// This should never be serialized.
|
||||
|
||||
@@ -21,8 +21,36 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class UserRootFolder : Folder
|
||||
{
|
||||
private List<Guid> _childrenIds = null;
|
||||
private readonly object _childIdsLock = new object();
|
||||
private List<Guid> _childrenIds = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UserRootFolder"/> class.
|
||||
/// </summary>
|
||||
public UserRootFolder()
|
||||
{
|
||||
IsRoot = true;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
[JsonIgnore]
|
||||
protected override bool SupportsShortcutChildren => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
private void ClearCache()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
{
|
||||
_childrenIds = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override List<BaseItem> LoadChildren()
|
||||
{
|
||||
@@ -39,20 +67,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
private void ClearCache()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
{
|
||||
_childrenIds = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
@@ -74,12 +88,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return GetChildren(user, true).Count;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
protected override bool SupportsShortcutChildren => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||
{
|
||||
var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList();
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Querying;
|
||||
|
||||
@@ -15,6 +16,25 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class UserView : Folder, IHasCollectionType
|
||||
{
|
||||
private static readonly string[] _viewTypesEligibleForGrouping = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Movies,
|
||||
Model.Entities.CollectionType.TvShows,
|
||||
string.Empty
|
||||
};
|
||||
|
||||
private static readonly string[] _originalFolderViewTypes = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Books,
|
||||
Model.Entities.CollectionType.MusicVideos,
|
||||
Model.Entities.CollectionType.HomeVideos,
|
||||
Model.Entities.CollectionType.Photos,
|
||||
Model.Entities.CollectionType.Music,
|
||||
Model.Entities.CollectionType.BoxSets
|
||||
};
|
||||
|
||||
public static ITVSeriesManager TVSeriesManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the view type.
|
||||
/// </summary>
|
||||
@@ -30,12 +50,22 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public Guid? UserId { get; set; }
|
||||
|
||||
public static ITVSeriesManager TVSeriesManager;
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public string CollectionType => ViewType;
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<Guid> GetIdsForAncestorQuery()
|
||||
{
|
||||
@@ -53,17 +83,13 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => false;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPlayedStatus => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetChildCount(User user)
|
||||
{
|
||||
return GetChildren(user, true).Count;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||
{
|
||||
var parent = this as Folder;
|
||||
@@ -77,10 +103,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
|
||||
}
|
||||
|
||||
return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager)
|
||||
return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager)
|
||||
.GetUserItems(parent, this, CollectionType, query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
|
||||
{
|
||||
query ??= new InternalItemsQuery(user);
|
||||
@@ -91,16 +118,19 @@ namespace MediaBrowser.Controller.Entities
|
||||
return result.ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
|
||||
{
|
||||
query.SetUser(user);
|
||||
@@ -111,32 +141,26 @@ namespace MediaBrowser.Controller.Entities
|
||||
return GetItemList(query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
|
||||
{
|
||||
return GetChildren(user, false);
|
||||
}
|
||||
|
||||
private static readonly string[] UserSpecificViewTypes = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Playlists
|
||||
};
|
||||
|
||||
public static bool IsUserSpecific(Folder folder)
|
||||
{
|
||||
var collectionFolder = folder as ICollectionFolder;
|
||||
|
||||
if (collectionFolder == null)
|
||||
if (folder is not ICollectionFolder collectionFolder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var supportsUserSpecific = folder as ISupportsUserSpecificView;
|
||||
if (supportsUserSpecific != null && supportsUserSpecific.EnableUserSpecificView)
|
||||
if (folder is ISupportsUserSpecificView supportsUserSpecific
|
||||
&& supportsUserSpecific.EnableUserSpecificView)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return UserSpecificViewTypes.Contains(collectionFolder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return string.Equals(Model.Entities.CollectionType.Playlists, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool IsEligibleForGrouping(Folder folder)
|
||||
@@ -145,39 +169,19 @@ namespace MediaBrowser.Controller.Entities
|
||||
&& IsEligibleForGrouping(collectionFolder.CollectionType);
|
||||
}
|
||||
|
||||
private static string[] ViewTypesEligibleForGrouping = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Movies,
|
||||
Model.Entities.CollectionType.TvShows,
|
||||
string.Empty
|
||||
};
|
||||
|
||||
public static bool IsEligibleForGrouping(string viewType)
|
||||
{
|
||||
return ViewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return _viewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static string[] OriginalFolderViewTypes = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Books,
|
||||
Model.Entities.CollectionType.MusicVideos,
|
||||
Model.Entities.CollectionType.HomeVideos,
|
||||
Model.Entities.CollectionType.Photos,
|
||||
Model.Entities.CollectionType.Music,
|
||||
Model.Entities.CollectionType.BoxSets
|
||||
};
|
||||
|
||||
public static bool EnableOriginalFolder(string viewType)
|
||||
{
|
||||
return OriginalFolderViewTypes.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return _originalFolderViewTypes.Contains(viewType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities.Movies;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.Model.Entities;
|
||||
@@ -17,8 +16,6 @@ using MediaBrowser.Model.Querying;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
|
||||
using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
|
||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
@@ -30,22 +27,19 @@ namespace MediaBrowser.Controller.Entities
|
||||
private readonly ILogger<BaseItem> _logger;
|
||||
private readonly IUserDataManager _userDataManager;
|
||||
private readonly ITVSeriesManager _tvSeriesManager;
|
||||
private readonly IServerConfigurationManager _config;
|
||||
|
||||
public UserViewBuilder(
|
||||
IUserViewManager userViewManager,
|
||||
ILibraryManager libraryManager,
|
||||
ILogger<BaseItem> logger,
|
||||
IUserDataManager userDataManager,
|
||||
ITVSeriesManager tvSeriesManager,
|
||||
IServerConfigurationManager config)
|
||||
ITVSeriesManager tvSeriesManager)
|
||||
{
|
||||
_userViewManager = userViewManager;
|
||||
_libraryManager = libraryManager;
|
||||
_logger = logger;
|
||||
_userDataManager = userDataManager;
|
||||
_tvSeriesManager = tvSeriesManager;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public QueryResult<BaseItem> GetUserItems(Folder queryParent, Folder displayParent, string viewType, InternalItemsQuery query)
|
||||
@@ -65,7 +59,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
switch (viewType)
|
||||
{
|
||||
case CollectionType.Folders:
|
||||
return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), queryParent, query);
|
||||
return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query);
|
||||
|
||||
case CollectionType.TvShows:
|
||||
return GetTvView(queryParent, user, query);
|
||||
@@ -110,7 +104,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
return GetMovieMovies(queryParent, user, query);
|
||||
|
||||
case SpecialFolder.MovieCollections:
|
||||
return GetMovieCollections(queryParent, user, query);
|
||||
return GetMovieCollections(user, query);
|
||||
|
||||
case SpecialFolder.TvFavoriteEpisodes:
|
||||
return GetFavoriteEpisodes(queryParent, user, query);
|
||||
@@ -122,7 +116,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (queryParent is UserView)
|
||||
{
|
||||
return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), queryParent, query);
|
||||
return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), query);
|
||||
}
|
||||
|
||||
return queryParent.GetItems(query);
|
||||
@@ -144,7 +138,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
if (query.IncludeItemTypes.Length == 0)
|
||||
{
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
}
|
||||
|
||||
return parent.QueryRecursive(query);
|
||||
@@ -160,7 +154,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
GetUserView(SpecialFolder.MovieGenres, "Genres", "5", parent)
|
||||
};
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
return GetResult(list, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
|
||||
@@ -169,7 +163,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -180,7 +174,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { nameof(Series) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Series };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -191,7 +185,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.IsFavorite = true;
|
||||
query.IncludeItemTypes = new[] { nameof(Episode) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Episode };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -202,15 +196,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query)
|
||||
private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
|
||||
{
|
||||
query.Parent = null;
|
||||
query.IncludeItemTypes = new[] { nameof(BoxSet) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
|
||||
query.SetUser(user);
|
||||
query.Recursive = true;
|
||||
|
||||
@@ -224,7 +218,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.Limit = GetSpecialItemsLimit();
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
|
||||
return ConvertToResult(_libraryManager.GetItemList(query));
|
||||
}
|
||||
@@ -237,7 +231,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.Limit = GetSpecialItemsLimit();
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
|
||||
return ConvertToResult(_libraryManager.GetItemList(query));
|
||||
}
|
||||
@@ -256,7 +250,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { nameof(Movie) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Movie },
|
||||
Recursive = true,
|
||||
EnableTotalRecordCount = false
|
||||
}).Items
|
||||
@@ -275,9 +269,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserViewWithName(i.Name, SpecialFolder.MovieGenre, i.SortName, parent));
|
||||
.Select(i => GetUserViewWithName(SpecialFolder.MovieGenre, i.SortName, parent));
|
||||
|
||||
return GetResult(genres, parent, query);
|
||||
return GetResult(genres, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
|
||||
@@ -287,7 +281,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.GenreIds = new[] { displayParent.Id };
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { nameof(Movie) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -303,9 +297,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
query.IncludeItemTypes = new[]
|
||||
{
|
||||
nameof(Series),
|
||||
nameof(Season),
|
||||
nameof(Episode)
|
||||
BaseItemKind.Series,
|
||||
BaseItemKind.Season,
|
||||
BaseItemKind.Episode
|
||||
};
|
||||
}
|
||||
|
||||
@@ -323,7 +317,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
GetUserView(SpecialFolder.TvGenres, "Genres", "6", parent)
|
||||
};
|
||||
|
||||
return GetResult(list, parent, query);
|
||||
return GetResult(list, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
|
||||
@@ -333,7 +327,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.Limit = GetSpecialItemsLimit();
|
||||
query.IncludeItemTypes = new[] { nameof(Episode) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Episode };
|
||||
query.IsVirtualItem = false;
|
||||
|
||||
return ConvertToResult(_libraryManager.GetItemList(query));
|
||||
@@ -364,7 +358,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
query.Limit = GetSpecialItemsLimit();
|
||||
query.IncludeItemTypes = new[] { nameof(Episode) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Episode };
|
||||
|
||||
return ConvertToResult(_libraryManager.GetItemList(query));
|
||||
}
|
||||
@@ -375,7 +369,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { nameof(Series) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Series };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -384,7 +378,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = new[] { nameof(Series) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Series },
|
||||
Recursive = true,
|
||||
EnableTotalRecordCount = false
|
||||
}).Items
|
||||
@@ -403,9 +397,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
})
|
||||
.Where(i => i != null)
|
||||
.Select(i => GetUserViewWithName(i.Name, SpecialFolder.TvGenre, i.SortName, parent));
|
||||
.Select(i => GetUserViewWithName(SpecialFolder.TvGenre, i.SortName, parent));
|
||||
|
||||
return GetResult(genres, parent, query);
|
||||
return GetResult(genres, query);
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
|
||||
@@ -415,7 +409,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
query.GenreIds = new[] { displayParent.Id };
|
||||
query.SetUser(user);
|
||||
|
||||
query.IncludeItemTypes = new[] { nameof(Series) };
|
||||
query.IncludeItemTypes = new[] { BaseItemKind.Series };
|
||||
|
||||
return _libraryManager.GetItemsResult(query);
|
||||
}
|
||||
@@ -432,13 +426,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
private QueryResult<BaseItem> GetResult<T>(
|
||||
IEnumerable<T> items,
|
||||
BaseItem queryParent,
|
||||
InternalItemsQuery query)
|
||||
where T : BaseItem
|
||||
{
|
||||
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
|
||||
|
||||
return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
|
||||
return PostFilterAndSort(items, null, query, _libraryManager);
|
||||
}
|
||||
|
||||
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
|
||||
@@ -448,11 +441,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public static QueryResult<BaseItem> PostFilterAndSort(
|
||||
IEnumerable<BaseItem> items,
|
||||
BaseItem queryParent,
|
||||
int? totalRecordLimit,
|
||||
InternalItemsQuery query,
|
||||
ILibraryManager libraryManager,
|
||||
IServerConfigurationManager configurationManager)
|
||||
ILibraryManager libraryManager)
|
||||
{
|
||||
var user = query.User;
|
||||
|
||||
@@ -501,17 +492,17 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager)
|
||||
{
|
||||
if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
|
||||
if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
|
||||
if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
|
||||
if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -752,10 +743,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
var val = query.HasTrailer.Value;
|
||||
var trailerCount = 0;
|
||||
|
||||
var hasTrailers = item as IHasTrailers;
|
||||
if (hasTrailers != null)
|
||||
if (item is IHasTrailers hasTrailers)
|
||||
{
|
||||
trailerCount = hasTrailers.GetTrailerIds().Count;
|
||||
trailerCount = hasTrailers.GetTrailerCount();
|
||||
}
|
||||
|
||||
var ok = val ? trailerCount > 0 : trailerCount == 0;
|
||||
@@ -770,7 +760,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var filterValue = query.HasThemeSong.Value;
|
||||
|
||||
var themeCount = item.ThemeSongIds.Length;
|
||||
var themeCount = item.GetThemeSongs().Count;
|
||||
var ok = filterValue ? themeCount > 0 : themeCount == 0;
|
||||
|
||||
if (!ok)
|
||||
@@ -783,7 +773,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var filterValue = query.HasThemeVideo.Value;
|
||||
|
||||
var themeCount = item.ThemeVideoIds.Length;
|
||||
var themeCount = item.GetThemeVideos().Count;
|
||||
var ok = filterValue ? themeCount > 0 : themeCount == 0;
|
||||
|
||||
if (!ok)
|
||||
@@ -793,7 +783,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
// Apply genre filter
|
||||
if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
|
||||
if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -817,7 +807,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
|
||||
{
|
||||
var studioItem = libraryManager.GetItemById(id);
|
||||
return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
|
||||
return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
@@ -827,7 +817,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
|
||||
{
|
||||
var genreItem = libraryManager.GetItemById(id);
|
||||
return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparer.OrdinalIgnoreCase);
|
||||
return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase);
|
||||
}))
|
||||
{
|
||||
return false;
|
||||
@@ -860,7 +850,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
var tags = query.Tags;
|
||||
if (tags.Length > 0)
|
||||
{
|
||||
if (!tags.Any(v => item.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
|
||||
if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -978,7 +968,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var folder = i as ICollectionFolder;
|
||||
|
||||
return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
@@ -987,7 +977,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var folder = i as ICollectionFolder;
|
||||
|
||||
return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
|
||||
return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
@@ -1001,7 +991,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
return new BaseItem[] { parent };
|
||||
}
|
||||
|
||||
private UserView GetUserViewWithName(string name, string type, string sortName, BaseItem parent)
|
||||
private UserView GetUserViewWithName(string type, string sortName, BaseItem parent)
|
||||
{
|
||||
return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N", CultureInfo.InvariantCulture), type, sortName);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.LiveTv;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
@@ -28,6 +29,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
ISupportsPlaceHolders,
|
||||
IHasMediaSources
|
||||
{
|
||||
public Video()
|
||||
{
|
||||
AdditionalParts = Array.Empty<string>();
|
||||
LocalAlternateVersions = Array.Empty<string>();
|
||||
SubtitleFiles = Array.Empty<string>();
|
||||
AudioFiles = Array.Empty<string>();
|
||||
LinkedAlternateVersions = Array.Empty<LinkedChild>();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public string PrimaryVersionId { get; set; }
|
||||
|
||||
@@ -74,30 +84,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPrimaryVersionId(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
PrimaryVersionId = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimaryVersionId = id;
|
||||
}
|
||||
|
||||
PresentationUniqueKey = CreatePresentationUniqueKey();
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PrimaryVersionId))
|
||||
{
|
||||
return PrimaryVersionId;
|
||||
}
|
||||
|
||||
return base.CreatePresentationUniqueKey();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsThemeMedia => true;
|
||||
|
||||
@@ -113,6 +99,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The subtitle paths.</value>
|
||||
public string[] SubtitleFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the audio paths.
|
||||
/// </summary>
|
||||
/// <value>The audio paths.</value>
|
||||
public string[] AudioFiles { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance has subtitles.
|
||||
/// </summary>
|
||||
@@ -151,24 +143,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <value>The aspect ratio.</value>
|
||||
public string AspectRatio { get; set; }
|
||||
|
||||
public Video()
|
||||
{
|
||||
AdditionalParts = Array.Empty<string>();
|
||||
LocalAlternateVersions = Array.Empty<string>();
|
||||
SubtitleFiles = Array.Empty<string>();
|
||||
LinkedAlternateVersions = Array.Empty<LinkedChild>();
|
||||
}
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsFileProtocol;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAddingToPlaylist => true;
|
||||
|
||||
@@ -196,16 +170,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override bool HasLocalAlternateVersions => LocalAlternateVersions.Length > 0;
|
||||
|
||||
public IEnumerable<Guid> GetAdditionalPartIds()
|
||||
{
|
||||
return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> GetLocalAlternateVersionIds()
|
||||
{
|
||||
return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
}
|
||||
|
||||
public static ILiveTvManager LiveTvManager { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
@@ -222,21 +186,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsActiveRecording()
|
||||
{
|
||||
return LiveTvManager.GetActiveRecordingInfo(Path) != null;
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
if (IsActiveRecording())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CanDelete();
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsCompleteMedia
|
||||
{
|
||||
@@ -244,7 +193,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return !Tags.Contains("livestream", StringComparer.OrdinalIgnoreCase);
|
||||
return !Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
return !IsActiveRecording();
|
||||
@@ -254,80 +203,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
protected virtual bool EnableDefaultVideoUserDataKeys => true;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (EnableDefaultVideoUserDataKeys)
|
||||
{
|
||||
if (ExtraType.HasValue)
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, GetUserDataKey(key));
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, GetUserDataKey(key));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private string GetUserDataKey(string providerId)
|
||||
{
|
||||
var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant();
|
||||
|
||||
// Make sure different trailers have their own data.
|
||||
if (RunTimeTicks.HasValue)
|
||||
{
|
||||
key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public IEnumerable<Video> GetLinkedAlternateVersions()
|
||||
{
|
||||
return LinkedAlternateVersions
|
||||
.Select(GetLinkedChild)
|
||||
.Where(i => i != null)
|
||||
.OfType<Video>()
|
||||
.OrderBy(i => i.SortName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the additional parts.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{Video}.</returns>
|
||||
public IOrderedEnumerable<Video> GetAdditionalParts()
|
||||
{
|
||||
return GetAdditionalPartIds()
|
||||
.Select(i => LibraryManager.GetItemById(i))
|
||||
.Where(i => i != null)
|
||||
.OfType<Video>()
|
||||
.OrderBy(i => i.SortName);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
@@ -369,6 +244,153 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [is3 D].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [is3 D]; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool Is3D => Video3DFormat.HasValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
[JsonIgnore]
|
||||
public override string MediaType => Model.Entities.MediaType.Video;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (EnableDefaultVideoUserDataKeys)
|
||||
{
|
||||
if (ExtraType.HasValue)
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, GetUserDataKey(key));
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, GetUserDataKey(key));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public void SetPrimaryVersionId(string id)
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
PrimaryVersionId = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimaryVersionId = id;
|
||||
}
|
||||
|
||||
PresentationUniqueKey = CreatePresentationUniqueKey();
|
||||
}
|
||||
|
||||
public override string CreatePresentationUniqueKey()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(PrimaryVersionId))
|
||||
{
|
||||
return PrimaryVersionId;
|
||||
}
|
||||
|
||||
return base.CreatePresentationUniqueKey();
|
||||
}
|
||||
|
||||
public override bool CanDownload()
|
||||
{
|
||||
if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsFileProtocol;
|
||||
}
|
||||
|
||||
protected override bool IsActiveRecording()
|
||||
{
|
||||
return LiveTvManager.GetActiveRecordingInfo(Path) != null;
|
||||
}
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
if (IsActiveRecording())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CanDelete();
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> GetAdditionalPartIds()
|
||||
{
|
||||
return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> GetLocalAlternateVersionIds()
|
||||
{
|
||||
return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
|
||||
}
|
||||
|
||||
private string GetUserDataKey(string providerId)
|
||||
{
|
||||
var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant();
|
||||
|
||||
// Make sure different trailers have their own data.
|
||||
if (RunTimeTicks.HasValue)
|
||||
{
|
||||
key += "-" + RunTimeTicks.Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
public IEnumerable<Video> GetLinkedAlternateVersions()
|
||||
{
|
||||
return LinkedAlternateVersions
|
||||
.Select(GetLinkedChild)
|
||||
.Where(i => i != null)
|
||||
.OfType<Video>()
|
||||
.OrderBy(i => i.SortName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the additional parts.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{Video}.</returns>
|
||||
public IOrderedEnumerable<Video> GetAdditionalParts()
|
||||
{
|
||||
return GetAdditionalPartIds()
|
||||
.Select(i => LibraryManager.GetItemById(i))
|
||||
.Where(i => i != null)
|
||||
.OfType<Video>()
|
||||
.OrderBy(i => i.SortName);
|
||||
}
|
||||
|
||||
internal override ItemUpdateType UpdateFromResolvedItem(BaseItem newItem)
|
||||
{
|
||||
var updateType = base.UpdateFromResolvedItem(newItem);
|
||||
@@ -397,20 +419,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return updateType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether [is3 D].
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if [is3 D]; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool Is3D => Video3DFormat.HasValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the media.
|
||||
/// </summary>
|
||||
/// <value>The type of the media.</value>
|
||||
[JsonIgnore]
|
||||
public override string MediaType => Model.Entities.MediaType.Video;
|
||||
|
||||
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
|
||||
@@ -509,35 +517,35 @@ namespace MediaBrowser.Controller.Entities
|
||||
}).FirstOrDefault();
|
||||
}
|
||||
|
||||
protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
|
||||
protected override IEnumerable<(BaseItem, MediaSourceType)> GetAllItemsForMediaSources()
|
||||
{
|
||||
var list = new List<Tuple<BaseItem, MediaSourceType>>();
|
||||
var list = new List<(BaseItem, MediaSourceType)>
|
||||
{
|
||||
(this, MediaSourceType.Default)
|
||||
};
|
||||
|
||||
list.Add(new Tuple<BaseItem, MediaSourceType>(this, MediaSourceType.Default));
|
||||
list.AddRange(GetLinkedAlternateVersions().Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Grouping)));
|
||||
list.AddRange(GetLinkedAlternateVersions().Select(i => ((BaseItem)i, MediaSourceType.Grouping)));
|
||||
|
||||
if (!string.IsNullOrEmpty(PrimaryVersionId))
|
||||
{
|
||||
var primary = LibraryManager.GetItemById(PrimaryVersionId) as Video;
|
||||
if (primary != null)
|
||||
if (LibraryManager.GetItemById(PrimaryVersionId) is Video primary)
|
||||
{
|
||||
var existingIds = list.Select(i => i.Item1.Id).ToList();
|
||||
list.Add(new Tuple<BaseItem, MediaSourceType>(primary, MediaSourceType.Grouping));
|
||||
list.AddRange(primary.GetLinkedAlternateVersions().Where(i => !existingIds.Contains(i.Id)).Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Grouping)));
|
||||
list.Add((primary, MediaSourceType.Grouping));
|
||||
list.AddRange(primary.GetLinkedAlternateVersions().Where(i => !existingIds.Contains(i.Id)).Select(i => ((BaseItem)i, MediaSourceType.Grouping)));
|
||||
}
|
||||
}
|
||||
|
||||
var localAlternates = list
|
||||
.SelectMany(i =>
|
||||
{
|
||||
var video = i.Item1 as Video;
|
||||
return video == null ? new List<Guid>() : video.GetLocalAlternateVersionIds();
|
||||
return i.Item1 is Video video ? video.GetLocalAlternateVersionIds() : Enumerable.Empty<Guid>();
|
||||
})
|
||||
.Select(LibraryManager.GetItemById)
|
||||
.Where(i => i != null)
|
||||
.ToList();
|
||||
|
||||
list.AddRange(localAlternates.Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Default)));
|
||||
list.AddRange(localAlternates.Select(i => (i, MediaSourceType.Default)));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -15,13 +15,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class Year : BaseItem, IItemByName
|
||||
{
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
list.Insert(0, "Year-" + Name);
|
||||
return list;
|
||||
}
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
@@ -31,6 +29,19 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath => Path;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
list.Insert(0, "Year-" + Name);
|
||||
return list;
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
double value = 2;
|
||||
@@ -39,14 +50,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return value;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
public override bool CanDelete()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool IsSaveLocalMetadataEnabled()
|
||||
{
|
||||
return true;
|
||||
@@ -54,9 +57,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
|
||||
{
|
||||
var usCulture = new CultureInfo("en-US");
|
||||
|
||||
if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out var year))
|
||||
if (!int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
|
||||
{
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
@@ -76,9 +77,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return null;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople => false;
|
||||
|
||||
public static string GetPath(string name)
|
||||
{
|
||||
return GetPath(name, true);
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MediaBrowser.Controller.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Class BaseExtensions.
|
||||
/// </summary>
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string RemoveDiacritics(this string text)
|
||||
{
|
||||
var chars = Normalize(text, NormalizationForm.FormD)
|
||||
.Where(ch => CharUnicodeInfo.GetUnicodeCategory(ch) != UnicodeCategory.NonSpacingMark);
|
||||
|
||||
return Normalize(string.Concat(chars), NormalizationForm.FormC);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counts the number of occurrences of [needle] in the string.
|
||||
/// </summary>
|
||||
/// <param name="value">The haystack to search in.</param>
|
||||
/// <param name="needle">The character to search for.</param>
|
||||
/// <returns>The number of occurrences of the [needle] character.</returns>
|
||||
public static int Count(this ReadOnlySpan<char> value, char needle)
|
||||
{
|
||||
var count = 0;
|
||||
var length = value.Length;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
if (value[i] == needle)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
|
||||
{
|
||||
if (stripStringOnFailure)
|
||||
{
|
||||
try
|
||||
{
|
||||
return text.Normalize(form);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// will throw if input contains invalid unicode chars
|
||||
// https://mnaoumov.wordpress.com/2014/06/14/stripping-invalid-characters-from-utf-16-strings/
|
||||
text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", string.Empty);
|
||||
return Normalize(text, form, false);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return text.Normalize(form);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// if it still fails, return the original text
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.IO
|
||||
if (string.IsNullOrEmpty(newPath))
|
||||
{
|
||||
// invalid shortcut - could be old or target could just be unavailable
|
||||
logger.LogWarning("Encountered invalid shortcut: " + fullName);
|
||||
logger.LogWarning("Encountered invalid shortcut: {Path}", fullName);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error resolving shortcut from {path}", fullName);
|
||||
logger.LogError(ex, "Error resolving shortcut from {Path}", fullName);
|
||||
}
|
||||
}
|
||||
else if (flattenFolderDepth > 0 && isDirectory)
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using MediaBrowser.Common;
|
||||
using MediaBrowser.Model.System;
|
||||
@@ -16,8 +14,6 @@ namespace MediaBrowser.Controller
|
||||
/// </summary>
|
||||
public interface IServerApplicationHost : IApplicationHost
|
||||
{
|
||||
event EventHandler HasUpdateAvailableChanged;
|
||||
|
||||
bool CoreStartupHasCompleted { get; }
|
||||
|
||||
bool CanLaunchWebBrowser { get; }
|
||||
@@ -39,62 +35,48 @@ namespace MediaBrowser.Controller
|
||||
/// </summary>
|
||||
bool ListenWithHttps { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance has update available.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance has update available; otherwise, <c>false</c>.</value>
|
||||
bool HasUpdateAvailable { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the friendly.
|
||||
/// </summary>
|
||||
/// <value>The name of the friendly.</value>
|
||||
string FriendlyName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configured published server url.
|
||||
/// </summary>
|
||||
string PublishedServerUrl { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system info.
|
||||
/// </summary>
|
||||
/// <param name="source">The originator of the request.</param>
|
||||
/// <param name="request">The HTTP request.</param>
|
||||
/// <returns>SystemInfo.</returns>
|
||||
SystemInfo GetSystemInfo(IPAddress source);
|
||||
SystemInfo GetSystemInfo(HttpRequest request);
|
||||
|
||||
PublicSystemInfo GetPublicSystemInfo(IPAddress address);
|
||||
PublicSystemInfo GetPublicSystemInfo(HttpRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a URL specific for the request.
|
||||
/// </summary>
|
||||
/// <param name="request">The <see cref="HttpRequest"/> instance.</param>
|
||||
/// <param name="port">Optional port number.</param>
|
||||
/// <returns>An accessible URL.</returns>
|
||||
string GetSmartApiUrl(HttpRequest request, int? port = null);
|
||||
string GetSmartApiUrl(HttpRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a URL specific for the request.
|
||||
/// </summary>
|
||||
/// <param name="remoteAddr">The remote <see cref="IPAddress"/> of the connection.</param>
|
||||
/// <param name="port">Optional port number.</param>
|
||||
/// <returns>An accessible URL.</returns>
|
||||
string GetSmartApiUrl(IPAddress remoteAddr, int? port = null);
|
||||
string GetSmartApiUrl(IPAddress remoteAddr);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a URL specific for the request.
|
||||
/// </summary>
|
||||
/// <param name="hostname">The hostname used in the connection.</param>
|
||||
/// <param name="port">Optional port number.</param>
|
||||
/// <returns>An accessible URL.</returns>
|
||||
string GetSmartApiUrl(string hostname, int? port = null);
|
||||
string GetSmartApiUrl(string hostname);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a localhost URL that can be used to access the API using the loop-back IP address.
|
||||
/// over HTTP (not HTTPS).
|
||||
/// Gets an URL that can be used to access the API over LAN.
|
||||
/// </summary>
|
||||
/// <param name="allowHttps">A value indicating whether to allow HTTPS.</param>
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetLoopbackHttpApiUrl();
|
||||
string GetApiUrlForLocalAccess(bool allowHttps = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a local (LAN) URL that can be used to access the API.
|
||||
@@ -112,15 +94,6 @@ namespace MediaBrowser.Controller
|
||||
/// <returns>The API URL.</returns>
|
||||
string GetLocalApiUrl(string hostname, string scheme = null, int? port = null);
|
||||
|
||||
/// <summary>
|
||||
/// Open a URL in an external browser window.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL to open.</param>
|
||||
/// <exception cref="NotSupportedException"><see cref="CanLaunchWebBrowser"/> is false.</exception>
|
||||
void LaunchUrl(string url);
|
||||
|
||||
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
|
||||
|
||||
string ExpandVirtualPath(string path);
|
||||
|
||||
string ReverseVirtualPath(string path);
|
||||
|
||||
19
MediaBrowser.Controller/Library/IDirectStreamProvider.cs
Normal file
19
MediaBrowser.Controller/Library/IDirectStreamProvider.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.IO;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// The direct live TV stream provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Deprecated.
|
||||
/// </remarks>
|
||||
public interface IDirectStreamProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the live stream, shared streams seek to the end of the file first.
|
||||
/// </summary>
|
||||
/// <returns>The stream.</returns>
|
||||
Stream GetStream();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Naming.Common;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
@@ -31,15 +30,40 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
public interface ILibraryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when [item added].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item updated].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item removed].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root folder.
|
||||
/// </summary>
|
||||
/// <value>The root folder.</value>
|
||||
AggregateFolder RootFolder { get; }
|
||||
|
||||
bool IsScanRunning { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the path.
|
||||
/// </summary>
|
||||
/// <param name="fileInfo">The file information.</param>
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
|
||||
/// <returns>BaseItem.</returns>
|
||||
BaseItem ResolvePath(
|
||||
FileSystemMetadata fileInfo,
|
||||
Folder parent = null);
|
||||
Folder parent = null,
|
||||
IDirectoryService directoryService = null);
|
||||
|
||||
/// <summary>
|
||||
/// Resolves a set of files into a list of BaseItem.
|
||||
@@ -57,16 +81,10 @@ namespace MediaBrowser.Controller.Library
|
||||
LibraryOptions libraryOptions,
|
||||
string collectionType = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root folder.
|
||||
/// </summary>
|
||||
/// <value>The root folder.</value>
|
||||
AggregateFolder RootFolder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Person.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="name">The name of the person.</param>
|
||||
/// <returns>Task{Person}.</returns>
|
||||
Person GetPerson(string name);
|
||||
|
||||
@@ -81,7 +99,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets the artist.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="name">The name of the artist.</param>
|
||||
/// <returns>Task{Artist}.</returns>
|
||||
MusicArtist GetArtist(string name);
|
||||
|
||||
@@ -90,21 +108,21 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets a Studio.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="name">The name of the studio.</param>
|
||||
/// <returns>Task{Studio}.</returns>
|
||||
Studio GetStudio(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Genre.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="name">The name of the genre.</param>
|
||||
/// <returns>Task{Genre}.</returns>
|
||||
Genre GetGenre(string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the genre.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="name">The name of the music genre.</param>
|
||||
/// <returns>Task{MusicGenre}.</returns>
|
||||
MusicGenre GetMusicGenre(string name);
|
||||
|
||||
@@ -113,7 +131,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>Task{Year}.</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Throws if year is invalid.</exception>
|
||||
Year GetYear(int value);
|
||||
|
||||
/// <summary>
|
||||
@@ -205,16 +223,26 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Creates the item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to create.</param>
|
||||
/// <param name="parent">Parent of new item.</param>
|
||||
void CreateItem(BaseItem item, BaseItem parent);
|
||||
|
||||
/// <summary>
|
||||
/// Creates the items.
|
||||
/// </summary>
|
||||
/// <param name="items">Items to create.</param>
|
||||
/// <param name="parent">Parent of new items.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
void CreateItems(IReadOnlyList<BaseItem> items, BaseItem parent, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the item.
|
||||
/// </summary>
|
||||
/// <param name="items">Items to update.</param>
|
||||
/// <param name="parent">Parent of updated items.</param>
|
||||
/// <param name="updateReason">Reason for update.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Returns a Task that can be awaited.</returns>
|
||||
Task UpdateItemsAsync(IReadOnlyList<BaseItem> items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -224,6 +252,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="parent">The parent item.</param>
|
||||
/// <param name="updateReason">The update reason.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Returns a Task that can be awaited.</returns>
|
||||
Task UpdateItemAsync(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -233,23 +262,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>BaseItem.</returns>
|
||||
BaseItem RetrieveItem(Guid id);
|
||||
|
||||
bool IsScanRunning { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item added].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item updated].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [item removed].
|
||||
/// </summary>
|
||||
event EventHandler<ItemChangeEventArgs> ItemRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the type of the collection.
|
||||
/// </summary>
|
||||
@@ -294,16 +306,25 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Deletes the item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to delete.</param>
|
||||
/// <param name="options">Options to use for deletion.</param>
|
||||
void DeleteItem(BaseItem item, DeleteOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to delete.</param>
|
||||
/// <param name="options">Options to use for deletion.</param>
|
||||
/// <param name="notifyParentItem">Notify parent of deletion.</param>
|
||||
void DeleteItem(BaseItem item, DeleteOptions options, bool notifyParentItem);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the item.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to delete.</param>
|
||||
/// <param name="options">Options to use for deletion.</param>
|
||||
/// <param name="parent">Parent of item.</param>
|
||||
/// <param name="notifyParentItem">Notify parent of deletion.</param>
|
||||
void DeleteItem(BaseItem item, DeleteOptions options, BaseItem parent, bool notifyParentItem);
|
||||
|
||||
/// <summary>
|
||||
@@ -314,6 +335,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="parentId">The parent identifier.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <returns>The named view.</returns>
|
||||
UserView GetNamedView(
|
||||
User user,
|
||||
string name,
|
||||
@@ -328,6 +350,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <returns>The named view.</returns>
|
||||
UserView GetNamedView(
|
||||
User user,
|
||||
string name,
|
||||
@@ -340,6 +363,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <returns>The named view.</returns>
|
||||
UserView GetNamedView(
|
||||
string name,
|
||||
string viewType,
|
||||
@@ -373,20 +397,6 @@ namespace MediaBrowser.Controller.Library
|
||||
string viewType,
|
||||
string sortName);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is video file] [the specified path].
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is video file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
bool IsVideoFile(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is audio file] [the specified path].
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
|
||||
bool IsAudioFile(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the season number from path.
|
||||
/// </summary>
|
||||
@@ -397,6 +407,9 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Fills the missing episode numbers from path.
|
||||
/// </summary>
|
||||
/// <param name="episode">Episode to use.</param>
|
||||
/// <param name="forceRefresh">Option to force refresh of episode numbers.</param>
|
||||
/// <returns>True if successful.</returns>
|
||||
bool FillMissingEpisodeNumbersFromPath(Episode episode, bool forceRefresh);
|
||||
|
||||
/// <summary>
|
||||
@@ -414,29 +427,14 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>Guid.</returns>
|
||||
Guid GetNewItemId(string key, Type type);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the trailers.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="fileSystemChildren">The file system children.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
/// <returns>IEnumerable<Trailer>.</returns>
|
||||
IEnumerable<Video> FindTrailers(
|
||||
BaseItem owner,
|
||||
List<FileSystemMetadata> fileSystemChildren,
|
||||
IDirectoryService directoryService);
|
||||
|
||||
/// <summary>
|
||||
/// Finds the extras.
|
||||
/// </summary>
|
||||
/// <param name="owner">The owner.</param>
|
||||
/// <param name="fileSystemChildren">The file system children.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
/// <returns>IEnumerable<Video>.</returns>
|
||||
IEnumerable<Video> FindExtras(
|
||||
BaseItem owner,
|
||||
List<FileSystemMetadata> fileSystemChildren,
|
||||
IDirectoryService directoryService);
|
||||
/// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
|
||||
/// <returns>IEnumerable<BaseItem>.</returns>
|
||||
IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the collection folders.
|
||||
@@ -539,6 +537,9 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets the items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query to use.</param>
|
||||
/// <param name="parents">Items to use for query.</param>
|
||||
/// <returns>List of items.</returns>
|
||||
List<BaseItem> GetItemList(InternalItemsQuery query, List<BaseItem> parents);
|
||||
|
||||
/// <summary>
|
||||
@@ -566,11 +567,11 @@ namespace MediaBrowser.Controller.Library
|
||||
|
||||
Task RemoveVirtualFolder(string name, bool refreshLibrary);
|
||||
|
||||
void AddMediaPath(string virtualFolderName, MediaPathInfo path);
|
||||
void AddMediaPath(string virtualFolderName, MediaPathInfo mediaPath);
|
||||
|
||||
void UpdateMediaPath(string virtualFolderName, MediaPathInfo path);
|
||||
void UpdateMediaPath(string virtualFolderName, MediaPathInfo mediaPath);
|
||||
|
||||
void RemoveMediaPath(string virtualFolderName, string path);
|
||||
void RemoveMediaPath(string virtualFolderName, string mediaPath);
|
||||
|
||||
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
|
||||
|
||||
@@ -596,11 +597,5 @@ namespace MediaBrowser.Controller.Library
|
||||
BaseItem GetParentItem(string parentId, Guid? userId);
|
||||
|
||||
BaseItem GetParentItem(Guid? parentId, Guid? userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or creates a static instance of <see cref="NamingOptions"/>.
|
||||
/// </summary>
|
||||
/// <returns>An instance of the <see cref="NamingOptions"/> class.</returns>
|
||||
NamingOptions GetNamingOptions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1711, CS1591
|
||||
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Dto;
|
||||
@@ -25,5 +26,7 @@ namespace MediaBrowser.Controller.Library
|
||||
Task Open(CancellationToken openCancellationToken);
|
||||
|
||||
Task Close();
|
||||
|
||||
Stream GetStream();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
@@ -31,13 +30,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>IEnumerable<MediaStream>.</returns>
|
||||
List<MediaStream> GetMediaStreams(Guid itemId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media streams.
|
||||
/// </summary>
|
||||
/// <param name="mediaSourceId">The media source identifier.</param>
|
||||
/// <returns>IEnumerable<MediaStream>.</returns>
|
||||
List<MediaStream> GetMediaStreams(string mediaSourceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media streams.
|
||||
/// </summary>
|
||||
@@ -62,16 +54,32 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets the playack media sources.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to use.</param>
|
||||
/// <param name="user">User to use for operation.</param>
|
||||
/// <param name="allowMediaProbe">Option to allow media probe.</param>
|
||||
/// <param name="enablePathSubstitution">Option to enable path substitution.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>List of media sources wrapped in an awaitable task.</returns>
|
||||
Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static media sources.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to use.</param>
|
||||
/// <param name="enablePathSubstitution">Option to enable path substitution.</param>
|
||||
/// <param name="user">User to use for operation.</param>
|
||||
/// <returns>List of media sources.</returns>
|
||||
List<MediaSourceInfo> GetStaticMediaSources(BaseItem item, bool enablePathSubstitution, User user = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the static media source.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to use.</param>
|
||||
/// <param name="mediaSourceId">Media source to get.</param>
|
||||
/// <param name="liveStreamId">Live stream to use.</param>
|
||||
/// <param name="enablePathSubstitution">Option to enable path substitution.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>The static media source wrapped in an awaitable task.</returns>
|
||||
Task<MediaSourceInfo> GetMediaSource(BaseItem item, string mediaSourceId, string liveStreamId, bool enablePathSubstitution, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -94,6 +102,20 @@ namespace MediaBrowser.Controller.Library
|
||||
|
||||
Task<Tuple<MediaSourceInfo, IDirectStreamProvider>> GetLiveStreamWithDirectStreamProvider(string id, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the live stream info.
|
||||
/// </summary>
|
||||
/// <param name="id">The identifier.</param>
|
||||
/// <returns>An instance of <see cref="ILiveStream"/>.</returns>
|
||||
public ILiveStream GetLiveStreamInfo(string id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the live stream info using the stream's unique id.
|
||||
/// </summary>
|
||||
/// <param name="uniqueId">The unique identifier.</param>
|
||||
/// <returns>An instance of <see cref="ILiveStream"/>.</returns>
|
||||
public ILiveStream GetLiveStreamInfoByUniqueId(string uniqueId);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the media source.
|
||||
/// </summary>
|
||||
@@ -110,14 +132,5 @@ namespace MediaBrowser.Controller.Library
|
||||
void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user);
|
||||
|
||||
Task AddMediaInfoWithProbe(MediaSourceInfo mediaSource, bool isAudio, string cacheKey, bool addProbeDelay, bool isLiveStream, CancellationToken cancellationToken);
|
||||
|
||||
Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IDirectStreamProvider
|
||||
{
|
||||
Task CopyToAsync(Stream stream, CancellationToken cancellationToken);
|
||||
|
||||
string GetFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
@@ -21,6 +21,10 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Opens the media source.
|
||||
/// </summary>
|
||||
/// <param name="openToken">Token to use.</param>
|
||||
/// <param name="currentLiveStreams">List of live streams.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>The media source wrapped as an awaitable task.</returns>
|
||||
Task<ILiveStream> OpenMediaSource(string openToken, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
void Save(BaseItem item, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Jellyfin.Data.Entities;
|
||||
@@ -15,16 +15,28 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets the instant mix from song.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to use.</param>
|
||||
/// <param name="user">The user to use.</param>
|
||||
/// <param name="dtoOptions">The options to use.</param>
|
||||
/// <returns>List of items.</returns>
|
||||
List<BaseItem> GetInstantMixFromItem(BaseItem item, User user, DtoOptions dtoOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instant mix from artist.
|
||||
/// </summary>
|
||||
/// <param name="artist">The artist to use.</param>
|
||||
/// <param name="user">The user to use.</param>
|
||||
/// <param name="dtoOptions">The options to use.</param>
|
||||
/// <returns>List of items.</returns>
|
||||
List<BaseItem> GetInstantMixFromArtist(MusicArtist artist, User user, DtoOptions dtoOptions);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the instant mix from genre.
|
||||
/// </summary>
|
||||
/// <param name="genres">The genres to use.</param>
|
||||
/// <param name="user">The user to use.</param>
|
||||
/// <param name="dtoOptions">The options to use.</param>
|
||||
/// <returns>List of items.</returns>
|
||||
List<BaseItem> GetInstantMixFromGenres(IEnumerable<string> genres, User user, DtoOptions dtoOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA1707, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -42,9 +42,12 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Gets the user data dto.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to use.</param>
|
||||
/// <param name="user">User to use.</param>
|
||||
/// <returns>User data dto.</returns>
|
||||
UserItemDataDto GetUserDataDto(BaseItem item, User user);
|
||||
|
||||
UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions dto_options);
|
||||
UserItemDataDto GetUserDataDto(BaseItem item, BaseItemDto itemDto, User user, DtoOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Get all user data for the given user.
|
||||
@@ -64,6 +67,10 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Updates playstate for an item and returns true or false indicating if it was played to completion.
|
||||
/// </summary>
|
||||
bool UpdatePlayState(BaseItem item, UserItemData data, long? positionTicks);
|
||||
/// <param name="item">Item to update.</param>
|
||||
/// <param name="data">Data to update.</param>
|
||||
/// <param name="reportedPositionTicks">New playstate.</param>
|
||||
/// <returns>True if playstate was updated.</returns>
|
||||
bool UpdatePlayState(BaseItem item, UserItemData data, long? reportedPositionTicks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Initializes the user manager and ensures that a user exists.
|
||||
/// </summary>
|
||||
/// <returns>Awaitable task.</returns>
|
||||
Task InitializeAsync();
|
||||
|
||||
/// <summary>
|
||||
@@ -65,14 +66,6 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <exception cref="ArgumentException">If the provided user doesn't exist.</exception>
|
||||
Task RenameUser(User user, string newName);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <exception cref="ArgumentNullException">If user is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">If the provided user doesn't exist.</exception>
|
||||
void UpdateUser(User user);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the user.
|
||||
/// </summary>
|
||||
@@ -110,17 +103,24 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>Task.</returns>
|
||||
void ResetEasyPassword(User user);
|
||||
Task ResetEasyPassword(User user);
|
||||
|
||||
/// <summary>
|
||||
/// Changes the password.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="newPassword">New password to use.</param>
|
||||
/// <returns>Awaitable task.</returns>
|
||||
Task ChangePassword(User user, string newPassword);
|
||||
|
||||
/// <summary>
|
||||
/// Changes the easy password.
|
||||
/// </summary>
|
||||
void ChangeEasyPassword(User user, string newPassword, string newPasswordSha1);
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="newPassword">New password to use.</param>
|
||||
/// <param name="newPasswordSha1">Hash of new password.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task ChangeEasyPassword(User user, string newPassword, string newPasswordSha1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the user dto.
|
||||
@@ -133,6 +133,12 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Authenticates the user.
|
||||
/// </summary>
|
||||
/// <param name="username">The user.</param>
|
||||
/// <param name="password">The password to use.</param>
|
||||
/// <param name="passwordSha1">Hash of password.</param>
|
||||
/// <param name="remoteEndPoint">Remove endpoint to use.</param>
|
||||
/// <param name="isUserSession">Specifies if a user session.</param>
|
||||
/// <returns>User wrapped in awaitable task.</returns>
|
||||
Task<User> AuthenticateUser(string username, string password, string passwordSha1, string remoteEndPoint, bool isUserSession);
|
||||
|
||||
/// <summary>
|
||||
@@ -157,7 +163,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// This method updates the user's configuration.
|
||||
/// This is only included as a stopgap until the new API, using this internally is not recommended.
|
||||
/// Instead, modify the user object directly, then call <see cref="UpdateUser"/>.
|
||||
/// Instead, modify the user object directly, then call <see cref="UpdateUserAsync"/>.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's Id.</param>
|
||||
/// <param name="config">The request containing the new user configuration.</param>
|
||||
@@ -167,7 +173,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// This method updates the user's policy.
|
||||
/// This is only included as a stopgap until the new API, using this internally is not recommended.
|
||||
/// Instead, modify the user object directly, then call <see cref="UpdateUser"/>.
|
||||
/// Instead, modify the user object directly, then call <see cref="UpdateUserAsync"/>.
|
||||
/// </summary>
|
||||
/// <param name="userId">The user's Id.</param>
|
||||
/// <param name="policy">The request containing the new user policy.</param>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -13,10 +13,29 @@ namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
public interface IUserViewManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets user views.
|
||||
/// </summary>
|
||||
/// <param name="query">Query to use.</param>
|
||||
/// <returns>Set of folders.</returns>
|
||||
Folder[] GetUserViews(UserViewQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets user sub views.
|
||||
/// </summary>
|
||||
/// <param name="parentId">Parent to use.</param>
|
||||
/// <param name="type">Type to use.</param>
|
||||
/// <param name="localizationKey">Localization key to use.</param>
|
||||
/// <param name="sortName">Sort to use.</param>
|
||||
/// <returns>User view.</returns>
|
||||
UserView GetUserSubView(Guid parentId, string type, string localizationKey, string sortName);
|
||||
|
||||
/// <summary>
|
||||
/// Gets latest items.
|
||||
/// </summary>
|
||||
/// <param name="request">Query to use.</param>
|
||||
/// <param name="options">Options to use.</param>
|
||||
/// <returns>Set of items.</returns>
|
||||
List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1711, CS1591
|
||||
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1721, CA1819, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Library
|
||||
DirectoryService = directoryService;
|
||||
}
|
||||
|
||||
// TODO remove dependencies as properties, they should be injected where it makes sense
|
||||
public IDirectoryService DirectoryService { get; }
|
||||
|
||||
/// <summary>
|
||||
@@ -109,6 +110,21 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <value>The additional locations.</value>
|
||||
private List<string> AdditionalLocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the physical locations.
|
||||
/// </summary>
|
||||
/// <value>The physical locations.</value>
|
||||
public string[] PhysicalLocations
|
||||
{
|
||||
get
|
||||
{
|
||||
var paths = string.IsNullOrEmpty(Path) ? Array.Empty<string>() : new[] { Path };
|
||||
return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public string CollectionType { get; set; }
|
||||
|
||||
public bool HasParent<T>()
|
||||
where T : Folder
|
||||
{
|
||||
@@ -138,6 +154,16 @@ namespace MediaBrowser.Controller.Library
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return Equals(obj as ItemResolveArgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the additional location.
|
||||
/// </summary>
|
||||
@@ -156,19 +182,6 @@ namespace MediaBrowser.Controller.Library
|
||||
|
||||
// REVIEW: @bond
|
||||
|
||||
/// <summary>
|
||||
/// Gets the physical locations.
|
||||
/// </summary>
|
||||
/// <value>The physical locations.</value>
|
||||
public string[] PhysicalLocations
|
||||
{
|
||||
get
|
||||
{
|
||||
var paths = string.IsNullOrEmpty(Path) ? Array.Empty<string>() : new[] { Path };
|
||||
return AdditionalLocations == null ? paths : paths.Concat(AdditionalLocations).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the file system entry by.
|
||||
/// </summary>
|
||||
@@ -190,7 +203,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>FileSystemInfo.</returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
/// <exception cref="ArgumentNullException">Throws if path is invalid.</exception>
|
||||
public FileSystemMetadata GetFileSystemEntryByPath(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
@@ -224,16 +237,38 @@ namespace MediaBrowser.Controller.Library
|
||||
return CollectionType;
|
||||
}
|
||||
|
||||
public string CollectionType { get; set; }
|
||||
/// <summary>
|
||||
/// Gets the configured content type for the path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is subject to future refactoring as it relies on a static property in BaseItem.
|
||||
/// </remarks>
|
||||
/// <returns>The configured content type.</returns>
|
||||
public string GetConfiguredContentType()
|
||||
{
|
||||
return BaseItem.LibraryManager.GetConfiguredContentType(Path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="object" /> is equal to this instance.
|
||||
/// Gets the file system children that do not hit the ignore file check.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to compare with the current object.</param>
|
||||
/// <returns><c>true</c> if the specified <see cref="object" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||
public override bool Equals(object obj)
|
||||
/// <remarks>
|
||||
/// This is subject to future refactoring as it relies on a static property in BaseItem.
|
||||
/// </remarks>
|
||||
/// <returns>The file system children that are not ignored.</returns>
|
||||
public IEnumerable<FileSystemMetadata> GetActualFileSystemChildren()
|
||||
{
|
||||
return Equals(obj as ItemResolveArgs);
|
||||
var numberOfChildren = FileSystemChildren.Length;
|
||||
for (var i = 0; i < numberOfChildren; i++)
|
||||
{
|
||||
var child = FileSystemChildren[i];
|
||||
if (BaseItem.LibraryManager.IgnoreFile(child, Parent))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Extensions;
|
||||
using Diacritics.Extensions;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -22,12 +22,22 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
public interface ILiveTvManager
|
||||
{
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the services.
|
||||
/// </summary>
|
||||
/// <value>The services.</value>
|
||||
IReadOnlyList<ILiveTvService> Services { get; }
|
||||
|
||||
IListingsProvider[] ListingProviders { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the new timer defaults asynchronous.
|
||||
/// </summary>
|
||||
@@ -86,6 +96,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <returns>A recording.</returns>
|
||||
QueryResult<BaseItemDto> GetRecordings(RecordingQuery query, DtoOptions options);
|
||||
|
||||
/// <summary>
|
||||
@@ -176,11 +187,16 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Recommended programs.</returns>
|
||||
QueryResult<BaseItemDto> GetRecommendedPrograms(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the recommended programs internal.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="options">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Recommended programs.</returns>
|
||||
QueryResult<BaseItem> GetRecommendedProgramsInternal(InternalItemsQuery query, DtoOptions options, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -202,6 +218,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// Gets the live tv folder.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Live TV folder.</returns>
|
||||
Folder GetInternalLiveTvFolder(CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -213,11 +230,18 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <summary>
|
||||
/// Gets the internal channels.
|
||||
/// </summary>
|
||||
/// <param name="query">The query.</param>
|
||||
/// <param name="dtoOptions">The options.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Internal channels.</returns>
|
||||
QueryResult<BaseItem> GetInternalChannels(LiveTvChannelQuery query, DtoOptions dtoOptions, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel media sources.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to search for.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Channel media sources wrapped in a task.</returns>
|
||||
Task<IEnumerable<MediaSourceInfo>> GetChannelMediaSources(BaseItem item, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
@@ -232,6 +256,9 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <summary>
|
||||
/// Saves the tuner host.
|
||||
/// </summary>
|
||||
/// <param name="info">Turner host to save.</param>
|
||||
/// <param name="dataSourceChanged">Option to specify that data source has changed.</param>
|
||||
/// <returns>Tuner host information wrapped in a task.</returns>
|
||||
Task<TunerHostInfo> SaveTunerHost(TunerHostInfo info, bool dataSourceChanged = true);
|
||||
|
||||
/// <summary>
|
||||
@@ -247,7 +274,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
|
||||
Task<TunerChannelMapping> SetChannelMapping(string providerId, string tunerChannelNumber, string providerChannelNumber);
|
||||
|
||||
TunerChannelMapping GetTunerChannelMapping(ChannelInfo channel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
|
||||
TunerChannelMapping GetTunerChannelMapping(ChannelInfo tunerChannel, NameValuePair[] mappings, List<ChannelInfo> providerChannels);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lineups.
|
||||
@@ -271,20 +298,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
|
||||
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
|
||||
|
||||
IListingsProvider[] ListingProviders { get; }
|
||||
|
||||
List<NameIdPair> GetTunerHostTypes();
|
||||
|
||||
Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken);
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
|
||||
|
||||
string GetEmbyTvActiveRecordingPath(string id);
|
||||
|
||||
ActiveRecordingInfo GetActiveRecordingInfo(string path);
|
||||
|
||||
@@ -70,10 +70,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <summary>
|
||||
/// Updates the timer asynchronous.
|
||||
/// </summary>
|
||||
/// <param name="info">The information.</param>
|
||||
/// <param name="updatedTimer">The updated timer information.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task UpdateTimerAsync(TimerInfo info, CancellationToken cancellationToken);
|
||||
Task UpdateTimerAsync(TimerInfo updatedTimer, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the series timer asynchronous.
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <summary>
|
||||
/// Gets the channels.
|
||||
/// </summary>
|
||||
/// <param name="enableCache">Option to enable using cache.</param>
|
||||
/// <param name="cancellationToken">The CancellationToken for this operation.</param>
|
||||
/// <returns>Task<IEnumerable<ChannelInfo>>.</returns>
|
||||
Task<List<ChannelInfo>> GetChannels(bool enableCache, CancellationToken cancellationToken);
|
||||
|
||||
@@ -47,6 +49,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <param name="streamId">The stream identifier.</param>
|
||||
/// <param name="currentLiveStreams">The current live streams.</param>
|
||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||
/// <returns>Live stream wrapped in a task.</returns>
|
||||
Task<ILiveStream> GetChannelStream(string channelId, string streamId, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
@@ -18,23 +18,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvChannel : BaseItem, IHasMediaSources, IHasProgramAttributes
|
||||
{
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (!ConfigurationManager.Configuration.DisableLiveTvChannelUserDataName)
|
||||
{
|
||||
list.Insert(0, GetClientTypeName() + "-" + Name);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.LiveTvChannel;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPositionTicksResume => false;
|
||||
|
||||
@@ -59,6 +42,67 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
[JsonIgnore]
|
||||
public override LocationType LocationType => LocationType.Remote;
|
||||
|
||||
[JsonIgnore]
|
||||
public override string MediaType => ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is sports.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsSports { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is series.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is news.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsNews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is kids.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
[JsonIgnore]
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (!ConfigurationManager.Configuration.DisableLiveTvChannelUserDataName)
|
||||
{
|
||||
list.Insert(0, GetClientTypeName() + "-" + Name);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override UnratedItem GetBlockUnratedType()
|
||||
{
|
||||
return UnratedItem.LiveTvChannel;
|
||||
}
|
||||
|
||||
protected override string CreateSortName()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Number))
|
||||
@@ -72,15 +116,12 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return (Number ?? string.Empty) + "-" + (Name ?? string.Empty);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override string MediaType => ChannelType == ChannelType.Radio ? Model.Entities.MediaType.Audio : Model.Entities.MediaType.Video;
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
return "TvChannel";
|
||||
}
|
||||
|
||||
public IEnumerable<BaseItem> GetTaggedItems(IEnumerable<BaseItem> inputItems)
|
||||
public IEnumerable<BaseItem> GetTaggedItems()
|
||||
{
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
@@ -120,46 +161,5 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is sports.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsSports { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is series.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is series; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is news.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsNews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is kids.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsRepeat { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the episode title.
|
||||
/// </summary>
|
||||
/// <value>The episode title.</value>
|
||||
[JsonIgnore]
|
||||
public string EpisodeTitle { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS1591, SA1306
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -8,6 +8,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
@@ -19,54 +20,14 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes
|
||||
{
|
||||
private static string EmbyServiceName = "Emby";
|
||||
|
||||
public LiveTvProgram()
|
||||
{
|
||||
IsVirtualItem = true;
|
||||
}
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (!IsSeries)
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(EpisodeTitle))
|
||||
{
|
||||
var name = GetClientTypeName();
|
||||
|
||||
list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private static string EmbyServiceName = "Emby";
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
var serviceName = ServiceName;
|
||||
|
||||
if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2.0 / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 16.0 / 9;
|
||||
}
|
||||
}
|
||||
public string SeriesName { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override SourceType SourceType => SourceType.LiveTV;
|
||||
@@ -106,7 +67,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsSports => Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsSports => Tags.Contains("Sports", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is series.
|
||||
@@ -120,28 +81,28 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsLive => Tags.Contains("Live", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is news.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsNews => Tags.Contains("News", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is kids.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is premiere.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsPremiere => Tags.Contains("Premiere", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder containing the item.
|
||||
@@ -182,6 +143,66 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople
|
||||
{
|
||||
get
|
||||
{
|
||||
// Optimization
|
||||
if (IsNews || IsSports)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.SupportsPeople;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
public override List<string> GetUserDataKeys()
|
||||
{
|
||||
var list = base.GetUserDataKeys();
|
||||
|
||||
if (!IsSeries)
|
||||
{
|
||||
var key = this.GetProviderId(MetadataProvider.Imdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
|
||||
key = this.GetProviderId(MetadataProvider.Tmdb);
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
list.Insert(0, key);
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(EpisodeTitle))
|
||||
{
|
||||
var name = GetClientTypeName();
|
||||
|
||||
list.Insert(0, name + "-" + Name + (EpisodeTitle ?? string.Empty));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
var serviceName = ServiceName;
|
||||
|
||||
if (string.Equals(serviceName, EmbyServiceName, StringComparison.OrdinalIgnoreCase) || string.Equals(serviceName, "Next Pvr", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return 2.0 / 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 16.0 / 9;
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetClientTypeName()
|
||||
{
|
||||
return "Program";
|
||||
@@ -202,24 +223,6 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
return false;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsPeople
|
||||
{
|
||||
get
|
||||
{
|
||||
// Optimization
|
||||
if (IsNews || IsSports)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.SupportsPeople;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsAncestors => false;
|
||||
|
||||
private LiveTvOptions GetConfiguration()
|
||||
{
|
||||
return ConfigurationManager.GetConfiguration<LiveTvOptions>("livetv");
|
||||
@@ -273,7 +276,5 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public string SeriesName { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.LiveTv;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
@@ -123,11 +123,11 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public bool IsSports => Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsSports => Tags.Contains("Sports", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsNews => Tags.Contains("News", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
@@ -136,10 +136,10 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsLive => Tags.Contains("Live", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
|
||||
public bool IsPremiere => Tags.Contains("Premiere", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
public int? ProductionYear { get; set; }
|
||||
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />
|
||||
<PackageReference Include="Diacritics" Version="3.3.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -31,13 +32,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release' ">true</TreatWarningsAsErrors>
|
||||
<Nullable>enable</Nullable>
|
||||
<AnalysisMode Condition=" '$(Configuration)' == 'Debug' ">AllEnabledByDefault</AnalysisMode>
|
||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
|
||||
@@ -10,6 +10,15 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
public class BaseEncodingJobOptions
|
||||
{
|
||||
public BaseEncodingJobOptions()
|
||||
{
|
||||
EnableAutoStreamCopy = true;
|
||||
AllowVideoStreamCopy = true;
|
||||
AllowAudioStreamCopy = true;
|
||||
Context = EncodingContext.Streaming;
|
||||
StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
@@ -191,14 +200,5 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public BaseEncodingJobOptions()
|
||||
{
|
||||
EnableAutoStreamCopy = true;
|
||||
AllowVideoStreamCopy = true;
|
||||
AllowAudioStreamCopy = true;
|
||||
Context = EncodingContext.Streaming;
|
||||
StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS1591, SA1401
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -20,6 +20,44 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// For now, a common base class until the API and MediaEncoding classes are unified
|
||||
public class EncodingJobInfo
|
||||
{
|
||||
public int? OutputAudioBitrate;
|
||||
public int? OutputAudioChannels;
|
||||
|
||||
private TranscodeReason[] _transcodeReasons = null;
|
||||
|
||||
public EncodingJobInfo(TranscodingJobType jobType)
|
||||
{
|
||||
TranscodingType = jobType;
|
||||
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SupportedAudioCodecs = Array.Empty<string>();
|
||||
SupportedVideoCodecs = Array.Empty<string>();
|
||||
SupportedSubtitleCodecs = Array.Empty<string>();
|
||||
}
|
||||
|
||||
public TranscodeReason[] TranscodeReasons
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_transcodeReasons == null)
|
||||
{
|
||||
if (BaseRequest.TranscodeReasons == null)
|
||||
{
|
||||
return Array.Empty<TranscodeReason>();
|
||||
}
|
||||
|
||||
_transcodeReasons = BaseRequest.TranscodeReasons
|
||||
.Split(',')
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return _transcodeReasons;
|
||||
}
|
||||
}
|
||||
|
||||
public IProgress<double> Progress { get; set; }
|
||||
|
||||
public MediaStream VideoStream { get; set; }
|
||||
|
||||
public VideoType VideoType { get; set; }
|
||||
@@ -58,40 +96,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
public string MimeType { get; set; }
|
||||
|
||||
public string GetMimeType(string outputPath, bool enableStreamDefault = true)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(MimeType))
|
||||
{
|
||||
return MimeType;
|
||||
}
|
||||
|
||||
return MimeTypes.GetMimeType(outputPath, enableStreamDefault);
|
||||
}
|
||||
|
||||
private TranscodeReason[] _transcodeReasons = null;
|
||||
|
||||
public TranscodeReason[] TranscodeReasons
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_transcodeReasons == null)
|
||||
{
|
||||
if (BaseRequest.TranscodeReasons == null)
|
||||
{
|
||||
return Array.Empty<TranscodeReason>();
|
||||
}
|
||||
|
||||
_transcodeReasons = BaseRequest.TranscodeReasons
|
||||
.Split(',')
|
||||
.Where(i => !string.IsNullOrEmpty(i))
|
||||
.Select(v => (TranscodeReason)Enum.Parse(typeof(TranscodeReason), v, true))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
return _transcodeReasons;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IgnoreInputDts => MediaSource.IgnoreDts;
|
||||
|
||||
public bool IgnoreInputIndex => MediaSource.IgnoreIndex;
|
||||
@@ -144,196 +148,17 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
public BaseEncodingJobOptions BaseRequest { get; set; }
|
||||
|
||||
public long? StartTimeTicks => BaseRequest.StartTimeTicks;
|
||||
|
||||
public bool CopyTimestamps => BaseRequest.CopyTimestamps;
|
||||
|
||||
public int? OutputAudioBitrate;
|
||||
public int? OutputAudioChannels;
|
||||
|
||||
public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced)
|
||||
{
|
||||
var videoStream = VideoStream;
|
||||
var isInputInterlaced = videoStream != null && videoStream.IsInterlaced;
|
||||
|
||||
if (!isInputInterlaced)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support general param
|
||||
if (BaseRequest.DeInterlace)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(videoCodec))
|
||||
{
|
||||
if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return forceDeinterlaceIfSourceIsInterlaced && isInputInterlaced;
|
||||
}
|
||||
|
||||
public string[] GetRequestedProfiles(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BaseRequest.Profile))
|
||||
{
|
||||
return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var profile = BaseRequest.GetOption(codec, "profile");
|
||||
|
||||
if (!string.IsNullOrEmpty(profile))
|
||||
{
|
||||
return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string GetRequestedLevel(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BaseRequest.Level))
|
||||
{
|
||||
return BaseRequest.Level;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
return BaseRequest.GetOption(codec, "level");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedMaxRefFrames(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxRefFrames.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxRefFrames;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "maxrefframes");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedVideoBitDepth(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxVideoBitDepth.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxVideoBitDepth;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "videobitdepth");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedAudioBitDepth(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxAudioBitDepth.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxAudioBitDepth;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiobitdepth");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedAudioChannels(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiochannels");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseRequest.MaxAudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxAudioChannels;
|
||||
}
|
||||
|
||||
if (BaseRequest.AudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.AudioChannels;
|
||||
}
|
||||
|
||||
if (BaseRequest.TranscodingMaxAudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.TranscodingMaxAudioChannels;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsVideoRequest { get; set; }
|
||||
|
||||
public TranscodingJobType TranscodingType { get; set; }
|
||||
|
||||
public EncodingJobInfo(TranscodingJobType jobType)
|
||||
{
|
||||
TranscodingType = jobType;
|
||||
RemoteHttpHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SupportedAudioCodecs = Array.Empty<string>();
|
||||
SupportedVideoCodecs = Array.Empty<string>();
|
||||
SupportedSubtitleCodecs = Array.Empty<string>();
|
||||
}
|
||||
public long? StartTimeTicks => BaseRequest.StartTimeTicks;
|
||||
|
||||
public bool CopyTimestamps => BaseRequest.CopyTimestamps;
|
||||
|
||||
public bool IsSegmentedLiveStream
|
||||
=> TranscodingType != TranscodingJobType.Progressive && !RunTimeTicks.HasValue;
|
||||
|
||||
public bool EnableBreakOnNonKeyFrames(string videoCodec)
|
||||
{
|
||||
if (TranscodingType != TranscodingJobType.Progressive)
|
||||
{
|
||||
if (IsSegmentedLiveStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int? TotalOutputBitrate => (OutputAudioBitrate ?? 0) + (OutputVideoBitrate ?? 0);
|
||||
|
||||
public int? OutputWidth
|
||||
@@ -597,7 +422,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (EncodingHelper.IsCopyCodec(OutputVideoCodec))
|
||||
{
|
||||
return VideoStream?.Codec;
|
||||
return VideoStream.Codec;
|
||||
}
|
||||
|
||||
return OutputVideoCodec;
|
||||
@@ -615,7 +440,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (EncodingHelper.IsCopyCodec(OutputAudioCodec))
|
||||
{
|
||||
return AudioStream?.Codec;
|
||||
return AudioStream.Codec;
|
||||
}
|
||||
|
||||
return OutputAudioCodec;
|
||||
@@ -682,6 +507,21 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
public int HlsListSize => 0;
|
||||
|
||||
public bool EnableBreakOnNonKeyFrames(string videoCodec)
|
||||
{
|
||||
if (TranscodingType != TranscodingJobType.Progressive)
|
||||
{
|
||||
if (IsSegmentedLiveStream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return BaseRequest.BreakOnNonKeyFrames && EncodingHelper.IsCopyCodec(videoCodec);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int? GetMediaStreamCount(MediaStreamType type, int limit)
|
||||
{
|
||||
var count = MediaSource.GetStreamCount(type);
|
||||
@@ -694,7 +534,172 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return count;
|
||||
}
|
||||
|
||||
public IProgress<double> Progress { get; set; }
|
||||
public string GetMimeType(string outputPath, bool enableStreamDefault = true)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(MimeType))
|
||||
{
|
||||
return MimeType;
|
||||
}
|
||||
|
||||
if (enableStreamDefault)
|
||||
{
|
||||
return MimeTypes.GetMimeType(outputPath);
|
||||
}
|
||||
|
||||
return MimeTypes.GetMimeType(outputPath, null);
|
||||
}
|
||||
|
||||
public bool DeInterlace(string videoCodec, bool forceDeinterlaceIfSourceIsInterlaced)
|
||||
{
|
||||
var videoStream = VideoStream;
|
||||
var isInputInterlaced = videoStream != null && videoStream.IsInterlaced;
|
||||
|
||||
if (!isInputInterlaced)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Support general param
|
||||
if (BaseRequest.DeInterlace)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(videoCodec))
|
||||
{
|
||||
if (string.Equals(BaseRequest.GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return forceDeinterlaceIfSourceIsInterlaced;
|
||||
}
|
||||
|
||||
public string[] GetRequestedProfiles(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BaseRequest.Profile))
|
||||
{
|
||||
return BaseRequest.Profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var profile = BaseRequest.GetOption(codec, "profile");
|
||||
|
||||
if (!string.IsNullOrEmpty(profile))
|
||||
{
|
||||
return profile.Split(new[] { '|', ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
public string GetRequestedLevel(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(BaseRequest.Level))
|
||||
{
|
||||
return BaseRequest.Level;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
return BaseRequest.GetOption(codec, "level");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedMaxRefFrames(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxRefFrames.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxRefFrames;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "maxrefframes");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedVideoBitDepth(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxVideoBitDepth.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxVideoBitDepth;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "videobitdepth");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedAudioBitDepth(string codec)
|
||||
{
|
||||
if (BaseRequest.MaxAudioBitDepth.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxAudioBitDepth;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiobitdepth");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int? GetRequestedAudioChannels(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiochannels");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseRequest.MaxAudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxAudioChannels;
|
||||
}
|
||||
|
||||
if (BaseRequest.AudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.AudioChannels;
|
||||
}
|
||||
|
||||
if (BaseRequest.TranscodingMaxAudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.TranscodingMaxAudioChannels;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate)
|
||||
{
|
||||
|
||||
23
MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs
Normal file
23
MediaBrowser.Controller/MediaEncoding/FilterOptionType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum FilterOptionType.
|
||||
/// </summary>
|
||||
public enum FilterOptionType
|
||||
{
|
||||
/// <summary>
|
||||
/// The scale_cuda_format.
|
||||
/// </summary>
|
||||
ScaleCudaFormat = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The tonemap_cuda_name.
|
||||
/// </summary>
|
||||
TonemapCudaName = 1,
|
||||
|
||||
/// <summary>
|
||||
/// The tonemap_opencl_bt2390.
|
||||
/// </summary>
|
||||
TonemapOpenclBt2390 = 2
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <summary>
|
||||
/// Refreshes the chapter images.
|
||||
/// </summary>
|
||||
/// <param name="video">Video to use.</param>
|
||||
/// <param name="directoryService">Directory service to use.</param>
|
||||
/// <param name="chapters">Set of chapters to refresh.</param>
|
||||
/// <param name="extractImages">Option to extract images.</param>
|
||||
/// <param name="saveChapters">Option to save chapters.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns><c>true</c> if successful, <c>false</c> if not.</returns>
|
||||
Task<bool> RefreshChapterImages(Video video, IDirectoryService directoryService, IReadOnlyList<ChapterInfo> chapters, bool extractImages, bool saveChapters, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Drawing;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.System;
|
||||
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
@@ -19,11 +19,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// </summary>
|
||||
public interface IMediaEncoder : ITranscoderSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets location of the discovered FFmpeg tool.
|
||||
/// </summary>
|
||||
FFmpegLocation EncoderLocation { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the encoder path.
|
||||
/// </summary>
|
||||
@@ -55,9 +50,21 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// Whether given filter is supported.
|
||||
/// </summary>
|
||||
/// <param name="filter">The filter.</param>
|
||||
/// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
|
||||
bool SupportsFilter(string filter);
|
||||
|
||||
/// <summary>
|
||||
/// Whether filter is supported with the given option.
|
||||
/// </summary>
|
||||
/// <param name="option">The option.</param>
|
||||
/// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
|
||||
bool SupportsFilter(string filter, string option);
|
||||
bool SupportsFilterWithOption(FilterOptionType option);
|
||||
|
||||
/// <summary>
|
||||
/// Get the version of media encoder.
|
||||
/// </summary>
|
||||
/// <returns>The version of media encoder.</returns>
|
||||
Version GetMediaEncoderVersion();
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the audio image.
|
||||
@@ -71,24 +78,28 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <summary>
|
||||
/// Extracts the video image.
|
||||
/// </summary>
|
||||
/// <param name="inputFile">Input file.</param>
|
||||
/// <param name="container">Video container type.</param>
|
||||
/// <param name="mediaSource">Media source information.</param>
|
||||
/// <param name="videoStream">Media stream information.</param>
|
||||
/// <param name="threedFormat">Video 3D format.</param>
|
||||
/// <param name="offset">Time offset.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Location of video image.</returns>
|
||||
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream videoStream, Video3DFormat? threedFormat, TimeSpan? offset, CancellationToken cancellationToken);
|
||||
|
||||
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the video images on interval.
|
||||
/// Extracts the video image.
|
||||
/// </summary>
|
||||
Task ExtractVideoImagesOnInterval(
|
||||
string inputFile,
|
||||
string container,
|
||||
MediaStream videoStream,
|
||||
MediaSourceInfo mediaSource,
|
||||
Video3DFormat? threedFormat,
|
||||
TimeSpan interval,
|
||||
string targetDirectory,
|
||||
string filenamePrefix,
|
||||
int? maxWidth,
|
||||
CancellationToken cancellationToken);
|
||||
/// <param name="inputFile">Input file.</param>
|
||||
/// <param name="container">Video container type.</param>
|
||||
/// <param name="mediaSource">Media source information.</param>
|
||||
/// <param name="imageStream">Media stream information.</param>
|
||||
/// <param name="imageStreamIndex">Index of the stream to extract from.</param>
|
||||
/// <param name="targetFormat">The format of the file to write.</param>
|
||||
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
|
||||
/// <returns>Location of video image.</returns>
|
||||
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, ImageFormat? targetFormat, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the media info.
|
||||
@@ -122,10 +133,24 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <returns>System.String.</returns>
|
||||
string EscapeSubtitleFilterPath(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the path to find FFmpeg.
|
||||
/// </summary>
|
||||
void SetFFmpegPath();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the encoder path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <param name="pathType">The type of path.</param>
|
||||
void UpdateEncoderPath(string path, string pathType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the primary playlist of .vob files.
|
||||
/// </summary>
|
||||
/// <param name="path">The to the .vob files.</param>
|
||||
/// <param name="titleNumber">The title number to start with.</param>
|
||||
/// <returns>A playlist.</returns>
|
||||
IEnumerable<string> GetPrimaryPlaylistVobFiles(string path, uint? titleNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,14 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
/// <summary>
|
||||
/// Gets the subtitles.
|
||||
/// </summary>
|
||||
/// <param name="item">Item to use.</param>
|
||||
/// <param name="mediaSourceId">Media source.</param>
|
||||
/// <param name="subtitleStreamIndex">Subtitle stream to use.</param>
|
||||
/// <param name="outputFormat">Output format to use.</param>
|
||||
/// <param name="startTimeTicks">Start time.</param>
|
||||
/// <param name="endTimeTicks">End time.</param>
|
||||
/// <param name="preserveOriginalTimestamps">Option to preserve original timestamps.</param>
|
||||
/// <param name="cancellationToken">The cancellation token for the operation.</param>
|
||||
/// <returns>Task{Stream}.</returns>
|
||||
Task<Stream> GetSubtitles(
|
||||
BaseItem item,
|
||||
|
||||
@@ -6,7 +6,6 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -14,7 +13,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
public class JobLogger
|
||||
{
|
||||
private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public JobLogger(ILogger logger)
|
||||
@@ -88,7 +86,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
var rate = parts[i + 1];
|
||||
|
||||
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
|
||||
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
|
||||
{
|
||||
framerate = val;
|
||||
}
|
||||
@@ -97,7 +95,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
var rate = part.Split('=', 2)[^1];
|
||||
|
||||
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
|
||||
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
|
||||
{
|
||||
framerate = val;
|
||||
}
|
||||
@@ -107,7 +105,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
var time = part.Split('=', 2)[^1];
|
||||
|
||||
if (TimeSpan.TryParse(time, _usCulture, out var val))
|
||||
if (TimeSpan.TryParse(time, CultureInfo.InvariantCulture, out var val))
|
||||
{
|
||||
var currentMs = startMs + val.TotalMilliseconds;
|
||||
|
||||
@@ -121,7 +119,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var size = part.Split('=', 2)[^1];
|
||||
|
||||
int? scale = null;
|
||||
if (size.IndexOf("kb", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (size.Contains("kb", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
scale = 1024;
|
||||
size = size.Replace("kb", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
@@ -129,7 +127,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (scale.HasValue)
|
||||
{
|
||||
if (long.TryParse(size, NumberStyles.Any, _usCulture, out var val))
|
||||
if (long.TryParse(size, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
|
||||
{
|
||||
bytesTranscoded = val * scale.Value;
|
||||
}
|
||||
@@ -140,7 +138,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var rate = part.Split('=', 2)[^1];
|
||||
|
||||
int? scale = null;
|
||||
if (rate.IndexOf("kbits/s", StringComparison.OrdinalIgnoreCase) != -1)
|
||||
if (rate.Contains("kbits/s", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
scale = 1024;
|
||||
rate = rate.Replace("kbits/s", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
@@ -148,7 +146,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (scale.HasValue)
|
||||
{
|
||||
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
|
||||
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
|
||||
{
|
||||
bitRate = (int)Math.Ceiling(val * scale.Value);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CS1591, SA1306, SA1401
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -30,6 +30,21 @@ namespace MediaBrowser.Controller.Net
|
||||
private readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> _activeConnections =
|
||||
new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>();
|
||||
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
protected ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger;
|
||||
|
||||
protected BasePeriodicWebSocketListener(ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> logger)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type used for the messages sent to the client.
|
||||
/// </summary>
|
||||
@@ -54,21 +69,6 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <returns>Task{`1}.</returns>
|
||||
protected abstract Task<TReturnDataType> GetDataToSend();
|
||||
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// </summary>
|
||||
protected ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger;
|
||||
|
||||
protected BasePeriodicWebSocketListener(ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> logger)
|
||||
{
|
||||
if (logger == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes the message.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
@@ -12,6 +13,6 @@ namespace MediaBrowser.Controller.Net
|
||||
/// </summary>
|
||||
/// <param name="request">The request.</param>
|
||||
/// <returns>Authorization information. Null if unauthenticated.</returns>
|
||||
AuthorizationInfo Authenticate(HttpRequest request);
|
||||
Task<AuthorizationInfo> Authenticate(HttpRequest request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
@@ -11,14 +12,14 @@ namespace MediaBrowser.Controller.Net
|
||||
/// Gets the authorization information.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <returns>AuthorizationInfo.</returns>
|
||||
AuthorizationInfo GetAuthorizationInfo(HttpContext requestContext);
|
||||
/// <returns>A task containing the authorization info.</returns>
|
||||
Task<AuthorizationInfo> GetAuthorizationInfo(HttpContext requestContext);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the authorization information.
|
||||
/// </summary>
|
||||
/// <param name="requestContext">The request context.</param>
|
||||
/// <returns>AuthorizationInfo.</returns>
|
||||
AuthorizationInfo GetAuthorizationInfo(HttpRequest requestContext);
|
||||
/// <returns>A <see cref="Task"/> containing the authorization info.</returns>
|
||||
Task<AuthorizationInfo> GetAuthorizationInfo(HttpRequest requestContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Data.Entities;
|
||||
using MediaBrowser.Controller.Session;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@@ -8,12 +9,12 @@ namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public interface ISessionContext
|
||||
{
|
||||
SessionInfo GetSession(object requestContext);
|
||||
Task<SessionInfo> GetSession(object requestContext);
|
||||
|
||||
User? GetUser(object requestContext);
|
||||
Task<User?> GetUser(object requestContext);
|
||||
|
||||
SessionInfo GetSession(HttpContext requestContext);
|
||||
Task<SessionInfo> GetSession(HttpContext requestContext);
|
||||
|
||||
User? GetUser(HttpContext requestContext);
|
||||
Task<User?> GetUser(HttpContext requestContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,17 +49,17 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <summary>
|
||||
/// Gets chapters for an item.
|
||||
/// </summary>
|
||||
/// <param name="id">The item.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <returns>The list of chapter info.</returns>
|
||||
List<ChapterInfo> GetChapters(BaseItem id);
|
||||
List<ChapterInfo> GetChapters(BaseItem item);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single chapter for an item.
|
||||
/// </summary>
|
||||
/// <param name="id">The item.</param>
|
||||
/// <param name="item">The item.</param>
|
||||
/// <param name="index">The chapter index.</param>
|
||||
/// <returns>The chapter info at the specified index.</returns>
|
||||
ChapterInfo GetChapter(BaseItem id, int index);
|
||||
ChapterInfo GetChapter(BaseItem item, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the chapters.
|
||||
|
||||
@@ -18,7 +18,6 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="userData">The user data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
void SaveUserData(long userId, string key, UserItemData userData, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -31,24 +31,18 @@ namespace MediaBrowser.Controller.Playlists
|
||||
".zpl"
|
||||
};
|
||||
|
||||
public Guid OwnerUserId { get; set; }
|
||||
|
||||
public Share[] Shares { get; set; }
|
||||
|
||||
public Playlist()
|
||||
{
|
||||
Shares = Array.Empty<Share>();
|
||||
}
|
||||
|
||||
public Guid OwnerUserId { get; set; }
|
||||
|
||||
public Share[] Shares { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsFile => IsPlaylistFile(Path);
|
||||
|
||||
public static bool IsPlaylistFile(string path)
|
||||
{
|
||||
// The path will sometimes be a directory and "Path.HasExtension" returns true if the name contains a '.' (dot).
|
||||
return System.IO.Path.HasExtension(path) && !Directory.Exists(path);
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override string ContainingFolderPath
|
||||
{
|
||||
@@ -80,6 +74,41 @@ namespace MediaBrowser.Controller.Playlists
|
||||
[JsonIgnore]
|
||||
public override bool SupportsCumulativeRunTimeTicks => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
public string PlaylistMediaType { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override string MediaType => PlaylistMediaType;
|
||||
|
||||
[JsonIgnore]
|
||||
private bool IsSharedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
var path = Path;
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, path);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsPlaylistFile(string path)
|
||||
{
|
||||
// The path will sometimes be a directory and "Path.HasExtension" returns true if the name contains a '.' (dot).
|
||||
return System.IO.Path.HasExtension(path) && !Directory.Exists(path);
|
||||
}
|
||||
|
||||
public void SetMediaType(string value)
|
||||
{
|
||||
PlaylistMediaType = value;
|
||||
}
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
return 1;
|
||||
@@ -160,7 +189,7 @@ namespace MediaBrowser.Controller.Playlists
|
||||
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
IncludeItemTypes = new[] { nameof(Audio) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Audio },
|
||||
GenreIds = new[] { musicGenre.Id },
|
||||
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
|
||||
DtoOptions = options
|
||||
@@ -172,7 +201,7 @@ namespace MediaBrowser.Controller.Playlists
|
||||
return LibraryManager.GetItemList(new InternalItemsQuery(user)
|
||||
{
|
||||
Recursive = true,
|
||||
IncludeItemTypes = new[] { nameof(Audio) },
|
||||
IncludeItemTypes = new[] { BaseItemKind.Audio },
|
||||
ArtistIds = new[] { musicArtist.Id },
|
||||
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
|
||||
DtoOptions = options
|
||||
@@ -197,35 +226,6 @@ namespace MediaBrowser.Controller.Playlists
|
||||
return new[] { item };
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool IsPreSorted => true;
|
||||
|
||||
public string PlaylistMediaType { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public override string MediaType => PlaylistMediaType;
|
||||
|
||||
public void SetMediaType(string value)
|
||||
{
|
||||
PlaylistMediaType = value;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private bool IsSharedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
var path = Path;
|
||||
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, path);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsVisible(User user)
|
||||
{
|
||||
if (!IsSharedItem)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma warning disable CS1591
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Providers
|
||||
|
||||
public FileSystemMetadata[] GetFileSystemEntries(string path)
|
||||
{
|
||||
return _cache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
|
||||
return _cache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
|
||||
}
|
||||
|
||||
public List<FileSystemMetadata> GetFiles(string path)
|
||||
@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.Providers
|
||||
_filePathCache.TryRemove(path, out _);
|
||||
}
|
||||
|
||||
var filePaths = _filePathCache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFilePaths(p).ToList(), _fileSystem);
|
||||
var filePaths = _filePathCache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFilePaths(p).ToList(), _fileSystem);
|
||||
|
||||
if (sort)
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user