mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-04 14:58:36 +01:00
Merge branch 'master' into comparisons
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using MediaBrowser.Common.Extensions;
|
||||
using MediaBrowser.Controller.Channels;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@@ -52,7 +53,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
|
||||
if (typeOptions != null)
|
||||
{
|
||||
return typeOptions.MetadataFetchers.Contains(name, StringComparer.OrdinalIgnoreCase);
|
||||
return typeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (!libraryOptions.EnableInternetProviders)
|
||||
@@ -62,7 +63,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return itemConfig == null || !itemConfig.DisabledMetadataFetchers.Contains(name, StringComparer.OrdinalIgnoreCase);
|
||||
return itemConfig == null || !itemConfig.DisabledMetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -83,7 +84,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
var typeOptions = libraryOptions.GetTypeOptions(baseItem.GetType().Name);
|
||||
if (typeOptions != null)
|
||||
{
|
||||
return typeOptions.ImageFetchers.Contains(name, StringComparer.OrdinalIgnoreCase);
|
||||
return typeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
if (!libraryOptions.EnableInternetProviders)
|
||||
@@ -93,7 +94,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
||||
|
||||
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return itemConfig == null || !itemConfig.DisabledImageFetchers.Contains(name, StringComparer.OrdinalIgnoreCase);
|
||||
return itemConfig == null || !itemConfig.DisabledImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -84,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);
|
||||
}
|
||||
|
||||
@@ -13,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; }
|
||||
@@ -80,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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelItemResult
|
||||
{
|
||||
public List<ChannelItemInfo> Items { get; set; }
|
||||
|
||||
public int? TotalRecordCount { get; set; }
|
||||
|
||||
public ChannelItemResult()
|
||||
{
|
||||
Items = new List<ChannelItemInfo>();
|
||||
}
|
||||
|
||||
public List<ChannelItemInfo> Items { get; set; }
|
||||
|
||||
public int? TotalRecordCount { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
11
MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs
Normal file
11
MediaBrowser.Controller/Channels/ChannelLatestMediaSearch.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public class ChannelLatestMediaSearch
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,4 @@ namespace MediaBrowser.Controller.Channels
|
||||
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
public class ChannelLatestMediaSearch
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,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>
|
||||
@@ -84,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
9
MediaBrowser.Controller/Channels/IHasFolderAttributes.cs
Normal file
9
MediaBrowser.Controller/Channels/IHasFolderAttributes.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
public interface IHasFolderAttributes
|
||||
{
|
||||
string[] Attributes { get; }
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
@@ -19,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; }
|
||||
}
|
||||
}
|
||||
|
||||
15
MediaBrowser.Controller/Channels/ISupportsDelete.cs
Normal file
15
MediaBrowser.Controller/Channels/ISupportsDelete.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
21
MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs
Normal file
21
MediaBrowser.Controller/Channels/ISupportsLatestMedia.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
9
MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs
Normal file
9
MediaBrowser.Controller/Channels/ISupportsMediaProbe.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
{
|
||||
/// <summary>
|
||||
/// Channel supports media probe.
|
||||
/// </summary>
|
||||
public interface ISupportsMediaProbe
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -30,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; }
|
||||
|
||||
@@ -41,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; }
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -25,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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,23 +9,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>
|
||||
@@ -36,6 +27,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; }
|
||||
}
|
||||
}
|
||||
@@ -20,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>
|
||||
@@ -47,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);
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Drawing
|
||||
@@ -10,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.
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
#nullable enable
|
||||
|
||||
using MediaBrowser.Model.Drawing;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,28 @@ namespace MediaBrowser.Controller.Dto
|
||||
ItemFields.RefreshState
|
||||
};
|
||||
|
||||
private static readonly ImageType[] AllImageTypes = Enum.GetValues<ImageType>();
|
||||
|
||||
private static readonly ItemFields[] AllItemFields = Enum.GetValues<ItemFields>()
|
||||
.Except(DefaultExcludedFields)
|
||||
.ToArray();
|
||||
|
||||
public DtoOptions()
|
||||
: this(true)
|
||||
{
|
||||
}
|
||||
|
||||
public DtoOptions(bool allFields)
|
||||
{
|
||||
ImageTypeLimit = int.MaxValue;
|
||||
EnableImages = true;
|
||||
EnableUserData = true;
|
||||
AddCurrentProgram = true;
|
||||
|
||||
Fields = allFields ? AllItemFields : Array.Empty<ItemFields>();
|
||||
ImageTypes = AllImageTypes;
|
||||
}
|
||||
|
||||
public IReadOnlyList<ItemFields> Fields { get; set; }
|
||||
|
||||
public IReadOnlyList<ImageType> ImageTypes { get; set; }
|
||||
@@ -32,34 +54,9 @@ namespace MediaBrowser.Controller.Dto
|
||||
|
||||
public bool AddCurrentProgram { get; set; }
|
||||
|
||||
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;
|
||||
EnableImages = true;
|
||||
EnableUserData = true;
|
||||
AddCurrentProgram = true;
|
||||
|
||||
Fields = allFields ? AllItemFields : Array.Empty<ItemFields>();
|
||||
ImageTypes = AllImageTypes;
|
||||
}
|
||||
|
||||
public int GetImageLimit(ImageType type)
|
||||
{
|
||||
if (EnableImages && ImageTypes.Contains(type))
|
||||
|
||||
@@ -36,11 +36,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
public class AggregateFolder : Folder
|
||||
{
|
||||
private bool _requiresRefresh;
|
||||
|
||||
public AggregateFolder()
|
||||
{
|
||||
PhysicalLocationsList = Array.Empty<string>();
|
||||
@@ -85,7 +87,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
private bool _requiresRefresh;
|
||||
public override bool RequiresRefresh()
|
||||
{
|
||||
var changed = base.RequiresRefresh() || _requiresRefresh;
|
||||
@@ -105,11 +106,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;
|
||||
}
|
||||
@@ -154,11 +155,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();
|
||||
@@ -184,7 +185,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))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using Jellyfin.Data.Enums;
|
||||
@@ -82,19 +83,19 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
/// <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;
|
||||
|
||||
@@ -94,7 +94,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)
|
||||
{
|
||||
@@ -102,7 +102,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()
|
||||
@@ -114,7 +114,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
@@ -208,9 +208,9 @@ 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)
|
||||
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
|
||||
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
|
||||
|
||||
if (IsAccessedByName)
|
||||
{
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace MediaBrowser.Controller.Entities.Audio
|
||||
public override bool IsDisplayedAsFolder => true;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
@@ -106,9 +106,9 @@ 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)
|
||||
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))
|
||||
|
||||
@@ -92,7 +92,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
public const string ShortsFolderName = "shorts";
|
||||
public const string FeaturettesFolderName = "featurettes";
|
||||
|
||||
public static readonly string[] AllExtrasTypesFolderNames = {
|
||||
public static readonly string[] AllExtrasTypesFolderNames =
|
||||
{
|
||||
ExtrasFolderName,
|
||||
BehindTheScenesFolderName,
|
||||
DeletedScenesFolderName,
|
||||
@@ -177,7 +178,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public virtual bool AlwaysScanInternalMetadataPath => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is in mixed folder.
|
||||
/// Gets or sets a value indicating whether this instance is in mixed folder.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is in mixed folder; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
@@ -244,7 +245,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public ProgramAudio? Audio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the id that should be used to key display prefs for this item.
|
||||
/// Gets the id that should be used to key display prefs for this item.
|
||||
/// Default is based on the type for everything except actual generic folders.
|
||||
/// </summary>
|
||||
/// <value>The display prefs id.</value>
|
||||
@@ -280,7 +281,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
@@ -305,8 +306,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If this content came from an external service, the id of the content on that service.
|
||||
/// Gets or sets the external id.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this content came from an external service, the id of the content on that service.
|
||||
/// </remarks>
|
||||
[JsonIgnore]
|
||||
public string ExternalId { get; set; }
|
||||
|
||||
@@ -330,7 +334,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the location.
|
||||
/// Gets the type of the location.
|
||||
/// </summary>
|
||||
/// <value>The type of the location.</value>
|
||||
[JsonIgnore]
|
||||
@@ -339,9 +343,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
get
|
||||
{
|
||||
// if (IsOffline)
|
||||
//{
|
||||
// {
|
||||
// return LocationType.Offline;
|
||||
//}
|
||||
// }
|
||||
|
||||
var path = Path;
|
||||
if (string.IsNullOrEmpty(path))
|
||||
@@ -449,8 +453,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is just a helper for convenience.
|
||||
/// Gets the primary image path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is just a helper for convenience.
|
||||
/// </remarks>
|
||||
/// <value>The primary image path.</value>
|
||||
[JsonIgnore]
|
||||
public string PrimaryImagePath => this.GetImagePath(ImageType.Primary);
|
||||
@@ -541,7 +548,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public DateTime DateLastRefreshed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The logger.
|
||||
/// Gets or sets the logger.
|
||||
/// </summary>
|
||||
public static ILogger<BaseItem> Logger { get; set; }
|
||||
|
||||
@@ -613,7 +620,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
public string ForcedSortName
|
||||
{
|
||||
get => _forcedSortName;
|
||||
set { _forcedSortName = value; _sortName = null; }
|
||||
set
|
||||
{
|
||||
_forcedSortName = value;
|
||||
_sortName = null;
|
||||
}
|
||||
}
|
||||
|
||||
private string _sortName;
|
||||
@@ -621,7 +632,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
private Guid[] _themeVideoIds;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the sort.
|
||||
/// Gets or sets the name of the sort.
|
||||
/// </summary>
|
||||
/// <value>The name of the sort.</value>
|
||||
[JsonIgnore]
|
||||
@@ -659,14 +670,12 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (SourceType == SourceType.Channel)
|
||||
{
|
||||
return System.IO.Path.Combine(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
|
||||
return System.IO.Path.Join(basePath, "channels", ChannelId.ToString("N", CultureInfo.InvariantCulture), Id.ToString("N", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
|
||||
|
||||
basePath = System.IO.Path.Combine(basePath, "library");
|
||||
|
||||
return System.IO.Path.Join(basePath, idString.Slice(0, 2), idString);
|
||||
return System.IO.Path.Join(basePath, "library", idString.Slice(0, 2), idString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -848,7 +857,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When the item first debuted. For movies this could be premiere date, episodes would be first aired
|
||||
/// Gets or sets the date that the item first debuted. For movies this could be premiere date, episodes would be first aired.
|
||||
/// </summary>
|
||||
/// <value>The premiere date.</value>
|
||||
[JsonIgnore]
|
||||
@@ -945,7 +954,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public int? ProductionYear { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If the item is part of a series, this is it's number in the series.
|
||||
/// Gets or sets the index number. If the item is part of a series, this is it's number in the series.
|
||||
/// This could be episode number, album track number, etc.
|
||||
/// </summary>
|
||||
/// <value>The index number.</value>
|
||||
@@ -953,7 +962,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
public int? IndexNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For an episode this could be the season number, or for a song this could be the disc number.
|
||||
/// Gets or sets the parent index number. For an episode this could be the season number, or for a song this could be the disc number.
|
||||
/// </summary>
|
||||
/// <value>The parent index number.</value>
|
||||
[JsonIgnore]
|
||||
@@ -1017,9 +1026,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
// if (!user.IsParentalScheduleAllowed())
|
||||
//{
|
||||
// {
|
||||
// return PlayAccess.None;
|
||||
//}
|
||||
// }
|
||||
|
||||
return PlayAccess.Full;
|
||||
}
|
||||
@@ -1251,7 +1260,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
// Support plex/xbmc convention
|
||||
files.AddRange(fileSystemChildren
|
||||
.Where(i => !i.IsDirectory && string.Equals(FileSystem.GetFileNameWithoutExtension(i), ThemeSongFilename, StringComparison.OrdinalIgnoreCase)));
|
||||
.Where(i => !i.IsDirectory && System.IO.Path.GetFileNameWithoutExtension(i.FullName.AsSpan()).Equals(ThemeSongFilename, StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
|
||||
.OfType<Audio.Audio>()
|
||||
@@ -1312,14 +1321,16 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
var extras = new List<Video>();
|
||||
|
||||
var folders = fileSystemChildren.Where(i => i.IsDirectory).ToArray();
|
||||
var libraryOptions = new LibraryOptions();
|
||||
var folders = fileSystemChildren.Where(i => i.IsDirectory).ToList();
|
||||
foreach (var extraFolderName in AllExtrasTypesFolderNames)
|
||||
{
|
||||
var files = folders
|
||||
.Where(i => string.Equals(i.Name, extraFolderName, StringComparison.OrdinalIgnoreCase))
|
||||
.SelectMany(i => FileSystem.GetFiles(i.FullName));
|
||||
|
||||
extras.AddRange(LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
|
||||
// Re-using the same instance of LibraryOptions since it looks like it's never being altered.
|
||||
extras.AddRange(LibraryManager.ResolvePaths(files, directoryService, null, libraryOptions)
|
||||
.OfType<Video>()
|
||||
.Select(item =>
|
||||
{
|
||||
@@ -1330,7 +1341,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
// Use some hackery to get the extra type based on foldername
|
||||
item.ExtraType = Enum.TryParse(extraFolderName.Replace(" ", string.Empty), true, out ExtraType extraType)
|
||||
item.ExtraType = Enum.TryParse(extraFolderName.Replace(" ", string.Empty, StringComparison.Ordinal), true, out ExtraType extraType)
|
||||
? extraType
|
||||
: Model.Entities.ExtraType.Unknown;
|
||||
|
||||
@@ -1420,10 +1431,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// Refreshes owned items such as trailers, theme videos, special features, etc.
|
||||
/// Returns true or false indicating if changes were found.
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <param name="fileSystemChildren"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="options">The metadata refresh options.</param>
|
||||
/// <param name="fileSystemChildren">The list of filesystem children.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns><c>true</c> if any items have changed, else <c>false</c>.</returns>
|
||||
protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
var themeSongsChanged = false;
|
||||
@@ -1765,7 +1776,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns><c>true</c> if [is parental allowed] [the specified user]; otherwise, <c>false</c>.</returns>
|
||||
/// <exception cref="ArgumentNullException">user</exception>
|
||||
/// <exception cref="ArgumentNullException">If user is null.</exception>
|
||||
public bool IsParentalAllowed(User user)
|
||||
{
|
||||
if (user == null)
|
||||
@@ -1910,7 +1921,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns><c>true</c> if the specified user is visible; otherwise, <c>false</c>.</returns>
|
||||
/// <exception cref="ArgumentNullException">user</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="user" /> is <c>null</c>.</exception>
|
||||
public virtual bool IsVisible(User user)
|
||||
{
|
||||
if (user == null)
|
||||
@@ -2208,7 +2219,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="type">The type.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns><c>true</c> if the specified type has image; otherwise, <c>false</c>.</returns>
|
||||
/// <exception cref="ArgumentException">Backdrops should be accessed using Item.Backdrops</exception>
|
||||
/// <exception cref="ArgumentException">Backdrops should be accessed using Item.Backdrops.</exception>
|
||||
public bool HasImage(ImageType type, int imageIndex)
|
||||
{
|
||||
return GetImageInfo(type, imageIndex) != null;
|
||||
@@ -2316,7 +2327,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
.Where(i => i.IsLocalFile)
|
||||
.Select(i => System.IO.Path.GetDirectoryName(i.Path))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.SelectMany(directoryService.GetFilePaths)
|
||||
.SelectMany(path => directoryService.GetFilePaths(path))
|
||||
.ToList();
|
||||
|
||||
var deletedImages = ImageInfos
|
||||
@@ -2337,9 +2348,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="imageIndex">Index of the image.</param>
|
||||
/// <returns>System.String.</returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// </exception>
|
||||
/// <exception cref="ArgumentNullException">item</exception>
|
||||
/// <exception cref="InvalidOperationException"> </exception>
|
||||
/// <exception cref="ArgumentNullException">Item is null.</exception>
|
||||
public string GetImagePath(ImageType imageType, int imageIndex)
|
||||
=> GetImageInfo(imageType, imageIndex)?.Path;
|
||||
|
||||
@@ -2426,7 +2436,15 @@ namespace MediaBrowser.Controller.Entities
|
||||
throw new ArgumentException("No image info for chapter images");
|
||||
}
|
||||
|
||||
return ImageInfos.Where(i => i.Type == imageType);
|
||||
// Yield return is more performant than LINQ Where on an Array
|
||||
for (var i = 0; i < ImageInfos.Length; i++)
|
||||
{
|
||||
var imageInfo = ImageInfos[i];
|
||||
if (imageInfo.Type == imageType)
|
||||
{
|
||||
yield return imageInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -2435,7 +2453,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <param name="imageType">Type of the image.</param>
|
||||
/// <param name="images">The images.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
|
||||
/// <exception cref="ArgumentException">Cannot call AddImages with chapter images</exception>
|
||||
/// <exception cref="ArgumentException">Cannot call AddImages with chapter images.</exception>
|
||||
public bool AddImages(ImageType imageType, List<FileSystemMetadata> images)
|
||||
{
|
||||
if (imageType == ImageType.Chapter)
|
||||
@@ -2458,7 +2476,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
var existing = existingImages
|
||||
.FirstOrDefault(i => string.Equals(i.Path, newImage.FullName, StringComparison.OrdinalIgnoreCase));
|
||||
.Find(i => string.Equals(i.Path, newImage.FullName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (existing == null)
|
||||
{
|
||||
@@ -2489,8 +2507,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
var newImagePaths = images.Select(i => i.FullName).ToList();
|
||||
|
||||
var deleted = existingImages
|
||||
.Where(i => i.IsLocalFile && !newImagePaths.Contains(i.Path, StringComparer.OrdinalIgnoreCase) && !File.Exists(i.Path))
|
||||
.ToList();
|
||||
.FindAll(i => i.IsLocalFile && !newImagePaths.Contains(i.Path.AsSpan(), StringComparison.OrdinalIgnoreCase) && !File.Exists(i.Path));
|
||||
|
||||
if (deleted.Count > 0)
|
||||
{
|
||||
@@ -2519,10 +2536,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Gets the file system path to delete when the item is to be deleted.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns>The metadata for the deleted paths.</returns>
|
||||
public virtual IEnumerable<FileSystemMetadata> GetDeletePaths()
|
||||
{
|
||||
return new[] {
|
||||
return new[]
|
||||
{
|
||||
new FileSystemMetadata
|
||||
{
|
||||
FullName = Path,
|
||||
@@ -2629,6 +2647,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
MetadataCountryCode = GetPreferredMetadataCountryCode(),
|
||||
MetadataLanguage = GetPreferredMetadataLanguage(),
|
||||
Name = GetNameForMetadataLookup(),
|
||||
OriginalTitle = OriginalTitle,
|
||||
ProviderIds = ProviderIds,
|
||||
IndexNumber = IndexNumber,
|
||||
ParentIndexNumber = ParentIndexNumber,
|
||||
@@ -2645,7 +2664,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// This is called before any metadata refresh and returns true if changes were made.
|
||||
/// </summary>
|
||||
public virtual bool BeforeMetadataRefresh(bool replaceAllMetdata)
|
||||
/// <param name="replaceAllMetadata">Whether to replace all metadata.</param>
|
||||
/// <returns>true if the item has change, else false.</returns>
|
||||
public virtual bool BeforeMetadataRefresh(bool replaceAllMetadata)
|
||||
{
|
||||
_sortName = null;
|
||||
|
||||
@@ -2769,11 +2790,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
// var parentId = Id;
|
||||
// if (!video.IsOwnedItem || video.ParentId != parentId)
|
||||
//{
|
||||
// {
|
||||
// video.IsOwnedItem = true;
|
||||
// video.ParentId = parentId;
|
||||
// newOptions.ForceSave = true;
|
||||
//}
|
||||
// }
|
||||
|
||||
if (video == null)
|
||||
{
|
||||
@@ -2880,7 +2901,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
/// <summary>
|
||||
/// Updates the official rating based on content and returns true or false indicating if it changed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns><c>true</c> if the rating was updated; otherwise <c>false</c>.</returns>
|
||||
public bool UpdateRatingToItems(IList<BaseItem> children)
|
||||
{
|
||||
var currentOfficialRating = OfficialRating;
|
||||
@@ -2896,7 +2917,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating;
|
||||
|
||||
return !string.Equals(currentOfficialRating ?? string.Empty, OfficialRating ?? string.Empty,
|
||||
return !string.Equals(
|
||||
currentOfficialRating ?? string.Empty,
|
||||
OfficialRating ?? string.Empty,
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
@@ -2993,7 +3016,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Equals(BaseItem item) => Object.Equals(Id, item?.Id);
|
||||
public bool Equals(BaseItem other) => object.Equals(Id, other?.Id);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int GetHashCode() => HashCode.Combine(Id);
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#nullable enable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
@@ -12,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;
|
||||
|
||||
@@ -28,11 +33,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
public Book()
|
||||
{
|
||||
this.RunTimeTicks = TimeSpan.TicksPerSecond;
|
||||
}
|
||||
|
||||
public string FindSeriesSortName()
|
||||
{
|
||||
return SeriesName;
|
||||
|
||||
@@ -29,30 +29,45 @@ namespace MediaBrowser.Controller.Entities
|
||||
public class CollectionFolder : Folder, ICollectionFolder
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
public static IXmlSerializer XmlSerializer { get; set; }
|
||||
|
||||
public static IServerApplicationHost ApplicationHost { get; set; }
|
||||
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>();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
@@ -106,12 +121,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;
|
||||
@@ -120,9 +135,9 @@ 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.Deserialize<LibraryOptions>(JsonSerializer.SerializeToUtf8Bytes(options, _jsonOptions), _jsonOptions);
|
||||
foreach (var mediaPath in clone.PathInfos)
|
||||
@@ -139,15 +154,18 @@ 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.
|
||||
/// 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;
|
||||
@@ -155,21 +173,20 @@ namespace MediaBrowser.Controller.Entities
|
||||
[JsonIgnore]
|
||||
public override string[] PhysicalLocations => PhysicalLocationsList;
|
||||
|
||||
public string[] PhysicalLocationsList { get; set; }
|
||||
|
||||
public Guid[] PhysicalFolderIds { get; set; }
|
||||
|
||||
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;
|
||||
@@ -201,9 +218,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;
|
||||
}
|
||||
@@ -298,27 +315,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);
|
||||
|
||||
@@ -37,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>
|
||||
@@ -50,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;
|
||||
|
||||
@@ -86,6 +86,85 @@ 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 override bool CanDelete()
|
||||
{
|
||||
if (IsRoot)
|
||||
@@ -108,20 +187,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)
|
||||
@@ -137,16 +202,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>
|
||||
/// <exception cref="InvalidOperationException">Unable to add + item.Name.</exception>
|
||||
public void AddChild(BaseItem item, CancellationToken cancellationToken)
|
||||
{
|
||||
item.SetParent(this);
|
||||
@@ -169,20 +230,6 @@ 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))
|
||||
@@ -226,20 +273,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()
|
||||
@@ -279,13 +326,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)
|
||||
{
|
||||
@@ -294,7 +341,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
|
||||
{
|
||||
@@ -305,7 +352,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();
|
||||
|
||||
@@ -527,7 +574,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
private Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
return RunTasks(
|
||||
(folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService),
|
||||
(folder, innerProgress) => folder.ValidateChildrenInternal(innerProgress, true, false, null, directoryService, cancellationToken),
|
||||
children,
|
||||
progress,
|
||||
cancellationToken);
|
||||
@@ -940,7 +987,13 @@ 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);
|
||||
@@ -965,7 +1018,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))
|
||||
@@ -1276,10 +1329,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;
|
||||
|
||||
@@ -1428,8 +1494,6 @@ namespace MediaBrowser.Controller.Entities
|
||||
return list;
|
||||
}
|
||||
|
||||
protected virtual bool FilterLinkedChildrenPerUser => false;
|
||||
|
||||
public bool ContainsLinkedChildByItemId(Guid itemId)
|
||||
{
|
||||
var linkedChildren = LinkedChildren;
|
||||
@@ -1530,9 +1594,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;
|
||||
@@ -1553,7 +1614,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)
|
||||
@@ -1696,51 +1758,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)
|
||||
|
||||
@@ -16,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();
|
||||
@@ -34,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;
|
||||
@@ -72,9 +75,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);
|
||||
@@ -108,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))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface IHasScreenshots.
|
||||
/// The item has screenshots.
|
||||
/// </summary>
|
||||
public interface IHasScreenshots
|
||||
{
|
||||
|
||||
@@ -9,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; }
|
||||
|
||||
11
MediaBrowser.Controller/Entities/IHasShares.cs
Normal file
11
MediaBrowser.Controller/Entities/IHasShares.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHasShares
|
||||
{
|
||||
Share[] Shares { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
@@ -20,9 +18,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
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; }
|
||||
|
||||
@@ -58,23 +56,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; }
|
||||
|
||||
@@ -82,7 +80,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; }
|
||||
|
||||
@@ -182,13 +180,13 @@ 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
|
||||
public BaseItem? Parent
|
||||
{
|
||||
set
|
||||
{
|
||||
@@ -213,9 +211,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; }
|
||||
|
||||
@@ -223,9 +221,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; }
|
||||
|
||||
@@ -235,7 +233,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; }
|
||||
|
||||
@@ -253,13 +251,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; }
|
||||
|
||||
@@ -267,6 +265,11 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
public bool? IsDeadPerson { get; set; }
|
||||
|
||||
/// <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()
|
||||
{
|
||||
AlbumArtistIds = Array.Empty<Guid>();
|
||||
@@ -283,12 +286,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
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>();
|
||||
@@ -309,32 +310,33 @@ namespace MediaBrowser.Controller.Entities
|
||||
Years = Array.Empty<int>();
|
||||
}
|
||||
|
||||
public InternalItemsQuery(User user)
|
||||
public InternalItemsQuery(User? user)
|
||||
: this()
|
||||
{
|
||||
SetUser(user);
|
||||
if (user != null)
|
||||
{
|
||||
SetUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUser(User user)
|
||||
{
|
||||
if (user != null)
|
||||
MaxParentalRating = user.MaxParentalAgeRating;
|
||||
|
||||
if (MaxParentalRating.HasValue)
|
||||
{
|
||||
MaxParentalRating = user.MaxParentalAgeRating;
|
||||
|
||||
if (MaxParentalRating.HasValue)
|
||||
{
|
||||
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
|
||||
.Where(i => i != UnratedItem.Other.ToString())
|
||||
.Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
|
||||
}
|
||||
|
||||
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
|
||||
|
||||
User = user;
|
||||
string other = UnratedItem.Other.ToString();
|
||||
BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
|
||||
.Where(i => i != other)
|
||||
.Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
|
||||
}
|
||||
|
||||
ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
|
||||
|
||||
User = user;
|
||||
}
|
||||
|
||||
public Dictionary<string, string> HasAnyProviderId { get; set; }
|
||||
public Dictionary<string, string>? HasAnyProviderId { get; set; }
|
||||
|
||||
public Guid[] AlbumArtistIds { get; set; }
|
||||
|
||||
@@ -356,8 +358,8 @@ 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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,24 @@
|
||||
#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>
|
||||
@@ -16,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; }
|
||||
|
||||
@@ -29,11 +41,5 @@ namespace MediaBrowser.Controller.Entities
|
||||
public User User { get; set; }
|
||||
|
||||
public bool? IsFavorite { get; set; }
|
||||
|
||||
public InternalPeopleQuery()
|
||||
{
|
||||
PersonTypes = Array.Empty<string>();
|
||||
ExcludePersonTypes = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
#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; }
|
||||
@@ -22,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; }
|
||||
|
||||
@@ -41,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
35
MediaBrowser.Controller/Entities/LinkedChildComparer.cs
Normal file
35
MediaBrowser.Controller/Entities/LinkedChildComparer.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
MediaBrowser.Controller/Entities/LinkedChildType.cs
Normal file
18
MediaBrowser.Controller/Entities/LinkedChildType.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -144,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)
|
||||
{
|
||||
|
||||
@@ -13,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;
|
||||
@@ -36,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)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
@@ -67,6 +67,9 @@ namespace MediaBrowser.Controller.Entities
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to enable alpha numeric sorting.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public override bool EnableAlphaNumericSorting => false;
|
||||
|
||||
@@ -126,9 +129,9 @@ 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)
|
||||
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))
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public interface IHasShares
|
||||
{
|
||||
Share[] Shares { get; set; }
|
||||
}
|
||||
|
||||
public class Share
|
||||
{
|
||||
public string UserId { get; set; }
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
@@ -105,9 +105,9 @@ 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)
|
||||
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))
|
||||
|
||||
@@ -34,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; }
|
||||
@@ -44,7 +44,7 @@ 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; }
|
||||
@@ -116,7 +116,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Episode's Series Instance.
|
||||
/// Gets the Episode's Series Instance.
|
||||
/// </summary>
|
||||
/// <value>The series.</value>
|
||||
[JsonIgnore]
|
||||
@@ -218,8 +218,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>
|
||||
@@ -261,6 +261,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeasonId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid SeriesId { get; set; }
|
||||
|
||||
@@ -286,7 +287,8 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
|
||||
public override IEnumerable<FileSystemMetadata> GetDeletePaths()
|
||||
{
|
||||
return new[] {
|
||||
return new[]
|
||||
{
|
||||
new FileSystemMetadata
|
||||
{
|
||||
FullName = Path,
|
||||
@@ -318,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)
|
||||
{
|
||||
@@ -328,7 +330,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
{
|
||||
try
|
||||
{
|
||||
if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetdata))
|
||||
if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetadata))
|
||||
{
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This Episode's Series Instance.
|
||||
/// Gets this Episode's Series Instance.
|
||||
/// </summary>
|
||||
/// <value>The series.</value>
|
||||
[JsonIgnore]
|
||||
@@ -122,7 +122,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,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)
|
||||
@@ -242,9 +242,9 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
|
||||
/// </summary>
|
||||
/// <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))
|
||||
{
|
||||
|
||||
@@ -59,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>
|
||||
|
||||
@@ -45,9 +45,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)
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
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>
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
private List<Guid> _childrenIds = null;
|
||||
private readonly object _childIdsLock = new object();
|
||||
|
||||
protected override List<BaseItem> LoadChildren()
|
||||
{
|
||||
lock (_childIdsLock)
|
||||
@@ -87,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))
|
||||
{
|
||||
@@ -108,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();
|
||||
|
||||
@@ -15,13 +15,19 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
public class UserView : Folder, IHasCollectionType
|
||||
{
|
||||
/// <inheritdoc />
|
||||
/// <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;
|
||||
@@ -110,10 +116,10 @@ namespace MediaBrowser.Controller.Entities
|
||||
return GetChildren(user, false);
|
||||
}
|
||||
|
||||
private static string[] UserSpecificViewTypes = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Playlists
|
||||
};
|
||||
private static readonly string[] UserSpecificViewTypes = new string[]
|
||||
{
|
||||
Model.Entities.CollectionType.Playlists
|
||||
};
|
||||
|
||||
public static bool IsUserSpecific(Folder folder)
|
||||
{
|
||||
@@ -166,7 +172,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -55,12 +55,12 @@ 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)
|
||||
{
|
||||
@@ -344,12 +344,14 @@ 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;
|
||||
}
|
||||
|
||||
@@ -482,7 +482,8 @@ namespace MediaBrowser.Controller.Entities
|
||||
{
|
||||
if (!IsInMixedFolder)
|
||||
{
|
||||
return new[] {
|
||||
return new[]
|
||||
{
|
||||
new FileSystemMetadata
|
||||
{
|
||||
FullName = ContainingFolderPath,
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// Gets the folder containing the item.
|
||||
/// If the item is a folder, it returns the folder itself.
|
||||
/// </summary>
|
||||
/// <value>The containing folder path.</value>
|
||||
@@ -112,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))
|
||||
|
||||
@@ -21,6 +21,27 @@ namespace MediaBrowser.Controller.Extensions
|
||||
return Normalize(string.Concat(chars), NormalizationForm.FormC);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Counts the number of occurrences of [needle] in the string.
|
||||
/// </summary>
|
||||
/// <param name="value">The haystack to search in.</param>
|
||||
/// <param name="needle">The character to search for.</param>
|
||||
/// <returns>The number of occurrences of the [needle] character.</returns>
|
||||
public static int Count(this ReadOnlySpan<char> value, char needle)
|
||||
{
|
||||
var count = 0;
|
||||
var length = value.Length;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
if (value[i] == needle)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static string Normalize(string text, NormalizationForm form, bool stripStringOnFailure = true)
|
||||
{
|
||||
if (stripStringOnFailure)
|
||||
@@ -33,7 +54,7 @@ namespace MediaBrowser.Controller.Extensions
|
||||
{
|
||||
// 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])", "");
|
||||
text = Regex.Replace(text, "([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])", string.Empty);
|
||||
return Normalize(text, form, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.IO
|
||||
/// <param name="flattenFolderDepth">The flatten folder depth.</param>
|
||||
/// <param name="resolveShortcuts">if set to <c>true</c> [resolve shortcuts].</param>
|
||||
/// <returns>Dictionary{System.StringFileSystemInfo}.</returns>
|
||||
/// <exception cref="ArgumentNullException">path</exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="path" /> is <c>null</c> or empty.</exception>
|
||||
public static FileSystemMetadata[] GetFilteredFileSystemEntries(
|
||||
IDirectoryService directoryService,
|
||||
string path,
|
||||
|
||||
@@ -4,13 +4,13 @@ namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
public class DeleteOptions
|
||||
{
|
||||
public bool DeleteFileLocation { get; set; }
|
||||
|
||||
public bool DeleteFromExternalProvider { get; set; }
|
||||
|
||||
public DeleteOptions()
|
||||
{
|
||||
DeleteFromExternalProvider = true;
|
||||
}
|
||||
|
||||
public bool DeleteFileLocation { get; set; }
|
||||
|
||||
public bool DeleteFromExternalProvider { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
public interface IIntroProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the intros.
|
||||
/// </summary>
|
||||
@@ -24,11 +30,5 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
IEnumerable<string> GetAllIntroFiles();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
/// <value>The name.</value>
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Naming.Common;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
@@ -43,6 +44,12 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Resolves a set of files into a list of BaseItem.
|
||||
/// </summary>
|
||||
/// <param name="files">The list of tiles.</param>
|
||||
/// <param name="directoryService">Instance of the <see cref="IDirectoryService"/> interface.</param>
|
||||
/// <param name="parent">The parent folder.</param>
|
||||
/// <param name="libraryOptions">The library options.</param>
|
||||
/// <param name="collectionType">The collection type.</param>
|
||||
/// <returns>The items resolved from the paths.</returns>
|
||||
IEnumerable<BaseItem> ResolvePaths(
|
||||
IEnumerable<FileSystemMetadata> files,
|
||||
IDirectoryService directoryService,
|
||||
@@ -346,6 +353,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <param name="uniqueId">The unique identifier.</param>
|
||||
/// <returns>The named view.</returns>
|
||||
UserView GetNamedView(
|
||||
string name,
|
||||
Guid parentId,
|
||||
@@ -359,10 +367,11 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="parent">The parent.</param>
|
||||
/// <param name="viewType">Type of the view.</param>
|
||||
/// <param name="sortName">Name of the sort.</param>
|
||||
/// <returns>The shadow view.</returns>
|
||||
UserView GetShadowView(
|
||||
BaseItem parent,
|
||||
string viewType,
|
||||
string sortName);
|
||||
string viewType,
|
||||
string sortName);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether [is video file] [the specified path].
|
||||
@@ -587,5 +596,11 @@ namespace MediaBrowser.Controller.Library
|
||||
BaseItem GetParentItem(string parentId, Guid? userId);
|
||||
|
||||
BaseItem GetParentItem(Guid? parentId, Guid? userId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or creates a static instance of <see cref="NamingOptions"/>.
|
||||
/// </summary>
|
||||
/// <returns>An instance of the <see cref="NamingOptions"/> class.</returns>
|
||||
NamingOptions GetNamingOptions();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,17 +49,16 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Get all user data for the given user.
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <returns>The user item data.</returns>
|
||||
List<UserItemData> GetAllUserData(Guid userId);
|
||||
|
||||
/// <summary>
|
||||
/// Save the all provided user data for the given user.
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="userData"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="userData">The array of user data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void SaveAllUserData(Guid userId, UserItemData[] userData, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -61,16 +61,16 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <param name="user">The user.</param>
|
||||
/// <param name="newName">The new name.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">user</exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="ArgumentNullException">If user is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">If the provided user doesn't exist.</exception>
|
||||
Task RenameUser(User user, string newName);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <exception cref="ArgumentNullException">user</exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="ArgumentNullException">If user is <c>null</c>.</exception>
|
||||
/// <exception cref="ArgumentException">If the provided user doesn't exist.</exception>
|
||||
void UpdateUser(User user);
|
||||
|
||||
/// <summary>
|
||||
@@ -87,8 +87,8 @@ namespace MediaBrowser.Controller.Library
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the new user.</param>
|
||||
/// <returns>The created user.</returns>
|
||||
/// <exception cref="ArgumentNullException">name</exception>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="name"/> is <c>null</c> or empty.</exception>
|
||||
/// <exception cref="ArgumentException"><paramref name="name"/> already exists.</exception>
|
||||
Task<User> CreateUserAsync(string name);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Library
|
||||
public IDirectoryService DirectoryService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file system children.
|
||||
/// Gets or sets the file system children.
|
||||
/// </summary>
|
||||
/// <value>The file system children.</value>
|
||||
public FileSystemMetadata[] FileSystemChildren { get; set; }
|
||||
@@ -242,14 +242,14 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Path.GetHashCode();
|
||||
return Path.GetHashCode(StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Equals the specified args.
|
||||
/// </summary>
|
||||
/// <param name="args">The args.</param>
|
||||
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
|
||||
/// <returns><c>true</c> if the arguments are the same, <c>false</c> otherwise.</returns>
|
||||
protected bool Equals(ItemResolveArgs args)
|
||||
{
|
||||
if (args != null)
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Controller.Library
|
||||
{
|
||||
/// <summary>
|
||||
/// Class Profiler.
|
||||
/// </summary>
|
||||
public class Profiler : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The name.
|
||||
/// </summary>
|
||||
readonly string _name;
|
||||
|
||||
/// <summary>
|
||||
/// The stopwatch.
|
||||
/// </summary>
|
||||
readonly Stopwatch _stopwatch;
|
||||
|
||||
/// <summary>
|
||||
/// The _logger.
|
||||
/// </summary>
|
||||
private readonly ILogger<Profiler> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Profiler" /> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
public Profiler(string name, ILogger<Profiler> logger)
|
||||
{
|
||||
this._name = name;
|
||||
|
||||
_logger = logger;
|
||||
|
||||
_stopwatch = new Stopwatch();
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases unmanaged and - optionally - managed resources.
|
||||
/// </summary>
|
||||
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
|
||||
protected virtual void Dispose(bool dispose)
|
||||
{
|
||||
if (dispose)
|
||||
{
|
||||
_stopwatch.Stop();
|
||||
string message;
|
||||
if (_stopwatch.ElapsedMilliseconds > 300000)
|
||||
{
|
||||
message = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0} took {1} minutes.",
|
||||
_name,
|
||||
((float)_stopwatch.ElapsedMilliseconds / 60000).ToString("F", CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
message = string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
"{0} took {1} seconds.",
|
||||
_name,
|
||||
((float)_stopwatch.ElapsedMilliseconds / 1000).ToString("#0.000", CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
_logger.LogInformation(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs
Normal file
19
MediaBrowser.Controller/LiveTv/ActiveRecordingInfo.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System.Threading;
|
||||
|
||||
namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class ActiveRecordingInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public TimerInfo Timer { get; set; }
|
||||
|
||||
public CancellationTokenSource CancellationTokenSource { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string Number { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get or sets the Id.
|
||||
/// Gets or sets the Id.
|
||||
/// </summary>
|
||||
/// <value>The id of the channel.</value>
|
||||
public string Id { get; set; }
|
||||
@@ -54,13 +54,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string ChannelGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image path if it can be accessed directly from the file system.
|
||||
/// Gets or sets the the image path if it can be accessed directly from the file system.
|
||||
/// </summary>
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded.
|
||||
/// Gets or sets the image url if it can be downloaded.
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
|
||||
@@ -268,16 +268,21 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user);
|
||||
|
||||
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);
|
||||
|
||||
Task<List<ChannelInfo>> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken);
|
||||
|
||||
IListingsProvider[] ListingProviders { get; }
|
||||
|
||||
List<NameIdPair> GetTunerHostTypes();
|
||||
|
||||
Task<List<TunerHostInfo>> DiscoverTuners(bool newDevicesOnly, CancellationToken cancellationToken);
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCancelled;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> TimerCreated;
|
||||
|
||||
event EventHandler<GenericEventArgs<TimerEventInfo>> SeriesTimerCreated;
|
||||
|
||||
string GetEmbyTvActiveRecordingPath(string id);
|
||||
@@ -288,15 +293,4 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
|
||||
List<BaseItem> GetRecordingFolders(User user);
|
||||
}
|
||||
|
||||
public class ActiveRecordingInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public TimerInfo Timer { get; set; }
|
||||
|
||||
public CancellationTokenSource CancellationTokenSource { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public bool IsNews { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is kids.
|
||||
/// Gets a value indicating whether this instance is kids.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
}
|
||||
|
||||
private static string EmbyServiceName = "Emby";
|
||||
|
||||
public override double GetDefaultPrimaryImageAspectRatio()
|
||||
{
|
||||
var serviceName = ServiceName;
|
||||
@@ -71,7 +72,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public override SourceType SourceType => SourceType.LiveTV;
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
/// Gets or sets start date of the program, in UTC.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public DateTime StartDate { get; set; }
|
||||
@@ -101,7 +102,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public bool IsMovie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is sports.
|
||||
/// Gets a value indicating whether this instance is sports.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
@@ -115,49 +116,49 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is live.
|
||||
/// Gets a value indicating whether this instance is live.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is news.
|
||||
/// Gets a value indicating whether this instance is news.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is kids.
|
||||
/// Gets a value indicating whether this instance is kids.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is premiere.
|
||||
/// Gets a value indicating whether this instance is premiere.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the folder containing the item.
|
||||
/// 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]
|
||||
// [JsonIgnore]
|
||||
// public override string MediaType
|
||||
//{
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return ChannelType == ChannelType.TV ? Model.Entities.MediaType.Video : Model.Entities.MediaType.Audio;
|
||||
// }
|
||||
//}
|
||||
// }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsAiring
|
||||
|
||||
@@ -10,8 +10,16 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class ProgramInfo
|
||||
{
|
||||
public ProgramInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
|
||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the program.
|
||||
/// Gets or sets the id of the program.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
@@ -22,7 +30,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the program.
|
||||
/// Gets or sets the name of the program.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -45,17 +53,17 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string ShortOverview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the program, in UTC.
|
||||
/// Gets or sets the start date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the program, in UTC.
|
||||
/// Gets or sets the end date of the program, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// Gets or sets the genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
@@ -71,6 +79,9 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// <value><c>true</c> if this instance is hd; otherwise, <c>false</c>.</value>
|
||||
public bool? IsHD { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is 3d.
|
||||
/// </summary>
|
||||
public bool? Is3D { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -100,13 +111,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string EpisodeTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image path if it can be accessed directly from the file system.
|
||||
/// Gets or sets the image path if it can be accessed directly from the file system.
|
||||
/// </summary>
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded.
|
||||
/// Gets or sets the image url if it can be downloaded.
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
@@ -212,13 +223,5 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public Dictionary<string, string> ProviderIds { get; set; }
|
||||
|
||||
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
||||
|
||||
public ProgramInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
|
||||
ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class RecordingInfo
|
||||
{
|
||||
public RecordingInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// Gets or sets the id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
@@ -28,7 +33,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string TimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// Gets or sets the channelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
@@ -39,7 +44,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public ChannelType ChannelType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// Gets or sets the name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -62,12 +67,12 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// Gets or sets the start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// Gets or sets the end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
@@ -84,7 +89,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public RecordingStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Genre of the program.
|
||||
/// Gets or sets the genre of the program.
|
||||
/// </summary>
|
||||
public List<string> Genres { get; set; }
|
||||
|
||||
@@ -173,13 +178,13 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public float? CommunityRating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image path if it can be accessed directly from the file system.
|
||||
/// Gets or sets the image path if it can be accessed directly from the file system.
|
||||
/// </summary>
|
||||
/// <value>The image path.</value>
|
||||
public string ImagePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Supply the image url if it can be downloaded.
|
||||
/// Gets or sets the image url if it can be downloaded.
|
||||
/// </summary>
|
||||
/// <value>The image URL.</value>
|
||||
public string ImageUrl { get; set; }
|
||||
@@ -201,10 +206,5 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <value>The date last updated.</value>
|
||||
public DateTime DateLastUpdated { get; set; }
|
||||
|
||||
public RecordingInfo()
|
||||
{
|
||||
Genres = new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,20 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
{
|
||||
public class SeriesTimerInfo
|
||||
{
|
||||
public SeriesTimerInfo()
|
||||
{
|
||||
Days = new List<DayOfWeek>();
|
||||
SkipEpisodesInLibrary = true;
|
||||
KeepUntil = KeepUntil.UntilDeleted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// Gets or sets the id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// Gets or sets the channelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
@@ -27,24 +34,27 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string ProgramId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// Gets or sets the name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the service name.
|
||||
/// </summary>
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// Gets or sets the description of the recording.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// Gets or sets the start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// Gets or sets the end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
@@ -113,12 +123,5 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
/// </summary>
|
||||
/// <value>The series identifier.</value>
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
public SeriesTimerInfo()
|
||||
{
|
||||
Days = new List<DayOfWeek>();
|
||||
SkipEpisodesInLibrary = true;
|
||||
KeepUntil = KeepUntil.UntilDeleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#nullable disable
|
||||
|
||||
#nullable enable
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
@@ -28,18 +28,17 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string[] Tags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the recording.
|
||||
/// Gets or sets the id of the recording.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the series timer identifier.
|
||||
/// </summary>
|
||||
/// <value>The series timer identifier.</value>
|
||||
public string SeriesTimerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ChannelId of the recording.
|
||||
/// Gets or sets the channelId of the recording.
|
||||
/// </summary>
|
||||
public string ChannelId { get; set; }
|
||||
|
||||
@@ -52,24 +51,24 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public string ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the recording.
|
||||
/// Gets or sets the name of the recording.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of the recording.
|
||||
/// Gets or sets the description of the recording.
|
||||
/// </summary>
|
||||
public string Overview { get; set; }
|
||||
|
||||
public string SeriesId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The start date of the recording, in UTC.
|
||||
/// Gets or sets the start date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The end date of the recording, in UTC.
|
||||
/// Gets or sets the end date of the recording, in UTC.
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
@@ -133,7 +132,7 @@ namespace MediaBrowser.Controller.LiveTv
|
||||
public bool IsSeries { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether this instance is live.
|
||||
/// Gets a value indicating whether this instance is live.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
|
||||
[JsonIgnore]
|
||||
|
||||
@@ -16,13 +16,14 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MediaBrowser.Model\MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="..\MediaBrowser.Common\MediaBrowser.Common.csproj" />
|
||||
<ProjectReference Include="../Emby.Naming/Emby.Naming.csproj" />
|
||||
<ProjectReference Include="../MediaBrowser.Model/MediaBrowser.Model.csproj" />
|
||||
<ProjectReference Include="../MediaBrowser.Common/MediaBrowser.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,63 +1,13 @@
|
||||
#nullable disable
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
public class EncodingJobOptions : BaseEncodingJobOptions
|
||||
{
|
||||
public string OutputDirectory { get; set; }
|
||||
|
||||
public string ItemId { get; set; }
|
||||
|
||||
public string TempDirectory { get; set; }
|
||||
|
||||
public bool ReadInputAtNativeFramerate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance has fixed resolution.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if this instance has fixed resolution; otherwise, <c>false</c>.</value>
|
||||
public bool HasFixedResolution => Width.HasValue || Height.HasValue;
|
||||
|
||||
public DeviceProfile DeviceProfile { get; set; }
|
||||
|
||||
public EncodingJobOptions(StreamInfo info, DeviceProfile deviceProfile)
|
||||
{
|
||||
Container = info.Container;
|
||||
StartTimeTicks = info.StartPositionTicks;
|
||||
MaxWidth = info.MaxWidth;
|
||||
MaxHeight = info.MaxHeight;
|
||||
MaxFramerate = info.MaxFramerate;
|
||||
Id = info.ItemId;
|
||||
MediaSourceId = info.MediaSourceId;
|
||||
AudioCodec = info.TargetAudioCodec.FirstOrDefault();
|
||||
MaxAudioChannels = info.GlobalMaxAudioChannels;
|
||||
AudioBitRate = info.AudioBitrate;
|
||||
AudioSampleRate = info.TargetAudioSampleRate;
|
||||
DeviceProfile = deviceProfile;
|
||||
VideoCodec = info.TargetVideoCodec.FirstOrDefault();
|
||||
VideoBitRate = info.VideoBitrate;
|
||||
AudioStreamIndex = info.AudioStreamIndex;
|
||||
SubtitleMethod = info.SubtitleDeliveryMethod;
|
||||
Context = info.Context;
|
||||
TranscodingMaxAudioChannels = info.TranscodingMaxAudioChannels;
|
||||
|
||||
if (info.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External)
|
||||
{
|
||||
SubtitleStreamIndex = info.SubtitleStreamIndex;
|
||||
}
|
||||
|
||||
StreamOptions = info.StreamOptions;
|
||||
}
|
||||
}
|
||||
|
||||
// For now until api and media encoding layers are unified
|
||||
public class BaseEncodingJobOptions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -251,4 +201,4 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
StreamOptions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,7 +596,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
|
||||
&& isNvdecDecoder)
|
||||
{
|
||||
arg.Append("-hwaccel_output_format cuda -autorotate 0 ");
|
||||
// Fix for 'No decoder surfaces left' error. https://trac.ffmpeg.org/ticket/7562
|
||||
arg.Append("-hwaccel_output_format cuda -extra_hw_frames 3 -autorotate 0 ");
|
||||
}
|
||||
|
||||
if (state.IsVideoRequest
|
||||
@@ -1070,7 +1071,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc)
|
||||
|| string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc)
|
||||
{
|
||||
// following preset will be deprecated in ffmpeg 4.4, use p1~p7 instead.
|
||||
switch (encodingOptions.EncoderPreset)
|
||||
{
|
||||
case "veryslow":
|
||||
@@ -1166,7 +1166,9 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
profileScore = Math.Min(profileScore, 2);
|
||||
|
||||
// http://www.webmproject.org/docs/encoder-parameters/
|
||||
param += string.Format(CultureInfo.InvariantCulture, " -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
|
||||
param += string.Format(
|
||||
CultureInfo.InvariantCulture,
|
||||
" -speed 16 -quality good -profile:v {0} -slices 8 -crf {1} -qmin {2} -qmax {3}",
|
||||
profileScore.ToString(_usCulture),
|
||||
crf,
|
||||
qmin,
|
||||
@@ -1251,7 +1253,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
|
||||
&& profile.Contains("constrainedbaseline", StringComparison.OrdinalIgnoreCase))
|
||||
&& profile.Contains("baseline", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
profile = "constrained_baseline";
|
||||
}
|
||||
@@ -1296,7 +1298,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
// hevc_qsv use -level 51 instead of -level 153.
|
||||
if (double.TryParse(level, NumberStyles.Any, _usCulture, out double hevcLevel))
|
||||
{
|
||||
param += " -level " + hevcLevel / 3;
|
||||
param += " -level " + (hevcLevel / 3);
|
||||
}
|
||||
}
|
||||
else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
|
||||
@@ -1392,7 +1394,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var requestedProfile = requestedProfiles[0];
|
||||
// strip spaces because they may be stripped out on the query string as well
|
||||
if (!string.IsNullOrEmpty(videoStream.Profile)
|
||||
&& !requestedProfiles.Contains(videoStream.Profile.Replace(" ", "", StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase))
|
||||
&& !requestedProfiles.Contains(videoStream.Profile.Replace(" ", string.Empty, StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
var currentScore = GetVideoProfileScore(videoStream.Profile);
|
||||
var requestedScore = GetVideoProfileScore(requestedProfile);
|
||||
@@ -1801,7 +1803,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
if (isTranscodingAudio
|
||||
&& state.TranscodingType != TranscodingJobType.Progressive
|
||||
&& resultChannels.HasValue
|
||||
&& (resultChannels.Value > 2 && resultChannels.Value < 6 || resultChannels.Value == 7))
|
||||
&& ((resultChannels.Value > 2 && resultChannels.Value < 6) || resultChannels.Value == 7))
|
||||
{
|
||||
resultChannels = 2;
|
||||
}
|
||||
@@ -2129,8 +2131,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return (null, null);
|
||||
}
|
||||
|
||||
decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth);
|
||||
decimal inputHeight = Convert.ToDecimal(videoHeight ?? requestedHeight);
|
||||
decimal inputWidth = Convert.ToDecimal(videoWidth ?? requestedWidth, CultureInfo.InvariantCulture);
|
||||
decimal inputHeight = Convert.ToDecimal(videoHeight ?? requestedHeight, CultureInfo.InvariantCulture);
|
||||
decimal outputWidth = requestedWidth.HasValue ? Convert.ToDecimal(requestedWidth.Value) : inputWidth;
|
||||
decimal outputHeight = requestedHeight.HasValue ? Convert.ToDecimal(requestedHeight.Value) : inputHeight;
|
||||
decimal maximumWidth = requestedMaxWidth.HasValue ? Convert.ToDecimal(requestedMaxWidth.Value) : outputWidth;
|
||||
@@ -2197,12 +2199,11 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
var isQsvHevcEncoder = videoEncoder.Contains("hevc_qsv", StringComparison.OrdinalIgnoreCase);
|
||||
var isTonemappingSupported = IsTonemappingSupported(state, options);
|
||||
var isVppTonemappingSupported = IsVppTonemappingSupported(state, options);
|
||||
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase)&& isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
||||
var isTonemappingSupportedOnVaapi = string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isVaapiH264Encoder || isVaapiHevcEncoder);
|
||||
var isTonemappingSupportedOnQsv = string.Equals(options.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase) && isVaapiDecoder && (isQsvH264Encoder || isQsvHevcEncoder);
|
||||
var isP010PixFmtRequired = (isTonemappingSupportedOnVaapi && (isTonemappingSupported || isVppTonemappingSupported))
|
||||
|| (isTonemappingSupportedOnQsv && isVppTonemappingSupported);
|
||||
|
||||
|
||||
var outputPixFmt = "format=nv12";
|
||||
if (isP010PixFmtRequired)
|
||||
{
|
||||
@@ -2933,6 +2934,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
return threads;
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
public void TryStreamCopy(EncodingJobInfo state)
|
||||
{
|
||||
@@ -3174,8 +3176,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
state.ReadInputAtNativeFramerate = mediaSource.ReadAtNativeFramerate;
|
||||
|
||||
if (state.ReadInputAtNativeFramerate
|
||||
|| mediaSource.Protocol == MediaProtocol.File
|
||||
&& string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase))
|
||||
|| (mediaSource.Protocol == MediaProtocol.File
|
||||
&& string.Equals(mediaSource.Container, "wtv", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
state.InputVideoSync = "-1";
|
||||
state.InputAudioSync = "1";
|
||||
@@ -3548,7 +3550,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hw decoder name
|
||||
/// Gets a hw decoder name.
|
||||
/// </summary>
|
||||
public string GetHwDecoderName(EncodingOptions options, string decoder, string videoCodec, bool isColorDepth10)
|
||||
{
|
||||
@@ -3566,7 +3568,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system
|
||||
/// Gets a hwaccel type to use as a hardware decoder(dxva/vaapi) depending on the system.
|
||||
/// </summary>
|
||||
public string GetHwaccelType(EncodingJobInfo state, EncodingOptions options, string videoCodec, bool isColorDepth10)
|
||||
{
|
||||
@@ -3692,7 +3694,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
if (flags.Count > 0)
|
||||
{
|
||||
return " -fflags " + string.Join("", flags);
|
||||
return " -fflags " + string.Join(string.Empty, flags);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
private TranscodeReason[] _transcodeReasons = null;
|
||||
|
||||
public TranscodeReason[] TranscodeReasons
|
||||
{
|
||||
get
|
||||
@@ -274,6 +275,16 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
|
||||
public int? GetRequestedAudioChannels(string codec)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiochannels");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseRequest.MaxAudioChannels.HasValue)
|
||||
{
|
||||
return BaseRequest.MaxAudioChannels;
|
||||
@@ -289,16 +300,6 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
return BaseRequest.TranscodingMaxAudioChannels;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(codec))
|
||||
{
|
||||
var value = BaseRequest.GetOption(codec, "audiochannels");
|
||||
if (!string.IsNullOrEmpty(value)
|
||||
&& int.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -430,7 +431,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predicts the audio sample rate that will be in the output stream.
|
||||
/// Gets the target video level.
|
||||
/// </summary>
|
||||
public double? TargetVideoLevel
|
||||
{
|
||||
@@ -453,7 +454,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predicts the audio sample rate that will be in the output stream.
|
||||
/// Gets the target video bit depth.
|
||||
/// </summary>
|
||||
public int? TargetVideoBitDepth
|
||||
{
|
||||
@@ -488,7 +489,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predicts the audio sample rate that will be in the output stream.
|
||||
/// Gets the target framerate.
|
||||
/// </summary>
|
||||
public float? TargetFramerate
|
||||
{
|
||||
@@ -520,7 +521,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predicts the audio sample rate that will be in the output stream.
|
||||
/// Gets the target packet length.
|
||||
/// </summary>
|
||||
public int? TargetPacketLength
|
||||
{
|
||||
@@ -536,7 +537,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Predicts the audio sample rate that will be in the output stream.
|
||||
/// Gets the target video profile.
|
||||
/// </summary>
|
||||
public string TargetVideoProfile
|
||||
{
|
||||
@@ -700,25 +701,4 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
Progress.Report(percentComplete.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enum TranscodingJobType.
|
||||
/// </summary>
|
||||
public enum TranscodingJobType
|
||||
{
|
||||
/// <summary>
|
||||
/// The progressive.
|
||||
/// </summary>
|
||||
Progressive,
|
||||
|
||||
/// <summary>
|
||||
/// The HLS.
|
||||
/// </summary>
|
||||
Hls,
|
||||
|
||||
/// <summary>
|
||||
/// The dash.
|
||||
/// </summary>
|
||||
Dash
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
||||
public interface IMediaEncoder : ITranscoderSupport
|
||||
{
|
||||
/// <summary>
|
||||
/// The location of the discovered FFmpeg tool.
|
||||
/// Gets location of the discovered FFmpeg tool.
|
||||
/// </summary>
|
||||
FFmpegLocation EncoderLocation { get; }
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
|
||||
23
MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs
Normal file
23
MediaBrowser.Controller/MediaEncoding/TranscodingJobType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
/// <summary>
|
||||
/// Enum TranscodingJobType.
|
||||
/// </summary>
|
||||
public enum TranscodingJobType
|
||||
{
|
||||
/// <summary>
|
||||
/// The progressive.
|
||||
/// </summary>
|
||||
Progressive,
|
||||
|
||||
/// <summary>
|
||||
/// The HLS.
|
||||
/// </summary>
|
||||
Hls,
|
||||
|
||||
/// <summary>
|
||||
/// The dash.
|
||||
/// </summary>
|
||||
Dash
|
||||
}
|
||||
}
|
||||
@@ -270,13 +270,4 @@ namespace MediaBrowser.Controller.Net
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public class WebSocketListenerState
|
||||
{
|
||||
public DateTime DateLastSendUtc { get; set; }
|
||||
|
||||
public long InitialDelayMs { get; set; }
|
||||
|
||||
public long IntervalMs { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
SessionInfo GetSession(object requestContext);
|
||||
|
||||
User GetUser(object requestContext);
|
||||
User? GetUser(object requestContext);
|
||||
|
||||
SessionInfo GetSession(HttpContext requestContext);
|
||||
|
||||
User GetUser(HttpContext requestContext);
|
||||
User? GetUser(HttpContext requestContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
@@ -34,7 +30,7 @@ namespace MediaBrowser.Controller.Net
|
||||
DateTime LastKeepAliveDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the query string.
|
||||
/// Gets the query string.
|
||||
/// </summary>
|
||||
/// <value>The query string.</value>
|
||||
IQueryCollection QueryString { get; }
|
||||
@@ -60,11 +56,11 @@ namespace MediaBrowser.Controller.Net
|
||||
/// <summary>
|
||||
/// Sends a message asynchronously.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <typeparam name="T">The type of websocket message data.</typeparam>
|
||||
/// <param name="message">The message.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
/// <exception cref="ArgumentNullException">message</exception>
|
||||
/// <exception cref="ArgumentNullException">The message is null.</exception>
|
||||
Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken);
|
||||
|
||||
Task ProcessAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
17
MediaBrowser.Controller/Net/WebSocketListenerState.cs
Normal file
17
MediaBrowser.Controller/Net/WebSocketListenerState.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
||||
namespace MediaBrowser.Controller.Net
|
||||
{
|
||||
public class WebSocketListenerState
|
||||
{
|
||||
public DateTime DateLastSendUtc { get; set; }
|
||||
|
||||
public long InitialDelayMs { get; set; }
|
||||
|
||||
public long IntervalMs { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -49,21 +49,23 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <summary>
|
||||
/// Gets chapters for an item.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="id">The item.</param>
|
||||
/// <returns>The list of chapter info.</returns>
|
||||
List<ChapterInfo> GetChapters(BaseItem id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single chapter for an item.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="id">The item.</param>
|
||||
/// <param name="index">The chapter index.</param>
|
||||
/// <returns>The chapter info at the specified index.</returns>
|
||||
ChapterInfo GetChapter(BaseItem id, int index);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the chapters.
|
||||
/// </summary>
|
||||
/// <param name="id">The item id.</param>
|
||||
/// <param name="chapters">The list of chapters to save.</param>
|
||||
void SaveChapters(Guid id, IReadOnlyList<ChapterInfo> chapters);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,17 +40,16 @@ namespace MediaBrowser.Controller.Persistence
|
||||
/// <summary>
|
||||
/// Return all user data associated with the given user.
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <returns>The list of user item data.</returns>
|
||||
List<UserItemData> GetAllUserData(long userId);
|
||||
|
||||
/// <summary>
|
||||
/// Save all user data associated with the given user.
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="userData"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="userId">The user id.</param>
|
||||
/// <param name="userData">The user item data.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
void SaveAllUserData(long userId, UserItemData[] userData, CancellationToken cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ namespace MediaBrowser.Controller.Playlists
|
||||
{
|
||||
public class Playlist : Folder, IHasShares
|
||||
{
|
||||
public static string[] SupportedExtensions =
|
||||
{
|
||||
".m3u",
|
||||
".m3u8",
|
||||
".pls",
|
||||
".wpl",
|
||||
".zpl"
|
||||
};
|
||||
public static readonly IReadOnlyList<string> SupportedExtensions = new[]
|
||||
{
|
||||
".m3u",
|
||||
".m3u8",
|
||||
".pls",
|
||||
".wpl",
|
||||
".zpl"
|
||||
};
|
||||
|
||||
public Guid OwnerUserId { get; set; }
|
||||
|
||||
@@ -101,7 +101,7 @@ namespace MediaBrowser.Controller.Playlists
|
||||
return new List<BaseItem>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
9
MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs
Normal file
9
MediaBrowser.Controller/Plugins/IRunBeforeStartup.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace MediaBrowser.Controller.Plugins
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="IServerEntryPoint"/> should be invoked as a pre-startup task.
|
||||
/// </summary>
|
||||
public interface IRunBeforeStartup
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,7 @@ namespace MediaBrowser.Controller.Plugins
|
||||
/// <summary>
|
||||
/// Run the initialization for this module. This method is invoked at application start.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task RunAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that a <see cref="IServerEntryPoint"/> should be invoked as a pre-startup task.
|
||||
/// </summary>
|
||||
public interface IRunBeforeStartup
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,13 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public class AlbumInfo : ItemLookupInfo
|
||||
{
|
||||
public AlbumInfo()
|
||||
{
|
||||
ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SongInfos = new List<SongInfo>();
|
||||
AlbumArtists = Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the album artist.
|
||||
/// </summary>
|
||||
@@ -20,12 +27,5 @@ namespace MediaBrowser.Controller.Providers
|
||||
public Dictionary<string, string> ArtistProviderIds { get; set; }
|
||||
|
||||
public List<SongInfo> SongInfos { get; set; }
|
||||
|
||||
public AlbumInfo()
|
||||
{
|
||||
ArtistProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
SongInfos = new List<SongInfo>();
|
||||
AlbumArtists = Array.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public class ArtistInfo : ItemLookupInfo
|
||||
{
|
||||
public List<SongInfo> SongInfos { get; set; }
|
||||
|
||||
public ArtistInfo()
|
||||
{
|
||||
SongInfos = new List<SongInfo>();
|
||||
}
|
||||
|
||||
public List<SongInfo> SongInfos { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,16 @@ namespace MediaBrowser.Controller.Providers
|
||||
|
||||
public FileSystemMetadata[] GetFileSystemEntries(string path)
|
||||
{
|
||||
return _cache.GetOrAdd(path, p => _fileSystem.GetFileSystemEntries(p).ToArray());
|
||||
return _cache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
|
||||
}
|
||||
|
||||
public List<FileSystemMetadata> GetFiles(string path)
|
||||
{
|
||||
var list = new List<FileSystemMetadata>();
|
||||
var items = GetFileSystemEntries(path);
|
||||
foreach (var item in items)
|
||||
for (var i = 0; i < items.Length; i++)
|
||||
{
|
||||
var item = items[i];
|
||||
if (!item.IsDirectory)
|
||||
{
|
||||
list.Add(item);
|
||||
@@ -48,10 +49,9 @@ namespace MediaBrowser.Controller.Providers
|
||||
if (!_fileCache.TryGetValue(path, out var result))
|
||||
{
|
||||
var file = _fileSystem.GetFileInfo(path);
|
||||
var res = file != null && file.Exists ? file : null;
|
||||
if (res != null)
|
||||
if (file.Exists)
|
||||
{
|
||||
result = res;
|
||||
result = file;
|
||||
_fileCache.TryAdd(path, result);
|
||||
}
|
||||
}
|
||||
@@ -62,14 +62,21 @@ namespace MediaBrowser.Controller.Providers
|
||||
public IReadOnlyList<string> GetFilePaths(string path)
|
||||
=> GetFilePaths(path, false);
|
||||
|
||||
public IReadOnlyList<string> GetFilePaths(string path, bool clearCache)
|
||||
public IReadOnlyList<string> GetFilePaths(string path, bool clearCache, bool sort = false)
|
||||
{
|
||||
if (clearCache)
|
||||
{
|
||||
_filePathCache.TryRemove(path, out _);
|
||||
}
|
||||
|
||||
return _filePathCache.GetOrAdd(path, p => _fileSystem.GetFilePaths(p).ToList());
|
||||
var filePaths = _filePathCache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFilePaths(p).ToList(), _fileSystem);
|
||||
|
||||
if (sort)
|
||||
{
|
||||
filePaths.Sort();
|
||||
}
|
||||
|
||||
return filePaths;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,11 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public class EpisodeInfo : ItemLookupInfo
|
||||
{
|
||||
public EpisodeInfo()
|
||||
{
|
||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public Dictionary<string, string> SeriesProviderIds { get; set; }
|
||||
|
||||
public int? IndexNumberEnd { get; set; }
|
||||
@@ -16,10 +21,5 @@ namespace MediaBrowser.Controller.Providers
|
||||
public bool IsMissingEpisode { get; set; }
|
||||
|
||||
public string SeriesDisplayOrder { get; set; }
|
||||
|
||||
public EpisodeInfo()
|
||||
{
|
||||
SeriesProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ namespace MediaBrowser.Controller.Providers
|
||||
|
||||
IReadOnlyList<string> GetFilePaths(string path);
|
||||
|
||||
IReadOnlyList<string> GetFilePaths(string path, bool clearCache);
|
||||
IReadOnlyList<string> GetFilePaths(string path, bool clearCache, bool sort = false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,12 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
public interface IMetadataService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
int Order { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can refresh the specified item.
|
||||
/// </summary>
|
||||
@@ -27,11 +33,5 @@ namespace MediaBrowser.Controller.Providers
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>Task.</returns>
|
||||
Task<ItemUpdateType> RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the order.
|
||||
/// </summary>
|
||||
/// <value>The order.</value>
|
||||
int Order { get; }
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user