Merge branch 'master' into EraYaN-add-management-interface

This commit is contained in:
Claus Vium
2021-08-18 08:56:14 +02:00
committed by GitHub
1474 changed files with 53223 additions and 28534 deletions

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using MediaBrowser.Controller.Session;

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System.Threading.Tasks;

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;

View File

@@ -0,0 +1,137 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.BaseItemManager
{
/// <inheritdoc />
public class BaseItemManager : IBaseItemManager
{
private readonly IServerConfigurationManager _serverConfigurationManager;
private int _metadataRefreshConcurrency;
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemManager"/> class.
/// </summary>
/// <param name="serverConfigurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
public BaseItemManager(IServerConfigurationManager serverConfigurationManager)
{
_serverConfigurationManager = serverConfigurationManager;
_metadataRefreshConcurrency = GetMetadataRefreshConcurrency();
SetupMetadataThrottler();
_serverConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
}
/// <inheritdoc />
public SemaphoreSlim MetadataRefreshThrottler { get; private set; }
/// <inheritdoc />
public bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name)
{
if (baseItem is Channel)
{
// Hack alert.
return true;
}
if (baseItem.SourceType == SourceType.Channel)
{
// Hack alert.
return !baseItem.EnableMediaSourceDisplay;
}
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
if (typeOptions != null)
{
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));
return itemConfig == null || !itemConfig.DisabledMetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}
/// <inheritdoc />
public bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name)
{
if (baseItem is Channel)
{
// Hack alert.
return true;
}
if (baseItem.SourceType == SourceType.Channel)
{
// Hack alert.
return !baseItem.EnableMediaSourceDisplay;
}
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
if (typeOptions != null)
{
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));
return itemConfig == null || !itemConfig.DisabledImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 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)
{
int newMetadataRefreshConcurrency = GetMetadataRefreshConcurrency();
if (_metadataRefreshConcurrency != newMetadataRefreshConcurrency)
{
_metadataRefreshConcurrency = newMetadataRefreshConcurrency;
SetupMetadataThrottler();
}
}
/// <summary>
/// Creates the metadata refresh throttler.
/// </summary>
[MemberNotNull(nameof(MetadataRefreshThrottler))]
private void SetupMetadataThrottler()
{
MetadataRefreshThrottler = new SemaphoreSlim(_metadataRefreshConcurrency);
}
/// <summary>
/// Returns the metadata refresh concurrency.
/// </summary>
private int GetMetadataRefreshConcurrency()
{
var concurrency = _serverConfigurationManager.Configuration.LibraryMetadataRefreshConcurrency;
if (concurrency <= 0)
{
concurrency = Environment.ProcessorCount;
}
return concurrency;
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Threading;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration;
namespace MediaBrowser.Controller.BaseItemManager
{
/// <summary>
/// The <c>BaseItem</c> manager.
/// </summary>
public interface IBaseItemManager
{
/// <summary>
/// Gets the semaphore used to limit the amount of concurrent metadata refreshes.
/// </summary>
SemaphoreSlim MetadataRefreshThrottler { get; }
/// <summary>
/// Is metadata fetcher enabled.
/// </summary>
/// <param name="baseItem">The base item.</param>
/// <param name="libraryOptions">The library options.</param>
/// <param name="name">The metadata fetcher name.</param>
/// <returns><c>true</c> if metadata fetcher is enabled, else false.</returns>
bool IsMetadataFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
/// <summary>
/// Is image fetcher enabled.
/// </summary>
/// <param name="baseItem">The base item.</param>
/// <param name="libraryOptions">The library options.</param>
/// <param name="name">The image fetcher name.</param>
/// <returns><c>true</c> if image fetcher is enabled, else false.</returns>
bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -15,11 +17,18 @@ 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)
{
if (user.GetPreference(PreferenceKind.BlockedChannels) != null)
var blockedChannelsPreference = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedChannels);
if (blockedChannelsPreference.Length != 0)
{
if (user.GetPreference(PreferenceKind.BlockedChannels).Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
if (blockedChannelsPreference.Contains(Id))
{
return false;
}
@@ -27,8 +36,7 @@ namespace MediaBrowser.Controller.Channels
else
{
if (!user.HasPermission(PermissionKind.EnableAllChannels)
&& !user.GetPreference(PreferenceKind.EnabledChannels)
.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
&& !user.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels).Contains(Id))
{
return false;
}
@@ -37,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
@@ -82,7 +84,7 @@ namespace MediaBrowser.Controller.Channels
internal static bool IsChannelVisible(BaseItem channelItem, User user)
{
var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(""));
var channel = ChannelManager.GetChannel(channelItem.ChannelId.ToString(string.Empty));
return channel.IsVisible(user);
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1002, CA2227, CS1591
using System;
using System.Collections.Generic;
@@ -11,6 +13,19 @@ namespace MediaBrowser.Controller.Channels
{
public class ChannelItemInfo : IHasProviderIds
{
public ChannelItemInfo()
{
MediaSources = new List<MediaSourceInfo>();
TrailerTypes = new List<TrailerType>();
Genres = new List<string>();
Studios = new List<string>();
People = new List<PersonInfo>();
Tags = new List<string>();
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Artists = new List<string>();
AlbumArtists = new List<string>();
}
public string Name { get; set; }
public string SeriesName { get; set; }
@@ -78,18 +93,5 @@ namespace MediaBrowser.Controller.Channels
public bool IsLiveStream { get; set; }
public string Etag { get; set; }
public ChannelItemInfo()
{
MediaSources = new List<MediaSourceInfo>();
TrailerTypes = new List<TrailerType>();
Genres = new List<string>();
Studios = new List<string>();
People = new List<PersonInfo>();
Tags = new List<string>();
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
Artists = new List<string>();
AlbumArtists = new List<string>();
}
}
}

View File

@@ -1,18 +1,19 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
namespace MediaBrowser.Controller.Channels
{
public class ChannelItemResult
{
public List<ChannelItemInfo> Items { get; set; }
public int? TotalRecordCount { get; set; }
public ChannelItemResult()
{
Items = new List<ChannelItemInfo>();
Items = Array.Empty<ChannelItemInfo>();
}
public IReadOnlyList<ChannelItemInfo> Items { get; set; }
public int? TotalRecordCount { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
#nullable disable
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Channels
{
public class ChannelLatestMediaSearch
{
public string UserId { get; set; }
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Channels
@@ -8,9 +10,4 @@ namespace MediaBrowser.Controller.Channels
public string UserId { get; set; }
}
public class ChannelLatestMediaSearch
{
public string UserId { get; set; }
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System.Collections.Generic;

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -24,7 +26,7 @@ namespace MediaBrowser.Controller.Channels
/// </summary>
/// <param name="id">The identifier.</param>
/// <returns>ChannelFeatures.</returns>
ChannelFeatures GetChannelFeatures(string id);
ChannelFeatures GetChannelFeatures(Guid? id);
/// <summary>
/// Gets all channel features.
@@ -49,32 +51,47 @@ namespace MediaBrowser.Controller.Channels
/// Gets the channels internal.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The channels.</returns>
QueryResult<Channel> GetChannelsInternal(ChannelQuery query);
/// <summary>
/// Gets the channels.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>The channels.</returns>
QueryResult<BaseItemDto> GetChannels(ChannelQuery query);
/// <summary>
/// Gets the latest media.
/// Gets the latest channel items.
/// </summary>
/// <param name="query">The item query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The latest channels.</returns>
Task<QueryResult<BaseItemDto>> GetLatestChannelItems(InternalItemsQuery query, CancellationToken cancellationToken);
/// <summary>
/// Gets the latest media.
/// Gets the latest channel items.
/// </summary>
/// <param name="query">The item query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The latest channels.</returns>
Task<QueryResult<BaseItem>> GetLatestChannelItemsInternal(InternalItemsQuery query, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel items.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The channel items.</returns>
Task<QueryResult<BaseItemDto>> GetChannelItems(InternalItemsQuery query, CancellationToken cancellationToken);
/// <summary>
/// Gets the channel items internal.
/// Gets the channel items.
/// </summary>
/// <param name="query">The query.</param>
/// <param name="progress">The progress to report to.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The channel items.</returns>
Task<QueryResult<BaseItem>> GetChannelItemsInternal(InternalItemsQuery query, IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
@@ -82,9 +99,14 @@ namespace MediaBrowser.Controller.Channels
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{MediaSourceInfo}}.</returns>
/// <returns>The item media sources.</returns>
IEnumerable<MediaSourceInfo> GetStaticMediaSources(BaseItem item, CancellationToken cancellationToken);
/// <summary>
/// Whether the item supports media probe.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>Whether media probe should be enabled.</returns>
bool EnableMediaProbe(BaseItem item);
}
}

View File

@@ -0,0 +1,12 @@
namespace MediaBrowser.Controller.Channels
{
/// <summary>
/// Disable media source display.
/// </summary>
/// <remarks>
/// <see cref="Channel"/> can inherit this interface to disable being displayed.
/// </remarks>
public interface IDisableMediaSourceDisplay
{
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Channels

View File

@@ -0,0 +1,9 @@
#pragma warning disable CA1819, CS1591
namespace MediaBrowser.Controller.Channels
{
public interface IHasFolderAttributes
{
string[] Attributes { get; }
}
}

View File

@@ -1,5 +1,3 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -7,11 +5,17 @@ using MediaBrowser.Model.Dto;
namespace MediaBrowser.Controller.Channels
{
/// <summary>
/// The channel requires a media info callback.
/// </summary>
public interface IRequiresMediaInfoCallback
{
/// <summary>
/// Gets the channel item media information.
/// </summary>
/// <param name="id">The channel item id.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The enumerable of media source info.</returns>
Task<IEnumerable<MediaSourceInfo>> GetChannelItemMediaInfo(string id, CancellationToken cancellationToken);
}
}

View File

@@ -1,9 +1,10 @@
#nullable disable
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Channels
{
@@ -17,35 +18,4 @@ namespace MediaBrowser.Controller.Channels
/// <returns>Task{IEnumerable{ChannelItemInfo}}.</returns>
Task<IEnumerable<ChannelItemInfo>> Search(ChannelSearchInfo searchInfo, CancellationToken cancellationToken);
}
public interface ISupportsLatestMedia
{
/// <summary>
/// Gets the latest media.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{IEnumerable{ChannelItemInfo}}.</returns>
Task<IEnumerable<ChannelItemInfo>> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken);
}
public interface ISupportsDelete
{
bool CanDelete(BaseItem item);
Task DeleteItem(string id, CancellationToken cancellationToken);
}
public interface IDisableMediaSourceDisplay
{
}
public interface ISupportsMediaProbe
{
}
public interface IHasFolderAttributes
{
string[] Attributes { get; }
}
}

View File

@@ -0,0 +1,15 @@
#pragma warning disable CS1591
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Channels
{
public interface ISupportsDelete
{
bool CanDelete(BaseItem item);
Task DeleteItem(string id, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,21 @@
#nullable disable
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Channels
{
public interface ISupportsLatestMedia
{
/// <summary>
/// Gets the latest media.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The latest media.</returns>
Task<IEnumerable<ChannelItemInfo>> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken);
}
}

View File

@@ -0,0 +1,9 @@
namespace MediaBrowser.Controller.Channels
{
/// <summary>
/// Channel supports media probe.
/// </summary>
public interface ISupportsMediaProbe
{
}
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1002, CA2227, CS1591
using System.Collections.Generic;
using MediaBrowser.Model.Channels;
@@ -28,7 +30,7 @@ namespace MediaBrowser.Controller.Channels
public List<ChannelMediaContentType> ContentTypes { get; set; }
/// <summary>
/// Represents the maximum number of records the channel allows retrieving at a time.
/// Gets or sets the maximum number of records the channel allows retrieving at a time.
/// </summary>
public int? MaxPageSize { get; set; }
@@ -39,7 +41,7 @@ namespace MediaBrowser.Controller.Channels
public List<ChannelItemSortField> DefaultSortFields { get; set; }
/// <summary>
/// Indicates if a sort ascending/descending toggle is supported or not.
/// Gets or sets a value indicating whether a sort ascending/descending toggle is supported or not.
/// </summary>
public bool SupportsSortOrderToggle { get; set; }

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;

View File

@@ -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);
}
}

View File

@@ -0,0 +1,24 @@
#nullable disable
#pragma warning disable CS1591
using System;
using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.Controller.Collections
{
public class CollectionCreatedEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the collection.
/// </summary>
/// <value>The collection.</value>
public BoxSet Collection { get; set; }
/// <summary>
/// Gets or sets the options.
/// </summary>
/// <value>The options.</value>
public CollectionCreationOptions Options { get; set; }
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -23,8 +25,8 @@ namespace MediaBrowser.Controller.Collections
public Dictionary<string, string> ProviderIds { get; set; }
public string[] ItemIdList { get; set; }
public IReadOnlyList<string> ItemIdList { get; set; }
public Guid[] UserIds { get; set; }
public IReadOnlyList<Guid> UserIds { get; set; }
}
}

View File

@@ -7,23 +7,14 @@ using MediaBrowser.Controller.Entities.Movies;
namespace MediaBrowser.Controller.Collections
{
public class CollectionCreatedEventArgs : EventArgs
{
/// <summary>
/// Gets or sets the collection.
/// </summary>
/// <value>The collection.</value>
public BoxSet Collection { get; set; }
/// <summary>
/// Gets or sets the options.
/// </summary>
/// <value>The options.</value>
public CollectionCreationOptions Options { get; set; }
}
public class CollectionModifiedEventArgs : EventArgs
{
public CollectionModifiedEventArgs(BoxSet collection, IReadOnlyCollection<BaseItem> itemsChanged)
{
Collection = collection;
ItemsChanged = itemsChanged;
}
/// <summary>
/// Gets or sets the collection.
/// </summary>
@@ -34,6 +25,6 @@ namespace MediaBrowser.Controller.Collections
/// Gets or sets the items changed.
/// </summary>
/// <value>The items changed.</value>
public List<BaseItem> ItemsChanged { get; set; }
public IReadOnlyCollection<BaseItem> ItemsChanged { get; set; }
}
}

View File

@@ -14,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>

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -18,7 +20,6 @@ namespace MediaBrowser.Controller.Devices
/// </summary>
/// <param name="reportedId">The reported identifier.</param>
/// <param name="capabilities">The capabilities.</param>
/// <returns>Task.</returns>
void SaveCapabilities(string reportedId, ClientCapabilities capabilities);
/// <summary>
@@ -45,6 +46,9 @@ namespace MediaBrowser.Controller.Devices
/// <summary>
/// Determines whether this instance [can access device] the specified user identifier.
/// </summary>
/// <param name="user">The user to test.</param>
/// <param name="deviceId">The device id to test.</param>
/// <returns>Whether the user can access the device.</returns>
bool CanAccessDevice(User user, string deviceId);
void UpdateDeviceOptions(string deviceId, DeviceOptions options);

View File

@@ -20,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.
@@ -51,14 +51,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.

View File

@@ -1,5 +1,4 @@
#pragma warning disable CS1591
#nullable enable
using System;
using System.Collections.Generic;
@@ -58,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>

View File

@@ -1,5 +1,4 @@
#pragma warning disable CS1591
#nullable enable
using System;
using System.Collections.Generic;
@@ -61,7 +60,7 @@ namespace MediaBrowser.Controller.Drawing
string GetImageCacheTag(BaseItem item, ChapterInfo info);
string GetImageCacheTag(User user);
string? GetImageCacheTag(User user);
/// <summary>
/// Processes the image.

View File

@@ -1,3 +1,7 @@
#nullable disable
using System.Collections.Generic;
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Drawing
@@ -8,7 +12,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets or sets the input paths.
/// </summary>
/// <value>The input paths.</value>
public string[] InputPaths { get; set; }
public IReadOnlyList<string> InputPaths { get; set; }
/// <summary>
/// Gets or sets the output path.

View File

@@ -1,75 +1,17 @@
#pragma warning disable CS1591
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Drawing
{
public static class ImageHelper
{
public static ImageDimensions GetNewImageSize(ImageProcessingOptions options, ImageDimensions? originalImageSize)
public static ImageDimensions GetNewImageSize(ImageProcessingOptions options, ImageDimensions originalImageSize)
{
if (originalImageSize.HasValue)
{
// Determine the output size based on incoming parameters
var newSize = DrawingUtils.Resize(originalImageSize.Value, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
return newSize;
}
return GetSizeEstimate(options);
}
private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options)
{
if (options.Width.HasValue && options.Height.HasValue)
{
return new ImageDimensions(options.Width.Value, options.Height.Value);
}
double aspect = GetEstimatedAspectRatio(options.Image.Type, options.Item);
int? width = options.Width ?? options.MaxWidth;
if (width.HasValue)
{
int heightValue = Convert.ToInt32((double)width.Value / aspect);
return new ImageDimensions(width.Value, heightValue);
}
var height = options.Height ?? options.MaxHeight ?? 200;
int widthValue = Convert.ToInt32(aspect * height);
return new ImageDimensions(widthValue, height);
}
private static double GetEstimatedAspectRatio(ImageType type, BaseItem item)
{
switch (type)
{
case ImageType.Art:
case ImageType.Backdrop:
case ImageType.Chapter:
case ImageType.Screenshot:
case ImageType.Thumb:
return 1.78;
case ImageType.Banner:
return 5.4;
case ImageType.Box:
case ImageType.BoxRear:
case ImageType.Disc:
case ImageType.Menu:
case ImageType.Profile:
return 1;
case ImageType.Logo:
return 2.58;
case ImageType.Primary:
double defaultPrimaryImageAspectRatio = item.GetDefaultPrimaryImageAspectRatio();
return defaultPrimaryImageAspectRatio > 0 ? defaultPrimaryImageAspectRatio : 2.0 / 3;
default:
return 1;
}
// Determine the output size based on incoming parameters
var newSize = DrawingUtils.Resize(originalImageSize, options.Width ?? 0, options.Height ?? 0, options.MaxWidth ?? 0, options.MaxHeight ?? 0);
newSize = DrawingUtils.ResizeFill(newSize, options.FillWidth, options.FillHeight);
return newSize;
}
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -24,8 +26,6 @@ namespace MediaBrowser.Controller.Drawing
public int ImageIndex { get; set; }
public bool CropWhiteSpace { get; set; }
public int? Width { get; set; }
public int? Height { get; set; }
@@ -34,6 +34,10 @@ namespace MediaBrowser.Controller.Drawing
public int? MaxHeight { get; set; }
public int? FillWidth { get; set; }
public int? FillHeight { get; set; }
public int Quality { get; set; }
public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; }
@@ -95,6 +99,11 @@ namespace MediaBrowser.Controller.Drawing
return false;
}
if (sizeValue.Width > FillWidth || sizeValue.Height > FillHeight)
{
return false;
}
return true;
}
@@ -106,7 +115,6 @@ namespace MediaBrowser.Controller.Drawing
PercentPlayed.Equals(0) &&
!UnplayedCount.HasValue &&
!Blur.HasValue &&
!CropWhiteSpace &&
string.IsNullOrEmpty(BackgroundColor) &&
string.IsNullOrEmpty(ForegroundLayer);
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;

View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CA1711, CS1591
using System;
using System.IO;
@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.Drawing
/// Gets or sets the stream.
/// </summary>
/// <value>The stream.</value>
public Stream Stream { get; set; }
public Stream? Stream { get; set; }
/// <summary>
/// Gets or sets the format.
@@ -22,9 +22,15 @@ namespace MediaBrowser.Controller.Drawing
public void Dispose()
{
if (Stream != null)
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Stream.Dispose();
Stream?.Dispose();
}
}
}

View File

@@ -1,6 +1,9 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
@@ -15,37 +18,17 @@ namespace MediaBrowser.Controller.Dto
ItemFields.RefreshState
};
public ItemFields[] Fields { get; set; }
private static readonly ImageType[] AllImageTypes = Enum.GetValues<ImageType>();
public ImageType[] ImageTypes { get; set; }
public int ImageTypeLimit { get; set; }
public bool EnableImages { get; set; }
public bool AddProgramRecordingInfo { get; set; }
public bool EnableUserData { get; set; }
public bool AddCurrentProgram { get; set; }
private static readonly ItemFields[] AllItemFields = Enum.GetValues<ItemFields>()
.Except(DefaultExcludedFields)
.ToArray();
public DtoOptions()
: this(true)
{
}
private static readonly ImageType[] AllImageTypes = Enum.GetNames(typeof(ImageType))
.Select(i => (ImageType)Enum.Parse(typeof(ImageType), i, true))
.ToArray();
private static readonly ItemFields[] AllItemFields = Enum.GetNames(typeof(ItemFields))
.Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true))
.Except(DefaultExcludedFields)
.ToArray();
public bool ContainsField(ItemFields field)
=> Fields.Contains(field);
public DtoOptions(bool allFields)
{
ImageTypeLimit = int.MaxValue;
@@ -57,6 +40,23 @@ namespace MediaBrowser.Controller.Dto
ImageTypes = AllImageTypes;
}
public IReadOnlyList<ItemFields> Fields { get; set; }
public IReadOnlyList<ImageType> ImageTypes { get; set; }
public int ImageTypeLimit { get; set; }
public bool EnableImages { get; set; }
public bool AddProgramRecordingInfo { get; set; }
public bool EnableUserData { get; set; }
public bool AddCurrentProgram { get; set; }
public bool ContainsField(ItemFields field)
=> Fields.Contains(field);
public int GetImageLimit(ImageType type)
{
if (EnableImages && ImageTypes.Contains(type))

View File

@@ -1,3 +1,6 @@
#nullable disable
#pragma warning disable CA1002
using System.Collections.Generic;
using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
@@ -34,11 +37,17 @@ namespace MediaBrowser.Controller.Dto
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
/// <param name="owner">The owner.</param>
/// <returns>The <see cref="IReadOnlyList{T}"/> of <see cref="BaseItemDto"/>.</returns>
IReadOnlyList<BaseItemDto> GetBaseItemDtos(IReadOnlyList<BaseItem> items, DtoOptions options, User user = null, BaseItem owner = null);
/// <summary>
/// Gets the item by name dto.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="options">The dto options.</param>
/// <param name="taggedItems">The list of tagged items.</param>
/// <param name="user">The user.</param>
/// <returns>The item dto.</returns>
BaseItemDto GetItemByNameDto(BaseItem item, DtoOptions options, List<BaseItem> taggedItems, User user = null);
}
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1819, CS1591
using System;
using System.Collections.Concurrent;
@@ -16,30 +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
{
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.
@@ -47,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)
@@ -83,7 +86,6 @@ namespace MediaBrowser.Controller.Entities
}
}
private bool _requiresRefresh;
public override bool RequiresRefresh()
{
var changed = base.RequiresRefresh() || _requiresRefresh;
@@ -103,11 +105,11 @@ namespace MediaBrowser.Controller.Entities
return changed;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
ClearCache();
var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh;
var changed = base.BeforeMetadataRefresh(replaceAllMetadata) || _requiresRefresh;
_requiresRefresh = false;
return changed;
}
@@ -120,8 +122,7 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
FileInfo = FileSystem.GetDirectoryInfo(path),
Path = path
FileInfo = FileSystem.GetDirectoryInfo(path)
};
// Gather child folder and files
@@ -153,11 +154,11 @@ namespace MediaBrowser.Controller.Entities
return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren);
}
protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
ClearCache();
await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService)
await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken)
.ConfigureAwait(false);
ClearCache();
@@ -167,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)
@@ -183,7 +184,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="id">The id.</param>
/// <returns>BaseItem.</returns>
/// <exception cref="ArgumentNullException">id</exception>
/// <exception cref="ArgumentNullException">The id is empty.</exception>
public BaseItem FindVirtualChild(Guid id)
{
if (id.Equals(Guid.Empty))

View File

@@ -1,7 +1,10 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1002, CA1724, CA1826, CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
@@ -22,6 +25,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; }
@@ -30,17 +39,6 @@ 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;
@@ -59,11 +57,6 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override Folder LatestItemsIndexContainer => AlbumEntity;
public override bool CanDownload()
{
return IsFileProtocol;
}
[JsonIgnore]
public MusicAlbum AlbumEntity => FindParent<MusicAlbum>();
@@ -74,25 +67,35 @@ 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>
/// <returns>System.String.</returns>
protected override string CreateSortName()
{
return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ") : "")
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty)
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty) + Name;
}
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000") : string.Empty;
var songKey = IndexNumber.HasValue ? IndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) : string.Empty;
if (ParentIndexNumber.HasValue)
{
songKey = ParentIndexNumber.Value.ToString("0000") + "-" + songKey;
songKey = ParentIndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) + "-" + songKey;
}
songKey += Name;

View File

@@ -1,6 +1,10 @@
#nullable disable
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Linq;
using MediaBrowser.Controller.Library;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -23,15 +27,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public static IEnumerable<string> GetAllArtists<T>(this T item)
where T : IHasArtist, IHasAlbumArtist
{
foreach (var i in item.AlbumArtists)
{
yield return i;
}
foreach (var i in item.Artists)
{
yield return i;
}
return item.AlbumArtists.Concat(item.Artists).DistinctNames();
}
}
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1819, CS1591
namespace MediaBrowser.Controller.Entities.Audio
{

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1721, CA1826, CS1591
using System;
using System.Collections.Generic;
@@ -21,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;
@@ -42,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();
@@ -62,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;
@@ -120,7 +122,7 @@ namespace MediaBrowser.Controller.Entities.Audio
protected override bool GetBlockUnratedValue(User user)
{
return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Music.ToString());
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Music);
}
public override UnratedItem GetBlockUnratedType()

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -6,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;
@@ -42,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;
@@ -56,27 +88,13 @@ namespace MediaBrowser.Controller.Entities.Audio
{
if (query.IncludeItemTypes.Length == 0)
{
query.IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name };
query.IncludeItemTypes = new[] { nameof(Audio), nameof(MusicVideo), nameof(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);
@@ -92,7 +110,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.IsSaveLocalMetadataEnabled();
}
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
if (IsAccessedByName)
{
@@ -100,7 +118,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return Task.CompletedTask;
}
return base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService);
return base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken);
}
public override List<string> GetUserDataKeys()
@@ -111,14 +129,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return list;
}
/// <summary>
/// Returns 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>
@@ -145,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
protected override bool GetBlockUnratedValue(User user)
{
return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Music.ToString());
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Music);
}
public override UnratedItem GetBlockUnratedType()
@@ -165,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
@@ -206,9 +208,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <param name="replaceAllMetadata">Option to replace metadata.</param>
/// <returns>True if metadata changed.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (IsAccessedByName)
{

View File

@@ -1,9 +1,11 @@
#nullable disable
#pragma warning disable CS1591
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.Audio
@@ -13,6 +15,26 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicGenre : BaseItem, IItemByName
{
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
[JsonIgnore]
public override bool IsDisplayedAsFolder => true;
/// <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 bool SupportsPeople => false;
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
@@ -26,23 +48,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return GetUserDataKeys()[0];
}
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
[JsonIgnore]
public override bool IsDisplayedAsFolder => true;
/// <summary>
/// Returns 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 double GetDefaultPrimaryImageAspectRatio()
{
return 1;
@@ -58,13 +63,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[] { typeof(MusicVideo).Name, typeof(Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
query.IncludeItemTypes = new[] { nameof(MusicVideo), nameof(Audio), nameof(MusicAlbum), nameof(MusicArtist) };
return LibraryManager.GetItemList(query);
}
@@ -104,9 +106,11 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <param name="replaceAllMetadata">Option to replace metadata.</param>
/// <returns>True if metadata changed.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
var newPath = GetRebasedPath();
if (!string.Equals(Path, newPath, StringComparison.Ordinal))

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1724, CS1591
using System;
using System.Text.Json.Serialization;

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
@@ -63,10 +64,22 @@ 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
where T : BaseItem
where TU : BaseItem
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
if (dest == null)
{
throw new ArgumentNullException(nameof(dest));
}
var destProps = typeof(TU).GetProperties().Where(x => x.CanWrite).ToList();
foreach (var sourceProp in typeof(T).GetProperties())
@@ -98,9 +111,12 @@ 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()
where T : BaseItem
where TU : BaseItem, new()
{
var dest = new TU();
source.DeepCopy(dest);

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System.Text.Json.Serialization;
@@ -13,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;
@@ -22,11 +30,5 @@ namespace MediaBrowser.Controller.Entities
{
return true;
}
[JsonIgnore]
public override bool SupportsInheritedParentImages => false;
[JsonIgnore]
public override bool SupportsPeople => false;
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -10,6 +12,11 @@ namespace MediaBrowser.Controller.Entities
{
public class Book : BaseItem, IHasLookupInfo<BookInfo>, IHasSeries
{
public Book()
{
this.RunTimeTicks = TimeSpan.TicksPerSecond;
}
[JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Book;
@@ -26,11 +33,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public Guid SeriesId { get; set; }
public Book()
{
this.RunTimeTicks = TimeSpan.TicksPerSecond;
}
public string FindSeriesSortName()
{
return SeriesName;

View File

@@ -1,12 +1,16 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -24,32 +28,66 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class CollectionFolder : Folder, ICollectionFolder
{
public static IXmlSerializer XmlSerializer { get; set; }
public static IJsonSerializer JsonSerializer { get; set; }
public static IServerApplicationHost ApplicationHost { get; set; }
private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private static readonly Dictionary<string, LibraryOptions> _libraryOptions = new Dictionary<string, LibraryOptions>();
private bool _requiresRefresh;
/// <summary>
/// Initializes a new instance of the <see cref="CollectionFolder"/> class.
/// </summary>
public CollectionFolder()
{
PhysicalLocationsList = Array.Empty<string>();
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; }
[JsonIgnore]
public override bool SupportsPlayedStatus => false;
[JsonIgnore]
public override bool SupportsInheritedParentImages => false;
public string CollectionType { get; set; }
/// <summary>
/// Gets the item's children.
/// </summary>
/// <remarks>
/// Our children are actually just references to the ones in the physical root...
/// </remarks>
/// <value>The actual children.</value>
[JsonIgnore]
public override IEnumerable<BaseItem> Children => GetActualChildren();
[JsonIgnore]
public override bool SupportsPeople => false;
public override bool CanDelete()
{
return false;
}
public string CollectionType { get; set; }
private static readonly Dictionary<string, LibraryOptions> LibraryOptions = new Dictionary<string, LibraryOptions>();
public LibraryOptions GetLibraryOptions()
{
return GetLibraryOptions(Path);
@@ -60,7 +98,6 @@ namespace MediaBrowser.Controller.Entities
try
{
var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
if (result == null)
{
return new LibraryOptions();
@@ -104,12 +141,12 @@ namespace MediaBrowser.Controller.Entities
public static LibraryOptions GetLibraryOptions(string path)
{
lock (LibraryOptions)
lock (_libraryOptions)
{
if (!LibraryOptions.TryGetValue(path, out var options))
if (!_libraryOptions.TryGetValue(path, out var options))
{
options = LoadLibraryOptions(path);
LibraryOptions[path] = options;
_libraryOptions[path] = options;
}
return options;
@@ -118,11 +155,11 @@ namespace MediaBrowser.Controller.Entities
public static void SaveLibraryOptions(string path, LibraryOptions options)
{
lock (LibraryOptions)
lock (_libraryOptions)
{
LibraryOptions[path] = options;
_libraryOptions[path] = options;
var clone = JsonSerializer.DeserializeFromString<LibraryOptions>(JsonSerializer.SerializeToString(options));
var clone = JsonSerializer.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
foreach (var mediaPath in clone.PathInfos)
{
if (!string.IsNullOrEmpty(mediaPath.Path))
@@ -137,37 +174,22 @@ namespace MediaBrowser.Controller.Entities
public static void OnCollectionFolderChange()
{
lock (LibraryOptions)
lock (_libraryOptions)
{
LibraryOptions.Clear();
_libraryOptions.Clear();
}
}
/// <summary>
/// Allow different display preferences for each collection folder.
/// </summary>
/// <value>The display prefs id.</value>
[JsonIgnore]
public override Guid DisplayPreferencesId => Id;
[JsonIgnore]
public override string[] PhysicalLocations => PhysicalLocationsList;
public override bool IsSaveLocalMetadataEnabled()
{
return true;
}
public string[] PhysicalLocationsList { get; set; }
public Guid[] PhysicalFolderIds { get; set; }
protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
private bool _requiresRefresh;
public override bool RequiresRefresh()
{
var changed = base.RequiresRefresh() || _requiresRefresh;
@@ -199,9 +221,9 @@ namespace MediaBrowser.Controller.Entities
return changed;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var changed = base.BeforeMetadataRefresh(replaceAllMetdata) || _requiresRefresh;
var changed = base.BeforeMetadataRefresh(replaceAllMetadata) || _requiresRefresh;
_requiresRefresh = false;
return changed;
}
@@ -270,7 +292,6 @@ namespace MediaBrowser.Controller.Entities
var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, directoryService)
{
FileInfo = FileSystem.GetDirectoryInfo(path),
Path = path,
Parent = GetParent() as Folder,
CollectionType = CollectionType
};
@@ -297,27 +318,20 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
/// ***Currently does not contain logic to maintain items that are unavailable in the file system***
/// ***Currently does not contain logic to maintain items that are unavailable in the file system***.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
/// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
/// <param name="refreshOptions">The refresh options.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
protected override Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
/// <summary>
/// Our children are actually just references to the ones in the physical root...
/// </summary>
/// <value>The actual children.</value>
[JsonIgnore]
public override IEnumerable<BaseItem> Children => GetActualChildren();
public IEnumerable<BaseItem> GetActualChildren()
{
return GetPhysicalFolders(true).SelectMany(c => c.Children);
@@ -354,9 +368,7 @@ namespace MediaBrowser.Controller.Entities
if (result.Count == 0)
{
var folder = LibraryManager.FindByPath(path, true) as Folder;
if (folder != null)
if (LibraryManager.FindByPath(path, true) is Folder folder)
{
result.Add(folder);
}
@@ -364,8 +376,5 @@ namespace MediaBrowser.Controller.Entities
return result;
}
[JsonIgnore]
public override bool SupportsPeople => false;
}
}

View File

@@ -1,6 +1,8 @@
#nullable disable
using System;
using System.Linq;
using MediaBrowser.Common.Extensions;
using Jellyfin.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@@ -13,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))

View File

@@ -1,13 +1,15 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1002, CA1721, CA1819, CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Progress;
@@ -35,6 +37,11 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Folder : BaseItem
{
public Folder()
{
LinkedChildren = Array.Empty<LinkedChild>();
}
public static IUserViewManager UserViewManager { get; set; }
/// <summary>
@@ -48,11 +55,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public DateTime? DateLastMediaAdded { get; set; }
public Folder()
{
LinkedChildren = Array.Empty<LinkedChild>();
}
[JsonIgnore]
public override bool SupportsThemeMedia => true;
@@ -84,6 +86,87 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public virtual bool SupportsDateLastMediaAdded => false;
[JsonIgnore]
public override string FileNameWithoutExtension
{
get
{
if (IsFileProtocol)
{
return System.IO.Path.GetFileName(Path);
}
return null;
}
}
/// <summary>
/// Gets the actual children.
/// </summary>
/// <value>The actual children.</value>
[JsonIgnore]
public virtual IEnumerable<BaseItem> Children => LoadChildren();
/// <summary>
/// Gets thread-safe access to all recursive children of this folder - without regard to user.
/// </summary>
/// <value>The recursive children.</value>
[JsonIgnore]
public IEnumerable<BaseItem> RecursiveChildren => GetRecursiveChildren();
[JsonIgnore]
protected virtual bool SupportsShortcutChildren => false;
protected virtual bool FilterLinkedChildrenPerUser => false;
[JsonIgnore]
protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren;
[JsonIgnore]
public virtual bool SupportsUserDataFromChildren
{
get
{
// These are just far too slow.
if (this is ICollectionFolder)
{
return false;
}
if (this is UserView)
{
return false;
}
if (this is UserRootFolder)
{
return false;
}
if (this is Channel)
{
return false;
}
if (SourceType != SourceType.Library)
{
return false;
}
if (this is IItemByName)
{
if (this is not IHasDualAccess hasDualAccess || hasDualAccess.IsAccessedByName)
{
return false;
}
}
return true;
}
}
public static ICollectionManager CollectionManager { get; set; }
public override bool CanDelete()
{
if (IsRoot)
@@ -106,20 +189,6 @@ namespace MediaBrowser.Controller.Entities
return baseResult;
}
[JsonIgnore]
public override string FileNameWithoutExtension
{
get
{
if (IsFileProtocol)
{
return System.IO.Path.GetFileName(Path);
}
return null;
}
}
protected override bool IsAllowTagFilterEnforced()
{
if (this is ICollectionFolder)
@@ -135,17 +204,12 @@ namespace MediaBrowser.Controller.Entities
return true;
}
[JsonIgnore]
protected virtual bool SupportsShortcutChildren => false;
/// <summary>
/// Adds the child.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="InvalidOperationException">Unable to add + item.Name</exception>
public void AddChild(BaseItem item, CancellationToken cancellationToken)
/// <exception cref="InvalidOperationException">Unable to add + item.Name.</exception>
public void AddChild(BaseItem item)
{
item.SetParent(this);
@@ -167,31 +231,14 @@ namespace MediaBrowser.Controller.Entities
LibraryManager.CreateItem(item, this);
}
/// <summary>
/// Gets the actual children.
/// </summary>
/// <value>The actual children.</value>
[JsonIgnore]
public virtual IEnumerable<BaseItem> Children => LoadChildren();
/// <summary>
/// thread-safe access to all recursive children of this folder - without regard to user.
/// </summary>
/// <value>The recursive children.</value>
[JsonIgnore]
public IEnumerable<BaseItem> RecursiveChildren => GetRecursiveChildren();
public override bool IsVisible(User user)
{
if (this is ICollectionFolder && !(this is BasePluginFolder))
{
var blockedMediaFolders = user.GetPreference(PreferenceKind.BlockedMediaFolders);
var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders);
if (blockedMediaFolders.Length > 0)
{
if (blockedMediaFolders.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase) ||
// Backwards compatibility
blockedMediaFolders.Contains(Name, StringComparer.OrdinalIgnoreCase))
if (blockedMediaFolders.Contains(Id))
{
return false;
}
@@ -199,8 +246,7 @@ namespace MediaBrowser.Controller.Entities
else
{
if (!user.HasPermission(PermissionKind.EnableAllFolders)
&& !user.GetPreference(PreferenceKind.EnabledFolders)
.Contains(Id.ToString("N", CultureInfo.InvariantCulture), StringComparer.OrdinalIgnoreCase))
&& !user.GetPreferenceValues<Guid>(PreferenceKind.EnabledFolders).Contains(Id))
{
return false;
}
@@ -212,8 +258,9 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Loads our children. Validation will occur externally.
/// We want this sychronous.
/// 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);
@@ -228,20 +275,20 @@ namespace MediaBrowser.Controller.Entities
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
{
return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(FileSystem)));
return ValidateChildren(progress, new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken: cancellationToken);
}
/// <summary>
/// Validates that the children of the folder still exist.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="metadataRefreshOptions">The metadata refresh options.</param>
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true)
public Task ValidateChildren(IProgress<double> progress, MetadataRefreshOptions metadataRefreshOptions, bool recursive = true, CancellationToken cancellationToken = default)
{
return ValidateChildrenInternal(progress, cancellationToken, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService);
return ValidateChildrenInternal(progress, recursive, true, metadataRefreshOptions, metadataRefreshOptions.DirectoryService, cancellationToken);
}
private Dictionary<Guid, BaseItem> GetActualChildrenDictionary()
@@ -281,13 +328,13 @@ namespace MediaBrowser.Controller.Entities
/// Validates the children internal.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="recursive">if set to <c>true</c> [recursive].</param>
/// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
/// <param name="refreshOptions">The refresh options.</param>
/// <param name="directoryService">The directory service.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
if (recursive)
{
@@ -296,7 +343,7 @@ namespace MediaBrowser.Controller.Entities
try
{
await ValidateChildrenInternal2(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false);
await ValidateChildrenInternal2(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken).ConfigureAwait(false);
}
finally
{
@@ -307,7 +354,7 @@ namespace MediaBrowser.Controller.Entities
}
}
private async Task ValidateChildrenInternal2(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
private async Task ValidateChildrenInternal2(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
@@ -328,11 +375,11 @@ namespace MediaBrowser.Controller.Entities
return;
}
progress.Report(5);
progress.Report(ProgressHelpers.RetrievedChildren);
if (recursive)
{
ProviderManager.OnRefreshProgress(this, 5);
ProviderManager.OnRefreshProgress(this, ProgressHelpers.RetrievedChildren);
}
// Build a dictionary of the current children we have now by Id so we can compare quickly and easily
@@ -393,11 +440,11 @@ namespace MediaBrowser.Controller.Entities
validChildrenNeedGeneration = true;
}
progress.Report(10);
progress.Report(ProgressHelpers.UpdatedChildItems);
if (recursive)
{
ProviderManager.OnRefreshProgress(this, 10);
ProviderManager.OnRefreshProgress(this, ProgressHelpers.UpdatedChildItems);
}
cancellationToken.ThrowIfCancellationRequested();
@@ -407,11 +454,13 @@ namespace MediaBrowser.Controller.Entities
var innerProgress = new ActionableProgress<double>();
var folder = this;
innerProgress.RegisterAction(p =>
innerProgress.RegisterAction(innerPercent =>
{
double newPct = 0.80 * p + 10;
progress.Report(newPct);
ProviderManager.OnRefreshProgress(folder, newPct);
var percent = ProgressHelpers.GetProgress(ProgressHelpers.UpdatedChildItems, ProgressHelpers.ScannedSubfolders, innerPercent);
progress.Report(percent);
ProviderManager.OnRefreshProgress(folder, percent);
});
if (validChildrenNeedGeneration)
@@ -425,11 +474,11 @@ namespace MediaBrowser.Controller.Entities
if (refreshChildMetadata)
{
progress.Report(90);
progress.Report(ProgressHelpers.ScannedSubfolders);
if (recursive)
{
ProviderManager.OnRefreshProgress(this, 90);
ProviderManager.OnRefreshProgress(this, ProgressHelpers.ScannedSubfolders);
}
var container = this as IMetadataContainer;
@@ -437,13 +486,15 @@ namespace MediaBrowser.Controller.Entities
var innerProgress = new ActionableProgress<double>();
var folder = this;
innerProgress.RegisterAction(p =>
innerProgress.RegisterAction(innerPercent =>
{
double newPct = 0.10 * p + 90;
progress.Report(newPct);
var percent = ProgressHelpers.GetProgress(ProgressHelpers.ScannedSubfolders, ProgressHelpers.RefreshedMetadata, innerPercent);
progress.Report(percent);
if (recursive)
{
ProviderManager.OnRefreshProgress(folder, newPct);
ProviderManager.OnRefreshProgress(folder, percent);
}
});
@@ -458,55 +509,35 @@ namespace MediaBrowser.Controller.Entities
validChildren = Children.ToList();
}
await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken);
await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken).ConfigureAwait(false);
}
}
}
private async Task RefreshMetadataRecursive(List<BaseItem> children, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
private Task RefreshMetadataRecursive(IList<BaseItem> children, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
{
var numComplete = 0;
var count = children.Count;
double currentPercent = 0;
foreach (var child in children)
{
cancellationToken.ThrowIfCancellationRequested();
var innerProgress = new ActionableProgress<double>();
// Avoid implicitly captured closure
var currentInnerPercent = currentPercent;
innerProgress.RegisterAction(p =>
{
double innerPercent = currentInnerPercent;
innerPercent += p / count;
progress.Report(innerPercent);
});
await RefreshChildMetadata(child, refreshOptions, recursive && child.IsFolder, innerProgress, cancellationToken)
.ConfigureAwait(false);
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
currentPercent = percent;
progress.Report(percent);
}
return RunTasks(
(baseItem, innerProgress) => RefreshChildMetadata(baseItem, refreshOptions, recursive && baseItem.IsFolder, innerProgress, cancellationToken),
children,
progress,
cancellationToken);
}
private async Task RefreshAllMetadataForContainer(IMetadataContainer container, MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
{
var series = container as Series;
if (series != null)
{
await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
}
// limit the amount of concurrent metadata refreshes
await ProviderManager.RunMetadataRefresh(
async () =>
{
var series = container as Series;
if (series != null)
{
await series.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
}
await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
await container.RefreshAllMetadata(refreshOptions, progress, cancellationToken).ConfigureAwait(false);
},
cancellationToken).ConfigureAwait(false);
}
private async Task RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
@@ -521,12 +552,15 @@ namespace MediaBrowser.Controller.Entities
{
if (refreshOptions.RefreshItem(child))
{
await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false);
// limit the amount of concurrent metadata refreshes
await ProviderManager.RunMetadataRefresh(
async () => await child.RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false),
cancellationToken).ConfigureAwait(false);
}
if (recursive && child is Folder folder)
{
await folder.RefreshMetadataRecursive(folder.Children.ToList(), refreshOptions, true, progress, cancellationToken);
await folder.RefreshMetadataRecursive(folder.Children.ToList(), refreshOptions, true, progress, cancellationToken).ConfigureAwait(false);
}
}
}
@@ -539,45 +573,80 @@ namespace MediaBrowser.Controller.Entities
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
private async Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken)
private Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken)
{
var numComplete = 0;
var count = children.Count;
double currentPercent = 0;
return RunTasks(
(folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, null, directoryService, cancellationToken),
children,
progress,
cancellationToken);
}
foreach (var child in children)
/// <summary>
/// Runs an action block on a list of children.
/// </summary>
/// <param name="task">The task to run for each child.</param>
/// <param name="children">The list of children.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
private async Task RunTasks<T>(Func<T, IProgress<double>, Task> task, IList<T> children, IProgress<double> progress, CancellationToken cancellationToken)
{
var childrenCount = children.Count;
var childrenProgress = new double[childrenCount];
void UpdateProgress()
{
cancellationToken.ThrowIfCancellationRequested();
progress.Report(childrenProgress.Average());
}
var innerProgress = new ActionableProgress<double>();
var fanoutConcurrency = ConfigurationManager.Configuration.LibraryScanFanoutConcurrency;
var parallelism = fanoutConcurrency == 0 ? Environment.ProcessorCount : fanoutConcurrency;
// Avoid implicitly captured closure
var currentInnerPercent = currentPercent;
innerProgress.RegisterAction(p =>
var actionBlock = new ActionBlock<int>(
async i =>
{
double innerPercent = currentInnerPercent;
innerPercent += p / count;
progress.Report(innerPercent);
var innerProgress = new ActionableProgress<double>();
innerProgress.RegisterAction(innerPercent =>
{
// round the percent and only update progress if it changed to prevent excessive UpdateProgress calls
var innerPercentRounded = Math.Round(innerPercent);
if (childrenProgress[i] != innerPercentRounded)
{
childrenProgress[i] = innerPercentRounded;
UpdateProgress();
}
});
await task(children[i], innerProgress).ConfigureAwait(false);
childrenProgress[i] = 100;
UpdateProgress();
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = parallelism,
CancellationToken = cancellationToken,
});
await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService)
.ConfigureAwait(false);
numComplete++;
double percent = numComplete;
percent /= count;
percent *= 100;
currentPercent = percent;
progress.Report(percent);
for (var i = 0; i < childrenCount; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion.ConfigureAwait(false);
}
/// <summary>
/// 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);
@@ -723,7 +792,7 @@ namespace MediaBrowser.Controller.Entities
private bool RequiresPostFiltering2(InternalItemsQuery query)
{
if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], typeof(BoxSet).Name, StringComparison.OrdinalIgnoreCase))
if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase))
{
Logger.LogDebug("Query requires post-filtering due to BoxSet query");
return true;
@@ -813,7 +882,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsPlayed.HasValue)
{
if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(typeof(Series).Name))
if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(nameof(Series)))
{
Logger.LogDebug("Query requires post-filtering due to IsPlayed");
return true;
@@ -922,14 +991,18 @@ namespace MediaBrowser.Controller.Entities
}
else
{
items = GetChildren(user, true).Where(filter);
// need to pass this param to the children.
var childQuery = new InternalItemsQuery
{
DisplayAlbumFolders = query.DisplayAlbumFolders
};
items = GetChildren(user, true, childQuery).Where(filter);
}
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;
@@ -947,7 +1020,7 @@ namespace MediaBrowser.Controller.Entities
if (!string.IsNullOrEmpty(query.NameStartsWith))
{
items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.OrdinalIgnoreCase));
items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase));
}
if (!string.IsNullOrEmpty(query.NameLessThan))
@@ -1067,12 +1140,12 @@ namespace MediaBrowser.Controller.Entities
return false;
}
if (request.Genres.Length > 0)
if (request.Genres.Count > 0)
{
return false;
}
if (request.GenreIds.Length > 0)
if (request.GenreIds.Count > 0)
{
return false;
}
@@ -1177,7 +1250,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
if (request.GenreIds.Length > 0)
if (request.GenreIds.Count > 0)
{
return false;
}
@@ -1258,10 +1331,23 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the children to list.
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private void AddChildren(User user, bool includeLinkedChildren, Dictionary<Guid, BaseItem> result, bool recursive, InternalItemsQuery query)
{
foreach (var child in GetEligibleChildrenForRecursiveChildren(user))
// If Query.AlbumFolders is set, then enforce the format as per the db in that it permits sub-folders in music albums.
IEnumerable<BaseItem> children = null;
if ((query?.DisplayAlbumFolders ?? false) && (this is MusicAlbum))
{
children = Children;
query = null;
}
// If there are not sub-folders, proceed as normal.
if (children == null)
{
children = GetEligibleChildrenForRecursiveChildren(user);
}
foreach (var child in children)
{
bool? isVisibleToUser = null;
@@ -1301,18 +1387,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)
@@ -1410,16 +1484,19 @@ namespace MediaBrowser.Controller.Entities
return list;
}
protected virtual bool FilterLinkedChildrenPerUser => false;
public bool ContainsLinkedChildByItemId(Guid itemId)
{
var linkedChildren = LinkedChildren;
foreach (var i in linkedChildren)
{
if (i.ItemId.HasValue && i.ItemId.Value == itemId)
if (i.ItemId.HasValue)
{
return true;
if (i.ItemId.Value == itemId)
{
return true;
}
continue;
}
var child = GetLinkedChild(i);
@@ -1507,9 +1584,6 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.Item2 != null);
}
[JsonIgnore]
protected override bool SupportsOwnedItems => base.SupportsOwnedItems || SupportsShortcutChildren;
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var changesFound = false;
@@ -1530,7 +1604,8 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Refreshes the linked children.
/// </summary>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
/// <param name="fileSystemChildren">The enumerable of file system metadata.</param>
/// <returns><c>true</c> if the linked children were updated, <c>false</c> otherwise.</returns>
protected virtual bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
if (SupportsShortcutChildren)
@@ -1594,7 +1669,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,
@@ -1636,7 +1710,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
@@ -1673,51 +1746,6 @@ namespace MediaBrowser.Controller.Entities
return !IsPlayed(user);
}
[JsonIgnore]
public virtual bool SupportsUserDataFromChildren
{
get
{
// These are just far too slow.
if (this is ICollectionFolder)
{
return false;
}
if (this is UserView)
{
return false;
}
if (this is UserRootFolder)
{
return false;
}
if (this is Channel)
{
return false;
}
if (SourceType != SourceType.Library)
{
return false;
}
var iItemByName = this as IItemByName;
if (iItemByName != null)
{
var hasDualAccess = this as IHasDualAccess;
if (hasDualAccess == null || hasDualAccess.IsAccessedByName)
{
return false;
}
}
return true;
}
}
public override void FillUserDataDtoValues(UserItemDataDto dto, UserItemData userData, BaseItemDto itemDto, User user, DtoOptions fields)
{
if (!SupportsUserDataFromChildren)
@@ -1747,20 +1775,15 @@ namespace MediaBrowser.Controller.Entities
{
EnableImages = false
}
});
}).TotalRecordCount;
double unplayedCount = unplayedQueryResult.TotalRecordCount;
dto.UnplayedItemCount = unplayedQueryResult;
dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount;
if (itemDto != null && itemDto.RecursiveItemCount.HasValue)
if (itemDto?.RecursiveItemCount > 0)
{
if (itemDto.RecursiveItemCount.Value > 0)
{
var unplayedPercentage = (unplayedCount / itemDto.RecursiveItemCount.Value) * 100;
dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
}
var unplayedPercentage = ((double)unplayedQueryResult / itemDto.RecursiveItemCount.Value) * 100;
dto.PlayedPercentage = 100 - unplayedPercentage;
dto.Played = dto.PlayedPercentage.Value >= 100;
}
else
{
@@ -1768,5 +1791,45 @@ namespace MediaBrowser.Controller.Entities
}
}
}
/// <summary>
/// Contains constants used when reporting scan progress.
/// </summary>
private static class ProgressHelpers
{
/// <summary>
/// Reported after the folders immediate children are retrieved.
/// </summary>
public const int RetrievedChildren = 5;
/// <summary>
/// Reported after add, updating, or deleting child items from the LibraryManager.
/// </summary>
public const int UpdatedChildItems = 10;
/// <summary>
/// Reported once subfolders are scanned.
/// When scanning subfolders, the progress will be between [UpdatedItems, ScannedSubfolders].
/// </summary>
public const int ScannedSubfolders = 50;
/// <summary>
/// Reported once metadata is refreshed.
/// When refreshing metadata, the progress will be between [ScannedSubfolders, MetadataRefreshed].
/// </summary>
public const int RefreshedMetadata = 100;
/// <summary>
/// Gets the current progress given the previous step, next step, and progress in between.
/// </summary>
/// <param name="previousProgressStep">The previous progress step.</param>
/// <param name="nextProgressStep">The next progress step.</param>
/// <param name="currentProgress">The current progress step.</param>
/// <returns>The progress.</returns>
public static double GetProgress(int previousProgressStep, int nextProgressStep, double currentProgress)
{
return previousProgressStep + ((nextProgressStep - previousProgressStep) * (currentProgress / 100));
}
}
}
}

View File

@@ -1,10 +1,12 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Diacritics.Extensions;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Extensions;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -14,6 +16,23 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Genre : BaseItem, IItemByName
{
/// <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 bool IsDisplayedAsFolder => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
[JsonIgnore]
public override bool SupportsPeople => false;
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
@@ -32,20 +51,6 @@ namespace MediaBrowser.Controller.Entities
return 1;
}
/// <summary>
/// Returns 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 bool IsDisplayedAsFolder => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
public override bool IsSaveLocalMetadataEnabled()
{
return true;
@@ -59,14 +64,17 @@ namespace MediaBrowser.Controller.Entities
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
query.GenreIds = new[] { Id };
query.ExcludeItemTypes = new[] { typeof(MusicVideo).Name, typeof(Audio.Audio).Name, typeof(MusicAlbum).Name, typeof(MusicArtist).Name };
query.ExcludeItemTypes = new[]
{
nameof(MusicVideo),
nameof(Entities.Audio.Audio),
nameof(MusicAlbum),
nameof(MusicArtist)
};
return LibraryManager.GetItemList(query);
}
[JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
{
return GetPath(name, true);
@@ -100,11 +108,13 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// This is called before any metadata refresh and returns true if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <param name="replaceAllMetadata">Whether to replace all metadata.</param>
/// <returns>true if the item has change, else false.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
var newPath = GetRebasedPath();
if (!string.Equals(Path, newPath, StringComparison.Ordinal))

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1819, CS1591
using System;

View File

@@ -1,3 +1,5 @@
#nullable disable
namespace MediaBrowser.Controller.Entities
{
/// <summary>

View File

@@ -1,3 +1,5 @@
#nullable disable
namespace MediaBrowser.Controller.Entities
{
/// <summary>

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -18,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();

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using MediaBrowser.Model.LiveTv;

View File

@@ -1,7 +1,7 @@
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Interface IHasScreenshots.
/// The item has screenshots.
/// </summary>
public interface IHasScreenshots
{

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -7,7 +9,7 @@ namespace MediaBrowser.Controller.Entities
public interface IHasSeries
{
/// <summary>
/// Gets the name of the series.
/// Gets or sets the name of the series.
/// </summary>
/// <value>The name of the series.</value>
string SeriesName { get; set; }

View File

@@ -0,0 +1,11 @@
#nullable disable
#pragma warning disable CA1819, CS1591
namespace MediaBrowser.Controller.Entities
{
public interface IHasShares
{
Share[] Shares { get; set; }
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -37,6 +39,7 @@ 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;
@@ -44,6 +47,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Gets the trailer ids.
/// </summary>
/// <param name="item">Media item.</param>
/// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
public static IReadOnlyList<Guid> GetTrailerIds(this IHasTrailers item)
{
@@ -68,6 +72,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Gets the trailers.
/// </summary>
/// <param name="item">Media item.</param>
/// <returns><see cref="IReadOnlyList{BaseItem}" />.</returns>
public static IReadOnlyList<BaseItem> GetTrailers(this IHasTrailers item)
{

View File

@@ -1,4 +1,4 @@
#pragma warning disable CS1591
#pragma warning disable CA1044, CA1819, CA2227, CS1591
using System;
using System.Collections.Generic;
@@ -12,15 +12,64 @@ 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<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)
{
SetUser(user);
}
}
public bool Recursive { get; set; }
public int? StartIndex { get; set; }
public int? Limit { get; set; }
public User User { get; set; }
public User? User { get; set; }
public BaseItem SimilarTo { get; set; }
public BaseItem? SimilarTo { get; set; }
public bool? IsFolder { get; set; }
@@ -46,7 +95,7 @@ namespace MediaBrowser.Controller.Entities
public string[] ExcludeInheritedTags { get; set; }
public string[] Genres { get; set; }
public IReadOnlyList<string> Genres { get; set; }
public bool? IsSpecialSeason { get; set; }
@@ -56,23 +105,23 @@ namespace MediaBrowser.Controller.Entities
public bool? CollapseBoxSetItems { get; set; }
public string NameStartsWithOrGreater { get; set; }
public string? NameStartsWithOrGreater { get; set; }
public string NameStartsWith { get; set; }
public string? NameStartsWith { get; set; }
public string NameLessThan { get; set; }
public string? NameLessThan { get; set; }
public string NameContains { get; set; }
public string? NameContains { get; set; }
public string MinSortName { get; set; }
public string? MinSortName { get; set; }
public string PresentationUniqueKey { get; set; }
public string? PresentationUniqueKey { get; set; }
public string Path { get; set; }
public string? Path { get; set; }
public string Name { get; set; }
public string? Name { get; set; }
public string Person { get; set; }
public string? Person { get; set; }
public Guid[] PersonIds { get; set; }
@@ -80,7 +129,7 @@ namespace MediaBrowser.Controller.Entities
public Guid[] ExcludeItemIds { get; set; }
public string AdjacentTo { get; set; }
public string? AdjacentTo { get; set; }
public string[] PersonTypes { get; set; }
@@ -116,7 +165,7 @@ namespace MediaBrowser.Controller.Entities
public Guid[] StudioIds { get; set; }
public Guid[] GenreIds { get; set; }
public IReadOnlyList<Guid> GenreIds { get; set; }
public ImageType[] ImageTypes { get; set; }
@@ -162,7 +211,7 @@ namespace MediaBrowser.Controller.Entities
public double? MinCommunityRating { get; set; }
public Guid[] ChannelIds { get; set; }
public IReadOnlyList<Guid> ChannelIds { get; set; }
public int? ParentIndexNumber { get; set; }
@@ -180,29 +229,12 @@ namespace MediaBrowser.Controller.Entities
public Guid ParentId { get; set; }
public string ParentType { get; set; }
public string? 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; }
@@ -211,9 +243,9 @@ namespace MediaBrowser.Controller.Entities
public SeriesStatus[] SeriesStatuses { get; set; }
public string ExternalSeriesId { get; set; }
public string? ExternalSeriesId { get; set; }
public string ExternalId { get; set; }
public string? ExternalId { get; set; }
public Guid[] AlbumIds { get; set; }
@@ -221,9 +253,9 @@ namespace MediaBrowser.Controller.Entities
public Guid[] ExcludeArtistIds { get; set; }
public string AncestorWithPresentationUniqueKey { get; set; }
public string? AncestorWithPresentationUniqueKey { get; set; }
public string SeriesPresentationUniqueKey { get; set; }
public string? SeriesPresentationUniqueKey { get; set; }
public bool GroupByPresentationUniqueKey { get; set; }
@@ -233,7 +265,7 @@ namespace MediaBrowser.Controller.Entities
public bool ForceDirect { get; set; }
public Dictionary<string, string> ExcludeProviderIds { get; set; }
public Dictionary<string, string>? ExcludeProviderIds { get; set; }
public bool EnableGroupByMetadataKey { get; set; }
@@ -251,13 +283,13 @@ namespace MediaBrowser.Controller.Entities
public int MinSimilarityScore { get; set; }
public string HasNoAudioTrackWithLanguage { get; set; }
public string? HasNoAudioTrackWithLanguage { get; set; }
public string HasNoInternalSubtitleTrackWithLanguage { get; set; }
public string? HasNoInternalSubtitleTrackWithLanguage { get; set; }
public string HasNoExternalSubtitleTrackWithLanguage { get; set; }
public string? HasNoExternalSubtitleTrackWithLanguage { get; set; }
public string HasNoSubtitleTrackWithLanguage { get; set; }
public string? HasNoSubtitleTrackWithLanguage { get; set; }
public bool? IsDeadArtist { get; set; }
@@ -265,74 +297,29 @@ namespace MediaBrowser.Controller.Entities
public bool? IsDeadPerson { get; set; }
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<string>();
ExcludeProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
ExcludeTags = Array.Empty<string>();
GenreIds = Array.Empty<Guid>();
Genres = Array.Empty<string>();
GroupByPresentationUniqueKey = true;
HasAnyProviderId = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
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>();
}
/// <summary>
/// Gets or sets a value indicating whether album sub-folders should be returned if they exist.
/// </summary>
public bool? DisplayAlbumFolders { get; set; }
public InternalItemsQuery(User user)
: this()
public BaseItem? Parent
{
SetUser(user);
}
public void SetUser(User user)
{
if (user != null)
set
{
MaxParentalRating = user.MaxParentalAgeRating;
if (MaxParentalRating.HasValue)
if (value == null)
{
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
.Where(i => i != UnratedItem.Other.ToString())
.Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
ParentId = Guid.Empty;
ParentType = null;
}
else
{
ParentId = value.Id;
ParentType = value.GetType().Name;
}
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
User = user;
}
}
public Dictionary<string, string> HasAnyProviderId { get; set; }
public Dictionary<string, string>? HasAnyProviderId { get; set; }
public Guid[] AlbumArtistIds { get; set; }
@@ -354,8 +341,25 @@ namespace MediaBrowser.Controller.Entities
public int? MinWidth { get; set; }
public string SearchTerm { get; set; }
public string? SearchTerm { get; set; }
public string SeriesTimerId { 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;
}
}
}

View File

@@ -1,11 +1,26 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using Jellyfin.Data.Entities;
namespace MediaBrowser.Controller.Entities
{
public class InternalPeopleQuery
{
public InternalPeopleQuery()
: this(Array.Empty<string>(), Array.Empty<string>())
{
}
public InternalPeopleQuery(IReadOnlyList<string> personTypes, IReadOnlyList<string> excludePersonTypes)
{
PersonTypes = personTypes;
ExcludePersonTypes = excludePersonTypes;
}
/// <summary>
/// Gets or sets the maximum number of items the query should return.
/// </summary>
@@ -13,9 +28,9 @@ namespace MediaBrowser.Controller.Entities
public Guid ItemId { get; set; }
public string[] PersonTypes { get; set; }
public IReadOnlyList<string> PersonTypes { get; }
public string[] ExcludePersonTypes { get; set; }
public IReadOnlyList<string> ExcludePersonTypes { get; }
public int? MaxListOrder { get; set; }
@@ -23,10 +38,8 @@ namespace MediaBrowser.Controller.Entities
public string NameContains { get; set; }
public InternalPeopleQuery()
{
PersonTypes = Array.Empty<string>();
ExcludePersonTypes = Array.Empty<string>();
}
public User User { get; set; }
public bool? IsFavorite { get; set; }
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;

View File

@@ -1,15 +1,20 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.Json.Serialization;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Entities
{
public class LinkedChild
{
public LinkedChild()
{
Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
public string Path { get; set; }
public LinkedChildType Type { get; set; }
@@ -20,7 +25,7 @@ namespace MediaBrowser.Controller.Entities
public string Id { get; set; }
/// <summary>
/// Serves as a cache.
/// Gets or sets the linked item id.
/// </summary>
public Guid? ItemId { get; set; }
@@ -39,41 +44,5 @@ namespace MediaBrowser.Controller.Entities
return child;
}
public LinkedChild()
{
Id = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
}
}
public enum LinkedChildType
{
Manual = 0,
Shortcut = 1
}
public class LinkedChildComparer : IEqualityComparer<LinkedChild>
{
private readonly IFileSystem _fileSystem;
public LinkedChildComparer(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public bool Equals(LinkedChild x, LinkedChild y)
{
if (x.Type == y.Type)
{
return _fileSystem.AreEqual(x.Path, y.Path);
}
return false;
}
public int GetHashCode(LinkedChild obj)
{
return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode();
}
}
}

View File

@@ -0,0 +1,35 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using MediaBrowser.Model.IO;
namespace MediaBrowser.Controller.Entities
{
public class LinkedChildComparer : IEqualityComparer<LinkedChild>
{
private readonly IFileSystem _fileSystem;
public LinkedChildComparer(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
public bool Equals(LinkedChild x, LinkedChild y)
{
if (x.Type == y.Type)
{
return _fileSystem.AreEqual(x.Path, y.Path);
}
return false;
}
public int GetHashCode(LinkedChild obj)
{
return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode(StringComparison.Ordinal);
}
}
}

View File

@@ -0,0 +1,18 @@
namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// The linked child type.
/// </summary>
public enum LinkedChildType
{
/// <summary>
/// Manually linked child.
/// </summary>
Manual = 0,
/// <summary>
/// Shortcut linked child.
/// </summary>
Shortcut = 1
}
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1721, CA1819, CS1591
using System;
using System.Collections.Generic;
@@ -47,9 +49,33 @@ 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.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie.ToString());
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie);
}
public override double GetDefaultPrimaryImageAspectRatio()
@@ -81,28 +107,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;
@@ -189,8 +193,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)
@@ -217,8 +219,7 @@ namespace MediaBrowser.Controller.Entities.Movies
private IEnumerable<BaseItem> FlattenItems(BaseItem item, List<Guid> expandedFolders)
{
var boxset = item as BoxSet;
if (boxset != null)
if (item is BoxSet boxset)
{
if (!expandedFolders.Contains(item.Id))
{

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -142,9 +144,9 @@ namespace MediaBrowser.Controller.Entities.Movies
}
/// <inheritdoc />
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (!ProductionYear.HasValue)
{

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -11,15 +13,15 @@ namespace MediaBrowser.Controller.Entities
{
public class MusicVideo : Video, IHasArtist, IHasMusicGenres, IHasLookupInfo<MusicVideoInfo>
{
/// <inheritdoc />
[JsonIgnore]
public IReadOnlyList<string> Artists { get; set; }
public MusicVideo()
{
Artists = Array.Empty<string>();
}
/// <inheritdoc />
[JsonIgnore]
public IReadOnlyList<string> Artists { get; set; }
public override UnratedItem GetBlockUnratedType()
{
return UnratedItem.Music;
@@ -34,9 +36,9 @@ namespace MediaBrowser.Controller.Entities
return info;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (!ProductionYear.HasValue)
{

View File

@@ -100,23 +100,5 @@ namespace MediaBrowser.Controller.Entities
existing.SetProviderId(id.Key, id.Value);
}
}
public static bool ContainsPerson(List<PersonInfo> people, string name)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
foreach (var i in people)
{
if (string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
}
}

View File

@@ -1,9 +1,11 @@
#nullable disable
#pragma warning disable CS1591
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;
@@ -14,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();
@@ -47,14 +69,6 @@ namespace MediaBrowser.Controller.Entities
return LibraryManager.GetItemList(query);
}
/// <summary>
/// Returns 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;
@@ -65,15 +79,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
[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);
@@ -124,9 +129,11 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <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(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
var newPath = GetRebasedPath();
if (!string.Equals(Path, newPath, StringComparison.Ordinal))

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA2227, CS1591
using System;
using System.Collections.Generic;

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System.Text.Json.Serialization;
@@ -24,8 +26,7 @@ namespace MediaBrowser.Controller.Entities
var parents = GetParents();
foreach (var parent in parents)
{
var photoAlbum = parent as PhotoAlbum;
if (photoAlbum != null)
if (parent is PhotoAlbum photoAlbum)
{
return photoAlbum;
}
@@ -35,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;
@@ -68,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; }
}
}

View File

@@ -1,12 +1,9 @@
#nullable disable
#pragma warning disable CS1591
namespace MediaBrowser.Controller.Entities
{
public interface IHasShares
{
Share[] Shares { get; set; }
}
public class Share
{
public string UserId { get; set; }

View File

@@ -1,9 +1,11 @@
#nullable disable
#pragma warning disable CS1591
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
@@ -13,6 +15,23 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Studio : BaseItem, IItemByName
{
/// <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 bool IsDisplayedAsFolder => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
[JsonIgnore]
public override bool SupportsPeople => false;
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
@@ -26,20 +45,6 @@ namespace MediaBrowser.Controller.Entities
return GetUserDataKeys()[0];
}
/// <summary>
/// Returns 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 bool IsDisplayedAsFolder => true;
[JsonIgnore]
public override bool SupportsAncestors => false;
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
@@ -65,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);
@@ -103,9 +105,11 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <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(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
var newPath = GetRebasedPath();
if (!string.Equals(Path, newPath, StringComparison.Ordinal))

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -32,7 +34,7 @@ namespace MediaBrowser.Controller.Entities.TV
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// Gets the season in which it aired.
/// Gets or sets the season in which it aired.
/// </summary>
/// <value>The aired season.</value>
public int? AirsBeforeSeasonNumber { get; set; }
@@ -42,17 +44,11 @@ namespace MediaBrowser.Controller.Entities.TV
public int? AirsBeforeEpisodeNumber { get; set; }
/// <summary>
/// This is the ending episode number for double episodes.
/// Gets or sets the ending episode number for double episodes.
/// </summary>
/// <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;
@@ -74,39 +70,8 @@ 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--;
}
list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000")));
}
return list;
}
/// <summary>
/// This Episode's Series Instance.
/// Gets the Episode's Series Instance.
/// </summary>
/// <value>The series.</value>
[JsonIgnore]
@@ -151,6 +116,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;
@@ -208,8 +241,8 @@ namespace MediaBrowser.Controller.Entities.TV
/// <returns>System.String.</returns>
protected override string CreateSortName()
{
return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ") : "")
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ", CultureInfo.InvariantCulture) : string.Empty)
+ (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ", CultureInfo.InvariantCulture) : string.Empty) + Name;
}
/// <summary>
@@ -232,28 +265,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>();
@@ -276,7 +287,8 @@ namespace MediaBrowser.Controller.Entities.TV
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
{
return new[] {
return new[]
{
new FileSystemMetadata
{
FullName = Path,
@@ -308,9 +320,9 @@ namespace MediaBrowser.Controller.Entities.TV
return id;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (!IsLocked)
{
@@ -318,7 +330,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
try
{
if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetdata))
if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetadata))
{
hasChanges = true;
}

View File

@@ -1,7 +1,10 @@
#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Entities;
@@ -35,42 +38,8 @@ namespace MediaBrowser.Controller.Entities.TV
[JsonIgnore]
public override Guid DisplayParentId => SeriesId;
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
value /= 3;
return value;
}
public string FindSeriesSortName()
{
var series = Series;
return series == null ? SeriesName : series.SortName;
}
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
var series = Series;
if (series != null)
{
list.InsertRange(0, series.GetUserDataKeys().Select(i => i + (IndexNumber ?? 0).ToString("000")));
}
return list;
}
public override int GetChildCount(User user)
{
var result = GetChildren(user, true).Count;
return result;
}
/// <summary>
/// This Episode's Series Instance.
/// Gets this Episode's Series Instance.
/// </summary>
/// <value>The series.</value>
[JsonIgnore]
@@ -104,6 +73,57 @@ namespace MediaBrowser.Controller.Entities.TV
}
}
[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;
value /= 3;
return value;
}
public string FindSeriesSortName()
{
var series = Series;
return series == null ? SeriesName : series.SortName;
}
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
var series = Series;
if (series != null)
{
var newList = series.GetUserDataKeys();
var suffix = (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture);
for (int i = 0; i < newList.Count; i++)
{
newList[i] = newList[i] + suffix;
}
newList.AddRange(list);
list = newList;
}
return list;
}
public override int GetChildCount(User user)
{
var result = GetChildren(user, true).Count;
return result;
}
public override string CreatePresentationUniqueKey()
{
if (IndexNumber.HasValue)
@@ -111,7 +131,7 @@ namespace MediaBrowser.Controller.Entities.TV
var series = Series;
if (series != null)
{
return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000");
return series.PresentationUniqueKey + "-" + (IndexNumber ?? 0).ToString("000", CultureInfo.InvariantCulture);
}
}
@@ -124,7 +144,7 @@ namespace MediaBrowser.Controller.Entities.TV
/// <returns>System.String.</returns>
protected override string CreateSortName()
{
return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name;
return IndexNumber != null ? IndexNumber.Value.ToString("0000", CultureInfo.InvariantCulture) : Name;
}
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
@@ -146,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);
@@ -182,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;
@@ -230,10 +244,11 @@ 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 replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path))
{

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -57,8 +59,11 @@ namespace MediaBrowser.Controller.Entities.TV
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
/// <summary>
/// airdate, dvd or absolute.
/// Gets or sets the display order.
/// </summary>
/// <remarks>
/// Valid options are airdate, dvd or absolute.
/// </remarks>
public string DisplayOrder { get; set; }
/// <summary>
@@ -67,6 +72,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;
@@ -107,7 +115,7 @@ namespace MediaBrowser.Controller.Entities.TV
return key;
}
return key + "-" + string.Join("-", folders);
return key + "-" + string.Join('-', folders);
}
private static string GetUniqueSeriesKey(BaseItem series)
@@ -151,7 +159,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
query.IncludeItemTypes = new[] { typeof(Episode).Name };
query.IncludeItemTypes = new[] { nameof(Episode) };
}
query.IsVirtualItem = false;
@@ -169,14 +177,12 @@ namespace MediaBrowser.Controller.Entities.TV
{
var list = base.GetUserDataKeys();
var key = this.GetProviderId(MetadataProvider.Imdb);
if (!string.IsNullOrEmpty(key))
if (this.TryGetProviderId(MetadataProvider.Imdb, out var key))
{
list.Insert(0, key);
}
key = this.GetProviderId(MetadataProvider.Tvdb);
if (!string.IsNullOrEmpty(key))
if (this.TryGetProviderId(MetadataProvider.Tvdb, out key))
{
list.Insert(0, key);
}
@@ -207,8 +213,8 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
query.IncludeItemTypes = new[] { typeof(Season).Name };
query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
query.IncludeItemTypes = new[] { nameof(Season) };
query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
if (user != null && !user.DisplayMissingEpisodes)
{
@@ -228,12 +234,12 @@ namespace MediaBrowser.Controller.Entities.TV
query.SeriesPresentationUniqueKey = seriesKey;
if (query.OrderBy.Count == 0)
{
query.OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray();
query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
}
if (query.IncludeItemTypes.Length == 0)
{
query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name };
query.IncludeItemTypes = new[] { nameof(Episode), nameof(Season) };
}
query.IsVirtualItem = false;
@@ -253,8 +259,8 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name },
OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
IncludeItemTypes = new[] { nameof(Episode), nameof(Season) },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
@@ -318,20 +324,13 @@ namespace MediaBrowser.Controller.Entities.TV
cancellationToken.ThrowIfCancellationRequested();
var skipItem = false;
var episode = item as Episode;
if (episode != null
bool skipItem = item is Episode episode
&& refreshOptions.MetadataRefreshMode != MetadataRefreshMode.FullRefresh
&& !refreshOptions.ReplaceAllMetadata
&& episode.IsMissingEpisode
&& episode.LocationType == LocationType.Virtual
&& episode.PremiereDate.HasValue
&& (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30)
{
skipItem = true;
}
&& (DateTime.UtcNow - episode.PremiereDate.Value).TotalDays > 30;
if (!skipItem)
{
@@ -364,8 +363,8 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
IncludeItemTypes = new[] { typeof(Episode).Name },
OrderBy = new[] { ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Ascending)).ToArray(),
IncludeItemTypes = new[] { nameof(Episode) },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
if (user != null)
@@ -398,6 +397,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;
@@ -428,6 +431,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)
@@ -452,7 +459,7 @@ namespace MediaBrowser.Controller.Entities.TV
protected override bool GetBlockUnratedValue(User user)
{
return user.GetPreference(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Series.ToString());
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Series);
}
public override UnratedItem GetBlockUnratedType()
@@ -503,8 +510,5 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
[JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
}
}

View File

@@ -1,4 +1,6 @@
#pragma warning disable CS1591
#nullable disable
#pragma warning disable CA1819, CS1591
using System;
using System.Collections.Generic;
@@ -21,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()
@@ -43,9 +48,9 @@ namespace MediaBrowser.Controller.Entities
return info;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (!ProductionYear.HasValue)
{
@@ -95,8 +100,5 @@ namespace MediaBrowser.Controller.Entities
return list;
}
[JsonIgnore]
public override bool StopRefreshIfLocalMetadataFound => false;
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -10,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>
@@ -22,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>
@@ -91,10 +95,8 @@ namespace MediaBrowser.Controller.Entities
/// <value>The index of the subtitle stream.</value>
public int? SubtitleStreamIndex { get; set; }
public const double MinLikeValue = 6.5;
/// <summary>
/// This is an interpreted property to indicate likes or dislikes
/// Gets or sets a value indicating whether the item is liked or not.
/// This should never be serialized.
/// </summary>
/// <value><c>null</c> if [likes] contains no value, <c>true</c> if [likes]; otherwise, <c>false</c>.</value>

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -19,8 +21,29 @@ 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;
[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()
{
lock (_childIdsLock)
@@ -36,20 +59,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)
@@ -71,12 +80,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();
@@ -85,10 +88,10 @@ namespace MediaBrowser.Controller.Entities
return list;
}
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
ClearCache();
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
if (string.Equals("default", Name, StringComparison.OrdinalIgnoreCase))
{
@@ -106,11 +109,11 @@ namespace MediaBrowser.Controller.Entities
return base.GetNonCachedChildren(directoryService);
}
protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
{
ClearCache();
await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService)
await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, refreshOptions, directoryService, cancellationToken)
.ConfigureAwait(false);
ClearCache();

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -13,21 +15,56 @@ namespace MediaBrowser.Controller.Entities
{
public class UserView : Folder, IHasCollectionType
{
/// <inheritdoc />
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>
public string ViewType { get; set; }
/// <inheritdoc />
/// <summary>
/// Gets or sets the display parent id.
/// </summary>
public new Guid DisplayParentId { get; set; }
/// <inheritdoc />
/// <summary>
/// Gets or sets the user id.
/// </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()
{
@@ -45,17 +82,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;
@@ -73,12 +106,10 @@ namespace MediaBrowser.Controller.Entities
.GetUserItems(parent, this, CollectionType, query);
}
/// <inheritdoc />
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
{
if (query == null)
{
query = new InternalItemsQuery(user);
}
query ??= new InternalItemsQuery(user);
query.EnableTotalRecordCount = false;
var result = GetItemList(query);
@@ -86,16 +117,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);
@@ -106,32 +140,26 @@ namespace MediaBrowser.Controller.Entities
return GetItemList(query);
}
/// <inheritdoc />
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
{
return GetChildren(user, false);
}
private static 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)
@@ -140,39 +168,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, StringComparer.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, StringComparer.OrdinalIgnoreCase);
}
protected override Task ValidateChildrenInternal(IProgress<double> progress, System.Threading.CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService)
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;
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -53,17 +55,17 @@ namespace MediaBrowser.Controller.Entities
// if (query.IncludeItemTypes != null &&
// query.IncludeItemTypes.Length == 1 &&
// string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
//{
// {
// if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
// {
// return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
// }
//}
// }
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);
@@ -108,7 +110,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);
@@ -120,7 +122,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);
@@ -142,7 +144,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IncludeItemTypes.Length == 0)
{
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(Movie) };
}
return parent.QueryRecursive(query);
@@ -158,7 +160,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)
@@ -167,7 +169,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(Movie) };
return _libraryManager.GetItemsResult(query);
}
@@ -178,7 +180,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
query.IncludeItemTypes = new[] { typeof(Series).Name };
query.IncludeItemTypes = new[] { nameof(Series) };
return _libraryManager.GetItemsResult(query);
}
@@ -189,7 +191,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
query.IncludeItemTypes = new[] { typeof(Episode).Name };
query.IncludeItemTypes = new[] { nameof(Episode) };
return _libraryManager.GetItemsResult(query);
}
@@ -200,15 +202,15 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(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[] { typeof(BoxSet).Name };
query.IncludeItemTypes = new[] { nameof(BoxSet) };
query.SetUser(user);
query.Recursive = true;
@@ -217,26 +219,25 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
{
query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(Movie) };
return ConvertToResult(_libraryManager.GetItemList(query));
}
private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
{
query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(Movie) };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -255,7 +256,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Movie).Name },
IncludeItemTypes = new[] { nameof(Movie) },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -274,9 +275,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)
@@ -286,7 +287,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(Movie).Name };
query.IncludeItemTypes = new[] { nameof(Movie) };
return _libraryManager.GetItemsResult(query);
}
@@ -322,18 +323,17 @@ 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)
{
query.OrderBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
query.IncludeItemTypes = new[] { nameof(Episode) };
query.IsVirtualItem = false;
return ConvertToResult(_libraryManager.GetItemList(query));
@@ -344,25 +344,27 @@ namespace MediaBrowser.Controller.Entities
var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
var result = _tvSeriesManager.GetNextUp(
new NextUpQuery
{
Limit = query.Limit,
StartIndex = query.StartIndex,
UserId = query.User.Id
}, parentFolders, query.DtoOptions);
new NextUpQuery
{
Limit = query.Limit,
StartIndex = query.StartIndex,
UserId = query.User.Id
},
parentFolders,
query.DtoOptions);
return result;
}
private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
{
query.OrderBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray();
query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending) };
query.IsResumable = true;
query.Recursive = true;
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
query.IncludeItemTypes = new[] { typeof(Episode).Name };
query.IncludeItemTypes = new[] { nameof(Episode) };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -373,7 +375,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(Series).Name };
query.IncludeItemTypes = new[] { nameof(Series) };
return _libraryManager.GetItemsResult(query);
}
@@ -382,7 +384,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
IncludeItemTypes = new[] { typeof(Series).Name },
IncludeItemTypes = new[] { nameof(Series) },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -401,9 +403,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)
@@ -413,7 +415,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
query.IncludeItemTypes = new[] { typeof(Series).Name };
query.IncludeItemTypes = new[] { nameof(Series) };
return _libraryManager.GetItemsResult(query);
}
@@ -430,13 +432,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)
@@ -446,11 +447,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;
@@ -791,7 +790,7 @@ namespace MediaBrowser.Controller.Entities
}
// Apply genre filter
if (query.Genres.Length > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
{
return false;
}
@@ -822,7 +821,7 @@ namespace MediaBrowser.Controller.Entities
}
// Apply genre filter
if (query.GenreIds.Length > 0 && !query.GenreIds.Any(id =>
if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
{
var genreItem = libraryManager.GetItemById(id);
return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparer.OrdinalIgnoreCase);
@@ -999,7 +998,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);
}

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -26,6 +28,14 @@ namespace MediaBrowser.Controller.Entities
ISupportsPlaceHolders,
IHasMediaSources
{
public Video()
{
AdditionalParts = Array.Empty<string>();
LocalAlternateVersions = Array.Empty<string>();
SubtitleFiles = Array.Empty<string>();
LinkedAlternateVersions = Array.Empty<LinkedChild>();
}
[JsonIgnore]
public string PrimaryVersionId { get; set; }
@@ -72,30 +82,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;
@@ -143,50 +129,12 @@ namespace MediaBrowser.Controller.Entities
/// <value>The video3 D format.</value>
public Video3DFormat? Video3DFormat { get; set; }
public string[] GetPlayableStreamFileNames()
{
var videoType = VideoType;
if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.BluRay)
{
videoType = VideoType.BluRay;
}
else if (videoType == VideoType.Iso && IsoType == Model.Entities.IsoType.Dvd)
{
videoType = VideoType.Dvd;
}
else
{
return Array.Empty<string>();
}
throw new NotImplementedException();
}
/// <summary>
/// Gets or sets the aspect ratio.
/// </summary>
/// <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;
@@ -214,16 +162,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]
@@ -240,21 +178,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
{
@@ -272,80 +195,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
{
@@ -387,6 +236,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);
@@ -415,45 +411,6 @@ namespace MediaBrowser.Controller.Entities
return updateType;
}
public static string[] QueryPlayableStreamFiles(string rootPath, VideoType videoType)
{
if (videoType == VideoType.Dvd)
{
return FileSystem.GetFiles(rootPath, new[] { ".vob" }, false, true)
.OrderByDescending(i => i.Length)
.ThenBy(i => i.FullName)
.Take(1)
.Select(i => i.FullName)
.ToArray();
}
if (videoType == VideoType.BluRay)
{
return FileSystem.GetFiles(rootPath, new[] { ".m2ts" }, false, true)
.OrderByDescending(i => i.Length)
.ThenBy(i => i.FullName)
.Take(1)
.Select(i => i.FullName)
.ToArray();
}
return Array.Empty<string>();
}
/// <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);
@@ -525,7 +482,8 @@ namespace MediaBrowser.Controller.Entities
{
if (!IsInMixedFolder)
{
return new[] {
return new[]
{
new FileSystemMetadata
{
FullName = ContainingFolderPath,

View File

@@ -1,3 +1,5 @@
#nullable disable
#pragma warning disable CS1591
using System;
@@ -13,6 +15,25 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Year : BaseItem, IItemByName
{
[JsonIgnore]
public override bool SupportsAncestors => false;
[JsonIgnore]
public override bool SupportsPeople => 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;
public override bool CanDelete()
{
return false;
}
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
@@ -21,14 +42,6 @@ namespace MediaBrowser.Controller.Entities
return list;
}
/// <summary>
/// Returns 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 double GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
@@ -37,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;
@@ -74,9 +79,6 @@ namespace MediaBrowser.Controller.Entities
return null;
}
[JsonIgnore]
public override bool SupportsPeople => false;
public static string GetPath(string name)
{
return GetPath(name, true);
@@ -110,11 +112,13 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// This is called before any metadata refresh and returns true if changes were made.
/// </summary>
public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
/// <param name="replaceAllMetadata">Whether to replace all metadata.</param>
/// <returns>true if the item has change, else false.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
var newPath = GetRebasedPath();
if (!string.Equals(Path, newPath, StringComparison.Ordinal))

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Events

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Events

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Session;
namespace MediaBrowser.Controller.Events.Session

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Session;
namespace MediaBrowser.Controller.Events.Session

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates

View File

@@ -1,18 +1,18 @@
using Jellyfin.Data.Events;
using MediaBrowser.Common.Plugins;
using Jellyfin.Data.Events;
using MediaBrowser.Model.Plugins;
namespace MediaBrowser.Controller.Events.Updates
{
/// <summary>
/// An event that occurs when a plugin is uninstalled.
/// </summary>
public class PluginUninstalledEventArgs : GenericEventArgs<IPlugin>
public class PluginUninstalledEventArgs : GenericEventArgs<PluginInfo>
{
/// <summary>
/// Initializes a new instance of the <see cref="PluginUninstalledEventArgs"/> class.
/// </summary>
/// <param name="arg">The plugin.</param>
public PluginUninstalledEventArgs(IPlugin arg) : base(arg)
public PluginUninstalledEventArgs(PluginInfo arg) : base(arg)
{
}
}

View File

@@ -1,4 +1,4 @@
using Jellyfin.Data.Events;
using Jellyfin.Data.Events;
using MediaBrowser.Model.Updates;
namespace MediaBrowser.Controller.Events.Updates

View File

@@ -1,53 +0,0 @@
#nullable enable
#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);
}
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])", "");
return Normalize(text, form, false);
}
}
try
{
return text.Normalize(form);
}
catch (ArgumentException)
{
// if it still fails, return the original text
return text;
}
}
}
}

View File

@@ -1,3 +1,5 @@
#nullable disable
using System;
using System.Collections.Generic;
using Jellyfin.Data.Entities;
@@ -12,14 +14,21 @@ namespace MediaBrowser.Controller
/// <summary>
/// Gets the display preferences for the user and client.
/// </summary>
/// <remarks>
/// This will create the display preferences if it does not exist, but it will not save automatically.
/// </remarks>
/// <param name="userId">The user's id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="client">The client string.</param>
/// <returns>The associated display preferences.</returns>
DisplayPreferences GetDisplayPreferences(Guid userId, string client);
DisplayPreferences GetDisplayPreferences(Guid userId, Guid itemId, string client);
/// <summary>
/// Gets the default item display preferences for the user and client.
/// </summary>
/// <remarks>
/// This will create the item display preferences if it does not exist, but it will not save automatically.
/// </remarks>
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="client">The client string.</param>
@@ -34,6 +43,24 @@ namespace MediaBrowser.Controller
/// <returns>A list of item display preferences.</returns>
IList<ItemDisplayPreferences> ListItemDisplayPreferences(Guid userId, string client);
/// <summary>
/// Gets all of the custom item display preferences for the user and client.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="client">The client string.</param>
/// <returns>The dictionary of custom item display preferences.</returns>
Dictionary<string, string> ListCustomItemDisplayPreferences(Guid userId, Guid itemId, string client);
/// <summary>
/// Sets the custom item display preference for the user and client.
/// </summary>
/// <param name="userId">The user id.</param>
/// <param name="itemId">The item id.</param>
/// <param name="client">The client id.</param>
/// <param name="customPreferences">A dictionary of custom item display preferences.</param>
void SetCustomItemDisplayPreferences(Guid userId, Guid itemId, string client, Dictionary<string, string> customPreferences);
/// <summary>
/// Saves changes made to the database.
/// </summary>

Some files were not shown because too many files have changed in this diff Show More