aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller/Entities')
-rw-r--r--MediaBrowser.Controller/Entities/AggregateFolder.cs43
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs55
-rw-r--r--MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs52
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs66
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicGenre.cs39
-rw-r--r--MediaBrowser.Controller/Entities/AudioBook.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs1430
-rw-r--r--MediaBrowser.Controller/Entities/BaseItemExtensions.cs7
-rw-r--r--MediaBrowser.Controller/Entities/BasePluginFolder.cs12
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs45
-rw-r--r--MediaBrowser.Controller/Entities/Extensions.cs4
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs56
-rw-r--r--MediaBrowser.Controller/Entities/Genre.cs12
-rw-r--r--MediaBrowser.Controller/Entities/ICollectionFolder.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasMediaSources.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasScreenshots.cs9
-rw-r--r--MediaBrowser.Controller/Entities/IHasShares.cs2
-rw-r--r--MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs4
-rw-r--r--MediaBrowser.Controller/Entities/IHasTrailers.cs67
-rw-r--r--MediaBrowser.Controller/Entities/InternalItemsQuery.cs164
-rw-r--r--MediaBrowser.Controller/Entities/Movies/BoxSet.cs62
-rw-r--r--MediaBrowser.Controller/Entities/Movies/Movie.cs71
-rw-r--r--MediaBrowser.Controller/Entities/Person.cs44
-rw-r--r--MediaBrowser.Controller/Entities/PersonInfo.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Photo.cs48
-rw-r--r--MediaBrowser.Controller/Entities/Studio.cs36
-rw-r--r--MediaBrowser.Controller/Entities/TV/Episode.cs150
-rw-r--r--MediaBrowser.Controller/Entities/TV/Season.cs92
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs38
-rw-r--r--MediaBrowser.Controller/Entities/TagExtensions.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Trailer.cs8
-rw-r--r--MediaBrowser.Controller/Entities/UserItemData.cs14
-rw-r--r--MediaBrowser.Controller/Entities/UserRootFolder.cs46
-rw-r--r--MediaBrowser.Controller/Entities/UserView.cs88
-rw-r--r--MediaBrowser.Controller/Entities/UserViewBuilder.cs102
-rw-r--r--MediaBrowser.Controller/Entities/Video.cs268
-rw-r--r--MediaBrowser.Controller/Entities/Year.cs38
38 files changed, 1345 insertions, 1840 deletions
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs
index fe1bc62ab..9589f5245 100644
--- a/MediaBrowser.Controller/Entities/AggregateFolder.cs
+++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1819, CS1591
using System;
using System.Collections.Concurrent;
@@ -18,33 +18,24 @@ namespace MediaBrowser.Controller.Entities
{
/// <summary>
/// Specialized folder that can have items added to it's children by external entities.
- /// Used for our RootFolder so plug-ins can add items.
+ /// Used for our RootFolder so plugins can add items.
/// </summary>
public class AggregateFolder : Folder
{
+ private readonly object _childIdsLock = new object();
+
+ /// <summary>
+ /// The _virtual children.
+ /// </summary>
+ private readonly ConcurrentBag<BaseItem> _virtualChildren = new ConcurrentBag<BaseItem>();
private bool _requiresRefresh;
+ private Guid[] _childrenIds = null;
public AggregateFolder()
{
PhysicalLocationsList = Array.Empty<string>();
}
- [JsonIgnore]
- public override bool IsPhysicalRoot => true;
-
- public override bool CanDelete()
- {
- return false;
- }
-
- [JsonIgnore]
- public override bool SupportsPlayedStatus => false;
-
- /// <summary>
- /// The _virtual children.
- /// </summary>
- private readonly ConcurrentBag<BaseItem> _virtualChildren = new ConcurrentBag<BaseItem>();
-
/// <summary>
/// Gets the virtual children.
/// </summary>
@@ -52,18 +43,26 @@ namespace MediaBrowser.Controller.Entities
public ConcurrentBag<BaseItem> VirtualChildren => _virtualChildren;
[JsonIgnore]
+ public override bool IsPhysicalRoot => true;
+
+ [JsonIgnore]
+ public override bool SupportsPlayedStatus => false;
+
+ [JsonIgnore]
public override string[] PhysicalLocations => PhysicalLocationsList;
public string[] PhysicalLocationsList { get; set; }
+ public override bool CanDelete()
+ {
+ return false;
+ }
+
protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
{
return CreateResolveArgs(directoryService, true).FileSystemChildren;
}
- private Guid[] _childrenIds = null;
- private readonly object _childIdsLock = new object();
-
protected override List<BaseItem> LoadChildren()
{
lock (_childIdsLock)
@@ -169,7 +168,7 @@ namespace MediaBrowser.Controller.Entities
/// Adds the virtual child.
/// </summary>
/// <param name="child">The child.</param>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException">Throws if child is null.</exception>
public void AddVirtualChild(BaseItem child)
{
if (child == null)
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 576ab67a2..9d0187c8c 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1002, CA1724, CA1826, CS1591
using System;
using System.Collections.Generic;
@@ -8,10 +8,8 @@ using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities.Audio
{
@@ -25,6 +23,12 @@ namespace MediaBrowser.Controller.Entities.Audio
IHasLookupInfo<SongInfo>,
IHasMediaSources
{
+ public Audio()
+ {
+ Artists = Array.Empty<string>();
+ AlbumArtists = Array.Empty<string>();
+ }
+
/// <inheritdoc />
[JsonIgnore]
public IReadOnlyList<string> Artists { get; set; }
@@ -33,22 +37,11 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public IReadOnlyList<string> AlbumArtists { get; set; }
- public Audio()
- {
- Artists = Array.Empty<string>();
- AlbumArtists = Array.Empty<string>();
- }
-
- public override double GetDefaultPrimaryImageAspectRatio()
- {
- return 1;
- }
-
[JsonIgnore]
public override bool SupportsPlayedStatus => true;
[JsonIgnore]
- public override bool SupportsPeople => false;
+ public override bool SupportsPeople => true;
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
@@ -62,11 +55,6 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override Folder LatestItemsIndexContainer => AlbumEntity;
- public override bool CanDownload()
- {
- return IsFileProtocol;
- }
-
[JsonIgnore]
public MusicAlbum AlbumEntity => FindParent<MusicAlbum>();
@@ -77,6 +65,16 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override string MediaType => Model.Entities.MediaType.Audio;
+ public override double GetDefaultPrimaryImageAspectRatio()
+ {
+ return 1;
+ }
+
+ public override bool CanDownload()
+ {
+ return IsFileProtocol;
+ }
+
/// <summary>
/// Creates the name of the sort.
/// </summary>
@@ -126,15 +124,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return base.GetBlockUnratedType();
}
- public List<MediaStream> GetMediaStreams(MediaStreamType type)
- {
- return MediaSourceManager.GetMediaStreams(new MediaStreamQuery
- {
- ItemId = Id,
- Type = type
- });
- }
-
public SongInfo GetLookupInfo()
{
var info = GetItemLookupInfo<SongInfo>();
@@ -146,11 +135,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return info;
}
- protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
- {
- var list = new List<Tuple<BaseItem, MediaSourceType>>();
- list.Add(new Tuple<BaseItem, MediaSourceType>(this, MediaSourceType.Default));
- return list;
- }
+ protected override IEnumerable<(BaseItem, MediaSourceType)> GetAllItemsForMediaSources()
+ => new[] { ((BaseItem)this, MediaSourceType.Default) };
}
}
diff --git a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
index db60c3071..c2dae5a2d 100644
--- a/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
+++ b/MediaBrowser.Controller/Entities/Audio/IHasMusicGenres.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1819, CS1591
namespace MediaBrowser.Controller.Entities.Audio
{
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index 610bce4f5..03d1f3304 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1721, CA1826, CS1591
using System;
using System.Collections.Generic;
@@ -23,18 +23,18 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>, IMetadataContainer
{
- /// <inheritdoc />
- public IReadOnlyList<string> AlbumArtists { get; set; }
-
- /// <inheritdoc />
- public IReadOnlyList<string> Artists { get; set; }
-
public MusicAlbum()
{
Artists = Array.Empty<string>();
AlbumArtists = Array.Empty<string>();
}
+ /// <inheritdoc />
+ public IReadOnlyList<string> AlbumArtists { get; set; }
+
+ /// <inheritdoc />
+ public IReadOnlyList<string> Artists { get; set; }
+
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
@@ -44,6 +44,25 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public MusicArtist MusicArtist => GetMusicArtist(new DtoOptions(true));
+ [JsonIgnore]
+ public override bool SupportsPlayedStatus => false;
+
+ [JsonIgnore]
+ public override bool SupportsCumulativeRunTimeTicks => true;
+
+ [JsonIgnore]
+ public string AlbumArtist => AlbumArtists.FirstOrDefault();
+
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ /// <summary>
+ /// Gets the tracks.
+ /// </summary>
+ /// <value>The tracks.</value>
+ [JsonIgnore]
+ public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
+
public MusicArtist GetMusicArtist(DtoOptions options)
{
var parents = GetParents();
@@ -64,25 +83,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return null;
}
- [JsonIgnore]
- public override bool SupportsPlayedStatus => false;
-
- [JsonIgnore]
- public override bool SupportsCumulativeRunTimeTicks => true;
-
- [JsonIgnore]
- public string AlbumArtist => AlbumArtists.FirstOrDefault();
-
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
- /// <summary>
- /// Gets the tracks.
- /// </summary>
- /// <value>The tracks.</value>
- [JsonIgnore]
- public IEnumerable<Audio> Tracks => GetRecursiveChildren(i => i is Audio).Cast<Audio>();
-
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
{
return Tracks;
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index c0cd81110..11b95b94b 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -8,9 +8,9 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -44,6 +44,36 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override bool SupportsPlayedStatus => false;
+ /// <summary>
+ /// Gets the folder containing the item.
+ /// If the item is a folder, it returns the folder itself.
+ /// </summary>
+ /// <value>The containing folder path.</value>
+ [JsonIgnore]
+ public override string ContainingFolderPath => Path;
+
+ [JsonIgnore]
+ public override IEnumerable<BaseItem> Children
+ {
+ get
+ {
+ if (IsAccessedByName)
+ {
+ return new List<BaseItem>();
+ }
+
+ return base.Children;
+ }
+ }
+
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ public static string GetPath(string name)
+ {
+ return GetPath(name, true);
+ }
+
public override double GetDefaultPrimaryImageAspectRatio()
{
return 1;
@@ -58,27 +88,13 @@ namespace MediaBrowser.Controller.Entities.Audio
{
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Audio), nameof(MusicVideo), nameof(MusicAlbum) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Audio, BaseItemKind.MusicVideo, BaseItemKind.MusicAlbum };
query.ArtistIds = new[] { Id };
}
return LibraryManager.GetItemList(query);
}
- [JsonIgnore]
- public override IEnumerable<BaseItem> Children
- {
- get
- {
- if (IsAccessedByName)
- {
- return new List<BaseItem>();
- }
-
- return base.Children;
- }
- }
-
public override int GetChildCount(User user)
{
return IsAccessedByName ? 0 : base.GetChildCount(user);
@@ -114,14 +130,6 @@ namespace MediaBrowser.Controller.Entities.Audio
}
/// <summary>
- /// Gets the folder containing the item.
- /// If the item is a folder, it returns the folder itself.
- /// </summary>
- /// <value>The containing folder path.</value>
- [JsonIgnore]
- public override string ContainingFolderPath => Path;
-
- /// <summary>
/// Gets the user data key.
/// </summary>
/// <param name="item">The item.</param>
@@ -167,14 +175,6 @@ namespace MediaBrowser.Controller.Entities.Audio
return info;
}
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
- public static string GetPath(string name)
- {
- return GetPath(name, true);
- }
-
public static string GetPath(string name, bool normalizeName)
{
// Trim the period at the end because windows will have a hard time with that
@@ -208,6 +208,8 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
+ /// <param name="replaceAllMetadata">Option to replace metadata.</param>
+ /// <returns>True if metadata changed.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
index a682a2e58..73a25232e 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs
@@ -5,7 +5,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
+using Jellyfin.Data.Enums;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.Audio
@@ -15,19 +16,6 @@ namespace MediaBrowser.Controller.Entities.Audio
/// </summary>
public class MusicGenre : BaseItem, IItemByName
{
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
-
- list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
- return list;
- }
-
- public override string CreatePresentationUniqueKey()
- {
- return GetUserDataKeys()[0];
- }
-
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
@@ -45,6 +33,22 @@ namespace MediaBrowser.Controller.Entities.Audio
[JsonIgnore]
public override string ContainingFolderPath => Path;
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
+ return list;
+ }
+
+ public override string CreatePresentationUniqueKey()
+ {
+ return GetUserDataKeys()[0];
+ }
+
public override double GetDefaultPrimaryImageAspectRatio()
{
return 1;
@@ -60,13 +64,10 @@ namespace MediaBrowser.Controller.Entities.Audio
return true;
}
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
query.GenreIds = new[] { Id };
- query.IncludeItemTypes = new[] { nameof(MusicVideo), nameof(Audio), nameof(MusicAlbum), nameof(MusicArtist) };
+ query.IncludeItemTypes = new[] { BaseItemKind.MusicVideo, BaseItemKind.Audio, BaseItemKind.MusicAlbum, BaseItemKind.MusicArtist };
return LibraryManager.GetItemList(query);
}
@@ -106,6 +107,8 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
+ /// <param name="replaceAllMetadata">Option to replace metadata.</param>
+ /// <returns>True if metadata changed.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
diff --git a/MediaBrowser.Controller/Entities/AudioBook.cs b/MediaBrowser.Controller/Entities/AudioBook.cs
index 405284622..782481fbc 100644
--- a/MediaBrowser.Controller/Entities/AudioBook.cs
+++ b/MediaBrowser.Controller/Entities/AudioBook.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1724, CS1591
using System;
using System.Text.Json.Serialization;
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 6137ddbf7..3ef2e5192 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1,27 +1,26 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CS1591, SA1401
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Diacritics.Extensions;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Extensions;
+using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
@@ -39,6 +38,10 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo>, IEquatable<BaseItem>
{
+ private BaseItemKind? _baseItemKind;
+
+ public const string ThemeSongFileName = "theme";
+
/// <summary>
/// The supported image extensions.
/// </summary>
@@ -60,6 +63,28 @@ namespace MediaBrowser.Controller.Entities
".ttml"
};
+ /// <summary>
+ /// Extra types that should be counted and displayed as "Special Features" in the UI.
+ /// </summary>
+ public static readonly IReadOnlyCollection<ExtraType> DisplayExtraTypes = new HashSet<ExtraType>
+ {
+ Model.Entities.ExtraType.Unknown,
+ Model.Entities.ExtraType.BehindTheScenes,
+ Model.Entities.ExtraType.Clip,
+ Model.Entities.ExtraType.DeletedScene,
+ Model.Entities.ExtraType.Interview,
+ Model.Entities.ExtraType.Sample,
+ Model.Entities.ExtraType.Scene
+ };
+
+ private string _sortName;
+
+ private string _forcedSortName;
+
+ private string _name;
+
+ public const char SlugChar = '-';
+
protected BaseItem()
{
Tags = Array.Empty<string>();
@@ -73,71 +98,6 @@ namespace MediaBrowser.Controller.Entities
ExtraIds = Array.Empty<Guid>();
}
- public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
- public static char SlugChar = '-';
-
- /// <summary>
- /// The trailer folder name.
- /// </summary>
- public const string TrailerFolderName = "trailers";
- public const string ThemeSongsFolderName = "theme-music";
- public const string ThemeSongFilename = "theme";
- public const string ThemeVideosFolderName = "backdrops";
- public const string ExtrasFolderName = "extras";
- public const string BehindTheScenesFolderName = "behind the scenes";
- public const string DeletedScenesFolderName = "deleted scenes";
- public const string InterviewFolderName = "interviews";
- public const string SceneFolderName = "scenes";
- public const string SampleFolderName = "samples";
- public const string ShortsFolderName = "shorts";
- public const string FeaturettesFolderName = "featurettes";
-
- public static readonly string[] AllExtrasTypesFolderNames =
- {
- ExtrasFolderName,
- BehindTheScenesFolderName,
- DeletedScenesFolderName,
- InterviewFolderName,
- SceneFolderName,
- SampleFolderName,
- ShortsFolderName,
- FeaturettesFolderName
- };
-
- [JsonIgnore]
- public Guid[] ThemeSongIds
- {
- get
- {
- return _themeSongIds ??= GetExtras()
- .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeSong)
- .Select(song => song.Id)
- .ToArray();
- }
-
- private set
- {
- _themeSongIds = value;
- }
- }
-
- [JsonIgnore]
- public Guid[] ThemeVideoIds
- {
- get
- {
- return _themeVideoIds ??= GetExtras()
- .Where(extra => extra.ExtraType == Model.Entities.ExtraType.ThemeVideo)
- .Select(song => song.Id)
- .ToArray();
- }
-
- private set
- {
- _themeVideoIds = value;
- }
- }
-
[JsonIgnore]
public string PreferredMetadataCountryCode { get; set; }
@@ -193,8 +153,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public virtual bool SupportsRemoteImageDownloading => true;
- private string _name;
-
/// <summary>
/// Gets or sets the name.
/// </summary>
@@ -317,22 +275,9 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public string ExternalSeriesId { get; set; }
- /// <summary>
- /// Gets or sets the etag.
- /// </summary>
- /// <value>The etag.</value>
- [JsonIgnore]
- public string ExternalEtag { get; set; }
-
[JsonIgnore]
public virtual bool IsHidden => false;
- public BaseItem GetOwner()
- {
- var ownerId = OwnerId;
- return ownerId.Equals(Guid.Empty) ? null : LibraryManager.GetItemById(ownerId);
- }
-
/// <summary>
/// Gets the type of the location.
/// </summary>
@@ -342,11 +287,6 @@ namespace MediaBrowser.Controller.Entities
{
get
{
- // if (IsOffline)
- // {
- // return LocationType.Offline;
- // }
-
var path = Path;
if (string.IsNullOrEmpty(path))
{
@@ -378,15 +318,8 @@ namespace MediaBrowser.Controller.Entities
}
}
- public bool IsPathProtocol(MediaProtocol protocol)
- {
- var current = PathProtocol;
-
- return current.HasValue && current.Value == protocol;
- }
-
[JsonIgnore]
- public bool IsFileProtocol => IsPathProtocol(MediaProtocol.File);
+ public bool IsFileProtocol => PathProtocol == MediaProtocol.File;
[JsonIgnore]
public bool HasPathProtocol => PathProtocol.HasValue;
@@ -422,35 +355,17 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public virtual bool EnableAlphaNumericSorting => true;
- private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
- {
- var list = new List<Tuple<StringBuilder, bool>>();
-
- int thisMarker = 0;
-
- while (thisMarker < s1.Length)
- {
- char thisCh = s1[thisMarker];
+ public virtual bool IsHD => Height >= 720;
- var thisChunk = new StringBuilder();
- bool isNumeric = char.IsDigit(thisCh);
+ public bool IsShortcut { get; set; }
- while (thisMarker < s1.Length && char.IsDigit(thisCh) == isNumeric)
- {
- thisChunk.Append(thisCh);
- thisMarker++;
+ public string ShortcutPath { get; set; }
- if (thisMarker < s1.Length)
- {
- thisCh = s1[thisMarker];
- }
- }
+ public int Width { get; set; }
- list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric));
- }
+ public int Height { get; set; }
- return list;
- }
+ public Guid[] ExtraIds { get; set; }
/// <summary>
/// Gets the primary image path.
@@ -462,72 +377,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public string PrimaryImagePath => this.GetImagePath(ImageType.Primary);
- public virtual bool CanDelete()
- {
- if (SourceType == SourceType.Channel)
- {
- return ChannelManager.CanDelete(this);
- }
-
- return IsFileProtocol;
- }
-
- public virtual bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
- {
- if (user.HasPermission(PermissionKind.EnableContentDeletion))
- {
- return true;
- }
-
- var allowed = user.GetPreferenceValues<Guid>(PreferenceKind.EnableContentDeletionFromFolders);
-
- if (SourceType == SourceType.Channel)
- {
- return allowed.Contains(ChannelId);
- }
- else
- {
- var collectionFolders = LibraryManager.GetCollectionFolders(this, allCollectionFolders);
-
- foreach (var folder in collectionFolders)
- {
- if (allowed.Contains(folder.Id))
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public bool CanDelete(User user, List<Folder> allCollectionFolders)
- {
- return CanDelete() && IsAuthorizedToDelete(user, allCollectionFolders);
- }
-
- public bool CanDelete(User user)
- {
- var allCollectionFolders = LibraryManager.GetUserRootFolder().Children.OfType<Folder>().ToList();
-
- return CanDelete(user, allCollectionFolders);
- }
-
- public virtual bool CanDownload()
- {
- return false;
- }
-
- public virtual bool IsAuthorizedToDownload(User user)
- {
- return user.HasPermission(PermissionKind.EnableContentDownloading);
- }
-
- public bool CanDownload(User user)
- {
- return CanDownload() && IsAuthorizedToDownload(user);
- }
-
/// <summary>
/// Gets or sets the date created.
/// </summary>
@@ -547,38 +396,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public DateTime DateLastRefreshed { get; set; }
- /// <summary>
- /// Gets or sets the logger.
- /// </summary>
- public static ILogger<BaseItem> Logger { get; set; }
-
- public static ILibraryManager LibraryManager { get; set; }
-
- public static IServerConfigurationManager ConfigurationManager { get; set; }
-
- public static IProviderManager ProviderManager { get; set; }
-
- public static ILocalizationManager LocalizationManager { get; set; }
-
- public static IItemRepository ItemRepository { get; set; }
-
- public static IFileSystem FileSystem { get; set; }
-
- public static IUserDataManager UserDataManager { get; set; }
-
- public static IChannelManager ChannelManager { get; set; }
-
- public static IMediaSourceManager MediaSourceManager { get; set; }
-
- /// <summary>
- /// Returns a <see cref="string" /> that represents this instance.
- /// </summary>
- /// <returns>A <see cref="string" /> that represents this instance.</returns>
- public override string ToString()
- {
- return Name;
- }
-
[JsonIgnore]
public bool IsLocked { get; set; }
@@ -610,7 +427,45 @@ namespace MediaBrowser.Controller.Entities
}
}
- private string _forcedSortName;
+ [JsonIgnore]
+ public bool EnableMediaSourceDisplay
+ {
+ get
+ {
+ if (SourceType == SourceType.Channel)
+ {
+ return ChannelManager.EnableMediaSourceDisplay(this);
+ }
+
+ return true;
+ }
+ }
+
+ [JsonIgnore]
+ public Guid ParentId { get; set; }
+
+ /// <summary>
+ /// Gets or sets the logger.
+ /// </summary>
+ public static ILogger<BaseItem> Logger { get; set; }
+
+ public static ILibraryManager LibraryManager { get; set; }
+
+ public static IServerConfigurationManager ConfigurationManager { get; set; }
+
+ public static IProviderManager ProviderManager { get; set; }
+
+ public static ILocalizationManager LocalizationManager { get; set; }
+
+ public static IItemRepository ItemRepository { get; set; }
+
+ public static IFileSystem FileSystem { get; set; }
+
+ public static IUserDataManager UserDataManager { get; set; }
+
+ public static IChannelManager ChannelManager { get; set; }
+
+ public static IMediaSourceManager MediaSourceManager { get; set; }
/// <summary>
/// Gets or sets the name of the forced sort.
@@ -627,10 +482,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- private string _sortName;
- private Guid[] _themeSongIds;
- private Guid[] _themeVideoIds;
-
/// <summary>
/// Gets or sets the name of the sort.
/// </summary>
@@ -659,187 +510,8 @@ namespace MediaBrowser.Controller.Entities
set => _sortName = value;
}
- public string GetInternalMetadataPath()
- {
- var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
-
- return GetInternalMetadataPath(basePath);
- }
-
- protected virtual string GetInternalMetadataPath(string basePath)
- {
- if (SourceType == SourceType.Channel)
- {
- 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);
-
- return System.IO.Path.Join(basePath, "library", idString.Slice(0, 2), idString);
- }
-
- /// <summary>
- /// Creates the name of the sort.
- /// </summary>
- /// <returns>System.String.</returns>
- protected virtual string CreateSortName()
- {
- if (Name == null)
- {
- return null; // some items may not have name filled in properly
- }
-
- if (!EnableAlphaNumericSorting)
- {
- return Name.TrimStart();
- }
-
- var sortable = Name.Trim().ToLowerInvariant();
-
- foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
- {
- sortable = sortable.Replace(removeChar, string.Empty, StringComparison.Ordinal);
- }
-
- foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters)
- {
- sortable = sortable.Replace(replaceChar, " ", StringComparison.Ordinal);
- }
-
- foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
- {
- // Remove from beginning if a space follows
- if (sortable.StartsWith(search + " ", StringComparison.Ordinal))
- {
- sortable = sortable.Remove(0, search.Length + 1);
- }
-
- // Remove from middle if surrounded by spaces
- sortable = sortable.Replace(" " + search + " ", " ", StringComparison.Ordinal);
-
- // Remove from end if followed by a space
- if (sortable.EndsWith(" " + search, StringComparison.Ordinal))
- {
- sortable = sortable.Remove(sortable.Length - (search.Length + 1));
- }
- }
-
- return ModifySortChunks(sortable);
- }
-
- private string ModifySortChunks(string name)
- {
- var chunks = GetSortChunks(name);
-
- var builder = new StringBuilder();
-
- foreach (var chunk in chunks)
- {
- var chunkBuilder = chunk.Item1;
-
- // This chunk is numeric
- if (chunk.Item2)
- {
- while (chunkBuilder.Length < 10)
- {
- chunkBuilder.Insert(0, '0');
- }
- }
-
- builder.Append(chunkBuilder);
- }
-
- // logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
- return builder.ToString().RemoveDiacritics();
- }
-
[JsonIgnore]
- public bool EnableMediaSourceDisplay
- {
- get
- {
- if (SourceType == SourceType.Channel)
- {
- return ChannelManager.EnableMediaSourceDisplay(this);
- }
-
- return true;
- }
- }
-
- [JsonIgnore]
- public Guid ParentId { get; set; }
-
- /// <summary>
- /// Gets or sets the parent.
- /// </summary>
- /// <value>The parent.</value>
- [JsonIgnore]
- public Folder Parent
- {
- get => GetParent() as Folder;
- set
- {
- }
- }
-
- public void SetParent(Folder parent)
- {
- ParentId = parent == null ? Guid.Empty : parent.Id;
- }
-
- public BaseItem GetParent()
- {
- var parentId = ParentId;
- if (!parentId.Equals(Guid.Empty))
- {
- return LibraryManager.GetItemById(parentId);
- }
-
- return null;
- }
-
- public IEnumerable<BaseItem> GetParents()
- {
- var parent = GetParent();
-
- while (parent != null)
- {
- yield return parent;
-
- parent = parent.GetParent();
- }
- }
-
- /// <summary>
- /// Finds a parent of a given type.
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <returns>``0.</returns>
- public T FindParent<T>()
- where T : Folder
- {
- foreach (var parent in GetParents())
- {
- var item = parent as T;
- if (item != null)
- {
- return item;
- }
- }
-
- return null;
- }
-
- [JsonIgnore]
- public virtual Guid DisplayParentId
- {
- get
- {
- var parentId = ParentId;
- return parentId;
- }
- }
+ public virtual Guid DisplayParentId => ParentId;
[JsonIgnore]
public BaseItem DisplayParent
@@ -1014,6 +686,342 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
+ /// Gets or sets the provider ids.
+ /// </summary>
+ /// <value>The provider ids.</value>
+ [JsonIgnore]
+ public Dictionary<string, string> ProviderIds { get; set; }
+
+ [JsonIgnore]
+ public virtual Folder LatestItemsIndexContainer => null;
+
+ [JsonIgnore]
+ public string PresentationUniqueKey { get; set; }
+
+ [JsonIgnore]
+ public virtual bool EnableRememberingTrackSelections => true;
+
+ [JsonIgnore]
+ public virtual bool IsTopParent
+ {
+ get
+ {
+ if (this is BasePluginFolder || this is Channel)
+ {
+ return true;
+ }
+
+ if (this is IHasCollectionType view)
+ {
+ if (string.Equals(view.CollectionType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ if (GetParent() is AggregateFolder)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ [JsonIgnore]
+ public virtual bool SupportsAncestors => true;
+
+ [JsonIgnore]
+ public virtual bool StopRefreshIfLocalMetadataFound => true;
+
+ [JsonIgnore]
+ protected virtual bool SupportsOwnedItems => !ParentId.Equals(Guid.Empty) && IsFileProtocol;
+
+ [JsonIgnore]
+ public virtual bool SupportsPeople => false;
+
+ [JsonIgnore]
+ public virtual bool SupportsThemeMedia => false;
+
+ [JsonIgnore]
+ public virtual bool SupportsInheritedParentImages => false;
+
+ /// <summary>
+ /// Gets a value indicating whether this instance is folder.
+ /// </summary>
+ /// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
+ [JsonIgnore]
+ public virtual bool IsFolder => false;
+
+ [JsonIgnore]
+ public virtual bool IsDisplayedAsFolder => false;
+
+ /// <summary>
+ /// Gets or sets the remote trailers.
+ /// </summary>
+ /// <value>The remote trailers.</value>
+ public IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
+
+ public virtual bool SupportsExternalTransfer => false;
+
+ public virtual double GetDefaultPrimaryImageAspectRatio()
+ {
+ return 0;
+ }
+
+ public virtual string CreatePresentationUniqueKey()
+ {
+ return Id.ToString("N", CultureInfo.InvariantCulture);
+ }
+
+ private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
+ {
+ var list = new List<Tuple<StringBuilder, bool>>();
+
+ int thisMarker = 0;
+
+ while (thisMarker < s1.Length)
+ {
+ char thisCh = s1[thisMarker];
+
+ var thisChunk = new StringBuilder();
+ bool isNumeric = char.IsDigit(thisCh);
+
+ while (thisMarker < s1.Length && char.IsDigit(thisCh) == isNumeric)
+ {
+ thisChunk.Append(thisCh);
+ thisMarker++;
+
+ if (thisMarker < s1.Length)
+ {
+ thisCh = s1[thisMarker];
+ }
+ }
+
+ list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric));
+ }
+
+ return list;
+ }
+
+ public virtual bool CanDelete()
+ {
+ if (SourceType == SourceType.Channel)
+ {
+ return ChannelManager.CanDelete(this);
+ }
+
+ return IsFileProtocol;
+ }
+
+ public virtual bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
+ {
+ if (user.HasPermission(PermissionKind.EnableContentDeletion))
+ {
+ return true;
+ }
+
+ var allowed = user.GetPreferenceValues<Guid>(PreferenceKind.EnableContentDeletionFromFolders);
+
+ if (SourceType == SourceType.Channel)
+ {
+ return allowed.Contains(ChannelId);
+ }
+ else
+ {
+ var collectionFolders = LibraryManager.GetCollectionFolders(this, allCollectionFolders);
+
+ foreach (var folder in collectionFolders)
+ {
+ if (allowed.Contains(folder.Id))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public BaseItem GetOwner()
+ {
+ var ownerId = OwnerId;
+ return ownerId.Equals(Guid.Empty) ? null : LibraryManager.GetItemById(ownerId);
+ }
+
+ public bool CanDelete(User user, List<Folder> allCollectionFolders)
+ {
+ return CanDelete() && IsAuthorizedToDelete(user, allCollectionFolders);
+ }
+
+ public bool CanDelete(User user)
+ {
+ var allCollectionFolders = LibraryManager.GetUserRootFolder().Children.OfType<Folder>().ToList();
+
+ return CanDelete(user, allCollectionFolders);
+ }
+
+ public virtual bool CanDownload()
+ {
+ return false;
+ }
+
+ public virtual bool IsAuthorizedToDownload(User user)
+ {
+ return user.HasPermission(PermissionKind.EnableContentDownloading);
+ }
+
+ public bool CanDownload(User user)
+ {
+ return CanDownload() && IsAuthorizedToDownload(user);
+ }
+
+ /// <summary>
+ /// Returns a <see cref="string" /> that represents this instance.
+ /// </summary>
+ /// <returns>A <see cref="string" /> that represents this instance.</returns>
+ public override string ToString()
+ {
+ return Name;
+ }
+
+ public string GetInternalMetadataPath()
+ {
+ var basePath = ConfigurationManager.ApplicationPaths.InternalMetadataPath;
+
+ return GetInternalMetadataPath(basePath);
+ }
+
+ protected virtual string GetInternalMetadataPath(string basePath)
+ {
+ if (SourceType == SourceType.Channel)
+ {
+ 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);
+
+ return System.IO.Path.Join(basePath, "library", idString[..2], idString);
+ }
+
+ /// <summary>
+ /// Creates the name of the sort.
+ /// </summary>
+ /// <returns>System.String.</returns>
+ protected virtual string CreateSortName()
+ {
+ if (Name == null)
+ {
+ return null; // some items may not have name filled in properly
+ }
+
+ if (!EnableAlphaNumericSorting)
+ {
+ return Name.TrimStart();
+ }
+
+ var sortable = Name.Trim().ToLowerInvariant();
+
+ foreach (var removeChar in ConfigurationManager.Configuration.SortRemoveCharacters)
+ {
+ sortable = sortable.Replace(removeChar, string.Empty, StringComparison.Ordinal);
+ }
+
+ foreach (var replaceChar in ConfigurationManager.Configuration.SortReplaceCharacters)
+ {
+ sortable = sortable.Replace(replaceChar, " ", StringComparison.Ordinal);
+ }
+
+ foreach (var search in ConfigurationManager.Configuration.SortRemoveWords)
+ {
+ // Remove from beginning if a space follows
+ if (sortable.StartsWith(search + " ", StringComparison.Ordinal))
+ {
+ sortable = sortable.Remove(0, search.Length + 1);
+ }
+
+ // Remove from middle if surrounded by spaces
+ sortable = sortable.Replace(" " + search + " ", " ", StringComparison.Ordinal);
+
+ // Remove from end if followed by a space
+ if (sortable.EndsWith(" " + search, StringComparison.Ordinal))
+ {
+ sortable = sortable.Remove(sortable.Length - (search.Length + 1));
+ }
+ }
+
+ return ModifySortChunks(sortable);
+ }
+
+ private string ModifySortChunks(string name)
+ {
+ var chunks = GetSortChunks(name);
+
+ var builder = new StringBuilder();
+
+ foreach (var chunk in chunks)
+ {
+ var chunkBuilder = chunk.Item1;
+
+ // This chunk is numeric
+ if (chunk.Item2)
+ {
+ while (chunkBuilder.Length < 10)
+ {
+ chunkBuilder.Insert(0, '0');
+ }
+ }
+
+ builder.Append(chunkBuilder);
+ }
+
+ // logger.LogDebug("ModifySortChunks Start: {0} End: {1}", name, builder.ToString());
+ return builder.ToString().RemoveDiacritics();
+ }
+
+ public BaseItem GetParent()
+ {
+ var parentId = ParentId;
+ if (!parentId.Equals(Guid.Empty))
+ {
+ return LibraryManager.GetItemById(parentId);
+ }
+
+ return null;
+ }
+
+ public IEnumerable<BaseItem> GetParents()
+ {
+ var parent = GetParent();
+
+ while (parent != null)
+ {
+ yield return parent;
+
+ parent = parent.GetParent();
+ }
+ }
+
+ /// <summary>
+ /// Finds a parent of a given type.
+ /// </summary>
+ /// <typeparam name="T">Type of parent.</typeparam>
+ /// <returns>``0.</returns>
+ public T FindParent<T>()
+ where T : Folder
+ {
+ foreach (var parent in GetParents())
+ {
+ if (parent is T item)
+ {
+ return item;
+ }
+ }
+
+ return null;
+ }
+
+ /// <summary>
/// Gets the play access.
/// </summary>
/// <param name="user">The user.</param>
@@ -1088,9 +1096,9 @@ namespace MediaBrowser.Controller.Entities
.ToList();
}
- protected virtual List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
+ protected virtual IEnumerable<(BaseItem, MediaSourceType)> GetAllItemsForMediaSources()
{
- return new List<Tuple<BaseItem, MediaSourceType>>();
+ return Enumerable.Empty<(BaseItem, MediaSourceType)>();
}
private MediaSourceInfo GetVersionInfo(bool enablePathSubstitution, BaseItem item, MediaSourceType type)
@@ -1208,8 +1216,7 @@ namespace MediaBrowser.Controller.Entities
terms.Add(item.Name);
}
- var video = item as Video;
- if (video != null)
+ if (item is Video video)
{
if (video.Video3DFormat.HasValue)
{
@@ -1244,114 +1251,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- return string.Join('/', terms.ToArray());
- }
-
- /// <summary>
- /// Loads the theme songs.
- /// </summary>
- /// <returns>List{Audio.Audio}.</returns>
- private static Audio.Audio[] LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => FileSystem.GetFiles(i.FullName))
- .ToList();
-
- // Support plex/xbmc convention
- files.AddRange(fileSystemChildren
- .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>()
- .Select(audio =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- var dbItem = LibraryManager.GetItemById(audio.Id) as Audio.Audio;
-
- if (dbItem != null)
- {
- audio = dbItem;
- }
- else
- {
- // item is new
- audio.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeSong;
- }
-
- return audio;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToArray();
- }
-
- /// <summary>
- /// Loads the video backdrops.
- /// </summary>
- /// <returns>List{Video}.</returns>
- private static Video[] LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var files = fileSystemChildren.Where(i => i.IsDirectory)
- .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
- .SelectMany(i => FileSystem.GetFiles(i.FullName));
-
- return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
- .OfType<Video>()
- .Select(item =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
-
- if (LibraryManager.GetItemById(item.Id) is Video dbItem)
- {
- item = dbItem;
- }
- else
- {
- // item is new
- item.ExtraType = Model.Entities.ExtraType.ThemeVideo;
- }
-
- return item;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path).ToArray();
- }
-
- protected virtual BaseItem[] LoadExtras(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
- {
- var extras = new List<Video>();
-
- 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));
-
- // 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 =>
- {
- // Try to retrieve it from the db. If we don't find it, use the resolved version
- if (LibraryManager.GetItemById(item.Id) is Video dbItem)
- {
- item = dbItem;
- }
-
- // Use some hackery to get the extra type based on foldername
- item.ExtraType = Enum.TryParse(extraFolderName.Replace(" ", string.Empty, StringComparison.Ordinal), true, out ExtraType extraType)
- ? extraType
- : Model.Entities.ExtraType.Unknown;
-
- return item;
-
- // Sort them so that the list can be easily compared for changes
- }).OrderBy(i => i.Path));
- }
-
- return extras.ToArray();
+ return string.Join('/', terms);
}
public Task RefreshMetadata(CancellationToken cancellationToken)
@@ -1383,21 +1283,16 @@ namespace MediaBrowser.Controller.Entities
{
try
{
- var files = IsFileProtocol ?
- GetFileSystemChildren(options.DirectoryService).ToList() :
- new List<FileSystemMetadata>();
-
- var ownedItemsChanged = await RefreshedOwnedItems(options, files, cancellationToken).ConfigureAwait(false);
- await LibraryManager.UpdateImagesAsync(this).ConfigureAwait(false); // ensure all image properties in DB are fresh
-
- if (ownedItemsChanged)
+ if (IsFileProtocol)
{
- requiresSave = true;
+ requiresSave = await RefreshedOwnedItems(options, GetFileSystemChildren(options.DirectoryService).ToList(), cancellationToken).ConfigureAwait(false);
}
+
+ await LibraryManager.UpdateImagesAsync(this).ConfigureAwait(false); // ensure all image properties in DB are fresh
}
catch (Exception ex)
{
- Logger.LogError(ex, "Error refreshing owned items for {path}", Path ?? Name);
+ Logger.LogError(ex, "Error refreshing owned items for {Path}", Path ?? Name);
}
}
@@ -1418,14 +1313,46 @@ namespace MediaBrowser.Controller.Entities
}
}
- [JsonIgnore]
- protected virtual bool SupportsOwnedItems => !ParentId.Equals(Guid.Empty) && IsFileProtocol;
+ protected bool IsVisibleStandaloneInternal(User user, bool checkFolders)
+ {
+ if (!IsVisible(user))
+ {
+ return false;
+ }
- [JsonIgnore]
- public virtual bool SupportsPeople => false;
+ if (GetParents().Any(i => !i.IsVisible(user)))
+ {
+ return false;
+ }
- [JsonIgnore]
- public virtual bool SupportsThemeMedia => false;
+ if (checkFolders)
+ {
+ var topParent = GetParents().LastOrDefault() ?? this;
+
+ if (string.IsNullOrEmpty(topParent.Path))
+ {
+ return true;
+ }
+
+ var itemCollectionFolders = LibraryManager.GetCollectionFolders(this).Select(i => i.Id).ToList();
+
+ if (itemCollectionFolders.Count > 0)
+ {
+ var userCollectionFolders = LibraryManager.GetUserRootFolder().GetChildren(user, true).Select(i => i.Id).ToList();
+ if (!itemCollectionFolders.Any(userCollectionFolders.Contains))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void SetParent(Folder parent)
+ {
+ ParentId = parent == null ? Guid.Empty : parent.Id;
+ }
/// <summary>
/// Refreshes owned items such as trailers, theme videos, special features, etc.
@@ -1437,36 +1364,12 @@ namespace MediaBrowser.Controller.Entities
/// <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;
-
- var themeVideosChanged = false;
-
- var extrasChanged = false;
-
- var localTrailersChanged = false;
-
- if (IsFileProtocol && SupportsOwnedItems)
+ if (!IsFileProtocol || !SupportsOwnedItems || IsInMixedFolder || this is ICollectionFolder or UserRootFolder or AggregateFolder || this.GetType() == typeof(Folder))
{
- if (SupportsThemeMedia)
- {
- if (!IsInMixedFolder)
- {
- themeSongsChanged = await RefreshThemeSongs(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
-
- themeVideosChanged = await RefreshThemeVideos(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
-
- extrasChanged = await RefreshExtras(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
- }
- }
-
- var hasTrailers = this as IHasTrailers;
- if (hasTrailers != null)
- {
- localTrailersChanged = await RefreshLocalTrailers(hasTrailers, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
- }
+ return false;
}
- return themeSongsChanged || themeVideosChanged || extrasChanged || localTrailersChanged;
+ return await RefreshExtras(this, options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
}
protected virtual FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
@@ -1476,98 +1379,24 @@ namespace MediaBrowser.Controller.Entities
return directoryService.GetFileSystemEntries(path);
}
- private async Task<bool> RefreshLocalTrailers(IHasTrailers item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
- {
- var newItems = LibraryManager.FindTrailers(this, fileSystemChildren, options.DirectoryService);
-
- var newItemIds = newItems.Select(i => i.Id);
-
- var itemsChanged = !item.LocalTrailerIds.SequenceEqual(newItemIds);
- var ownerId = item.Id;
-
- var tasks = newItems.Select(i =>
- {
- var subOptions = new MetadataRefreshOptions(options);
-
- if (i.ExtraType != Model.Entities.ExtraType.Trailer ||
- i.OwnerId != ownerId ||
- !i.ParentId.Equals(Guid.Empty))
- {
- i.ExtraType = Model.Entities.ExtraType.Trailer;
- i.OwnerId = ownerId;
- i.ParentId = Guid.Empty;
- subOptions.ForceSave = true;
- }
-
- return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
- });
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
- item.LocalTrailerIds = newItemIds.ToArray();
-
- return itemsChanged;
- }
-
private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
- var extras = LoadExtras(fileSystemChildren, options.DirectoryService);
- var themeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
- var themeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
- var newExtras = new BaseItem[extras.Length + themeVideos.Length + themeSongs.Length];
- extras.CopyTo(newExtras, 0);
- themeVideos.CopyTo(newExtras, extras.Length);
- themeSongs.CopyTo(newExtras, extras.Length + themeVideos.Length);
-
- var newExtraIds = newExtras.Select(i => i.Id).ToArray();
-
+ var extras = LibraryManager.FindExtras(item, fileSystemChildren, options.DirectoryService).ToArray();
+ var newExtraIds = extras.Select(i => i.Id).ToArray();
var extrasChanged = !item.ExtraIds.SequenceEqual(newExtraIds);
- if (extrasChanged)
+ if (!extrasChanged && !options.ReplaceAllMetadata && options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh)
{
- var ownerId = item.Id;
-
- var tasks = newExtras.Select(i =>
- {
- var subOptions = new MetadataRefreshOptions(options);
- if (i.OwnerId != ownerId || i.ParentId != Guid.Empty)
- {
- i.OwnerId = ownerId;
- i.ParentId = Guid.Empty;
- subOptions.ForceSave = true;
- }
-
- return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
- });
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
- item.ExtraIds = newExtraIds;
+ return false;
}
- return extrasChanged;
- }
-
- private async Task<bool> RefreshThemeVideos(BaseItem item, MetadataRefreshOptions options, IEnumerable<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
- {
- var newThemeVideos = LoadThemeVideos(fileSystemChildren, options.DirectoryService);
-
- var newThemeVideoIds = newThemeVideos.Select(i => i.Id).ToArray();
-
- var themeVideosChanged = !item.ThemeVideoIds.SequenceEqual(newThemeVideoIds);
-
var ownerId = item.Id;
- var tasks = newThemeVideos.Select(i =>
+ var tasks = extras.Select(i =>
{
var subOptions = new MetadataRefreshOptions(options);
-
- if (!i.ExtraType.HasValue ||
- i.ExtraType.Value != Model.Entities.ExtraType.ThemeVideo ||
- i.OwnerId != ownerId ||
- !i.ParentId.Equals(Guid.Empty))
+ if (i.OwnerId != ownerId || i.ParentId != Guid.Empty)
{
- i.ExtraType = Model.Entities.ExtraType.ThemeVideo;
i.OwnerId = ownerId;
i.ParentId = Guid.Empty;
subOptions.ForceSave = true;
@@ -1578,73 +1407,11 @@ namespace MediaBrowser.Controller.Entities
await Task.WhenAll(tasks).ConfigureAwait(false);
- // They are expected to be sorted by SortName
- item.ThemeVideoIds = newThemeVideos.OrderBy(i => i.SortName).Select(i => i.Id).ToArray();
+ item.ExtraIds = newExtraIds;
- return themeVideosChanged;
- }
-
- /// <summary>
- /// Refreshes the theme songs.
- /// </summary>
- private async Task<bool> RefreshThemeSongs(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
- {
- var newThemeSongs = LoadThemeSongs(fileSystemChildren, options.DirectoryService);
- var newThemeSongIds = newThemeSongs.Select(i => i.Id).ToArray();
-
- var themeSongsChanged = !item.ThemeSongIds.SequenceEqual(newThemeSongIds);
-
- var ownerId = item.Id;
-
- var tasks = newThemeSongs.Select(i =>
- {
- var subOptions = new MetadataRefreshOptions(options);
-
- if (!i.ExtraType.HasValue ||
- i.ExtraType.Value != Model.Entities.ExtraType.ThemeSong ||
- i.OwnerId != ownerId ||
- !i.ParentId.Equals(Guid.Empty))
- {
- i.ExtraType = Model.Entities.ExtraType.ThemeSong;
- i.OwnerId = ownerId;
- i.ParentId = Guid.Empty;
- subOptions.ForceSave = true;
- }
-
- return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken);
- });
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
- // They are expected to be sorted by SortName
- item.ThemeSongIds = newThemeSongs.OrderBy(i => i.SortName).Select(i => i.Id).ToArray();
-
- return themeSongsChanged;
- }
-
- /// <summary>
- /// Gets or sets the provider ids.
- /// </summary>
- /// <value>The provider ids.</value>
- [JsonIgnore]
- public Dictionary<string, string> ProviderIds { get; set; }
-
- [JsonIgnore]
- public virtual Folder LatestItemsIndexContainer => null;
-
- public virtual double GetDefaultPrimaryImageAspectRatio()
- {
- return 0;
- }
-
- public virtual string CreatePresentationUniqueKey()
- {
- return Id.ToString("N", CultureInfo.InvariantCulture);
+ return true;
}
- [JsonIgnore]
- public string PresentationUniqueKey { get; set; }
-
public string GetPresentationUniqueKey()
{
return PresentationUniqueKey ?? CreatePresentationUniqueKey();
@@ -1875,7 +1642,7 @@ namespace MediaBrowser.Controller.Entities
private bool IsVisibleViaTags(User user)
{
- if (user.GetPreference(PreferenceKind.BlockedTags).Any(i => Tags.Contains(i, StringComparer.OrdinalIgnoreCase)))
+ if (user.GetPreference(PreferenceKind.BlockedTags).Any(i => Tags.Contains(i, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
@@ -1942,58 +1709,9 @@ namespace MediaBrowser.Controller.Entities
return IsVisibleStandaloneInternal(user, true);
}
- [JsonIgnore]
- public virtual bool SupportsInheritedParentImages => false;
-
- protected bool IsVisibleStandaloneInternal(User user, bool checkFolders)
- {
- if (!IsVisible(user))
- {
- return false;
- }
-
- if (GetParents().Any(i => !i.IsVisible(user)))
- {
- return false;
- }
-
- if (checkFolders)
- {
- var topParent = GetParents().LastOrDefault() ?? this;
-
- if (string.IsNullOrEmpty(topParent.Path))
- {
- return true;
- }
-
- var itemCollectionFolders = LibraryManager.GetCollectionFolders(this).Select(i => i.Id).ToList();
-
- if (itemCollectionFolders.Count > 0)
- {
- var userCollectionFolders = LibraryManager.GetUserRootFolder().GetChildren(user, true).Select(i => i.Id).ToList();
- if (!itemCollectionFolders.Any(userCollectionFolders.Contains))
- {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /// <summary>
- /// Gets a value indicating whether this instance is folder.
- /// </summary>
- /// <value><c>true</c> if this instance is folder; otherwise, <c>false</c>.</value>
- [JsonIgnore]
- public virtual bool IsFolder => false;
-
- [JsonIgnore]
- public virtual bool IsDisplayedAsFolder => false;
-
public virtual string GetClientTypeName()
{
- if (IsFolder && SourceType == SourceType.Channel && !(this is Channel))
+ if (IsFolder && SourceType == SourceType.Channel && this is not Channel)
{
return "ChannelFolderItem";
}
@@ -2003,7 +1721,7 @@ namespace MediaBrowser.Controller.Entities
public BaseItemKind GetBaseItemKind()
{
- return Enum.Parse<BaseItemKind>(GetClientTypeName());
+ return _baseItemKind ??= Enum.Parse<BaseItemKind>(GetClientTypeName());
}
/// <summary>
@@ -2079,14 +1797,11 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [JsonIgnore]
- public virtual bool EnableRememberingTrackSelections => true;
-
/// <summary>
/// Adds a studio to the item.
/// </summary>
/// <param name="name">The name.</param>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException">Throws if name is null.</exception>
public void AddStudio(string name)
{
if (string.IsNullOrEmpty(name))
@@ -2096,7 +1811,7 @@ namespace MediaBrowser.Controller.Entities
var current = Studios;
- if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
+ if (!current.Contains(name, StringComparison.OrdinalIgnoreCase))
{
int curLen = current.Length;
if (curLen == 0)
@@ -2122,7 +1837,7 @@ namespace MediaBrowser.Controller.Entities
/// Adds a genre to the item.
/// </summary>
/// <param name="name">The name.</param>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException">Throwns if name is null.</exception>
public void AddGenre(string name)
{
if (string.IsNullOrEmpty(name))
@@ -2131,7 +1846,7 @@ namespace MediaBrowser.Controller.Entities
}
var genres = Genres;
- if (!genres.Contains(name, StringComparer.OrdinalIgnoreCase))
+ if (!genres.Contains(name, StringComparison.OrdinalIgnoreCase))
{
var list = genres.ToList();
list.Add(name);
@@ -2145,8 +1860,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="user">The user.</param>
/// <param name="datePlayed">The date played.</param>
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException">Throws if user is null.</exception>
public virtual void MarkPlayed(
User user,
DateTime? datePlayed,
@@ -2183,8 +1897,7 @@ namespace MediaBrowser.Controller.Entities
/// Marks the unplayed.
/// </summary>
/// <param name="user">The user.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException"></exception>
+ /// <exception cref="ArgumentNullException">Throws if user is null.</exception>
public virtual void MarkUnplayed(User user)
{
if (user == null)
@@ -2234,7 +1947,11 @@ namespace MediaBrowser.Controller.Entities
var existingImage = GetImageInfo(image.Type, index);
- if (existingImage != null)
+ if (existingImage == null)
+ {
+ AddImage(image);
+ }
+ else
{
existingImage.Path = image.Path;
existingImage.DateModified = image.DateModified;
@@ -2242,15 +1959,6 @@ namespace MediaBrowser.Controller.Entities
existingImage.Height = image.Height;
existingImage.BlurHash = image.BlurHash;
}
- else
- {
- var current = ImageInfos;
- var currentCount = current.Length;
- var newArr = new ItemImageInfo[currentCount + 1];
- current.CopyTo(newArr, 0);
- newArr[currentCount] = image;
- ImageInfos = newArr;
- }
}
public void SetImagePath(ImageType type, int index, FileSystemMetadata file)
@@ -2264,7 +1972,7 @@ namespace MediaBrowser.Controller.Entities
if (image == null)
{
- ImageInfos = ImageInfos.Concat(new[] { GetImageInfo(file, type) }).ToArray();
+ AddImage(GetImageInfo(file, type));
}
else
{
@@ -2284,6 +1992,7 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="type">The type.</param>
/// <param name="index">The index.</param>
+ /// <returns>A task.</returns>
public async Task DeleteImageAsync(ImageType type, int index)
{
var info = GetImageInfo(type, index);
@@ -2307,20 +2016,32 @@ namespace MediaBrowser.Controller.Entities
public void RemoveImage(ItemImageInfo image)
{
- RemoveImages(new List<ItemImageInfo> { image });
+ RemoveImages(new[] { image });
}
- public void RemoveImages(List<ItemImageInfo> deletedImages)
+ public void RemoveImages(IEnumerable<ItemImageInfo> deletedImages)
{
ImageInfos = ImageInfos.Except(deletedImages).ToArray();
}
+ public void AddImage(ItemImageInfo image)
+ {
+ var current = ImageInfos;
+ var currentCount = current.Length;
+ var newArr = new ItemImageInfo[currentCount + 1];
+ current.CopyTo(newArr, 0);
+ newArr[currentCount] = image;
+ ImageInfos = newArr;
+ }
+
public virtual Task UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken)
=> LibraryManager.UpdateItemAsync(this, GetParent(), updateReason, cancellationToken);
/// <summary>
/// Validates that images within the item are still on the filesystem.
/// </summary>
+ /// <param name="directoryService">The directory service to use.</param>
+ /// <returns><c>true</c> if the images validate, <c>false</c> if not.</returns>
public bool ValidateImages(IDirectoryService directoryService)
{
var allFiles = ImageInfos
@@ -2331,12 +2052,12 @@ namespace MediaBrowser.Controller.Entities
.ToList();
var deletedImages = ImageInfos
- .Where(image => image.IsLocalFile && !allFiles.Contains(image.Path, StringComparer.OrdinalIgnoreCase))
+ .Where(image => image.IsLocalFile && !allFiles.Contains(image.Path, StringComparison.OrdinalIgnoreCase))
.ToList();
if (deletedImages.Count > 0)
{
- ImageInfos = ImageInfos.Except(deletedImages).ToArray();
+ RemoveImages(deletedImages);
}
return deletedImages.Count > 0;
@@ -2348,7 +2069,6 @@ 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 is null.</exception>
public string GetImagePath(ImageType imageType, int imageIndex)
=> GetImageInfo(imageType, imageIndex)?.Path;
@@ -2385,6 +2105,17 @@ namespace MediaBrowser.Controller.Entities
};
}
+ // Music albums usually don't have dedicated backdrops, so return one from the artist instead
+ if (GetType() == typeof(MusicAlbum) && imageType == ImageType.Backdrop)
+ {
+ var artist = FindParent<MusicArtist>();
+
+ if (artist != null)
+ {
+ return artist.GetImages(imageType).ElementAtOrDefault(imageIndex);
+ }
+ }
+
return GetImages(imageType)
.ElementAtOrDefault(imageIndex);
}
@@ -2448,11 +2179,11 @@ namespace MediaBrowser.Controller.Entities
}
/// <summary>
- /// Adds the images.
+ /// Adds the images, updating metadata if they already are part of this item.
/// </summary>
/// <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>
+ /// <returns><c>true</c> if images were added or updated, <c>false</c> otherwise.</returns>
/// <exception cref="ArgumentException">Cannot call AddImages with chapter images.</exception>
public bool AddImages(ImageType imageType, List<FileSystemMetadata> images)
{
@@ -2465,7 +2196,6 @@ namespace MediaBrowser.Controller.Entities
.ToList();
var newImageList = new List<FileSystemMetadata>();
- var imageAdded = false;
var imageUpdated = false;
foreach (var newImage in images)
@@ -2481,7 +2211,6 @@ namespace MediaBrowser.Controller.Entities
if (existing == null)
{
newImageList.Add(newImage);
- imageAdded = true;
}
else
{
@@ -2502,19 +2231,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- if (imageAdded || images.Count != existingImages.Count)
- {
- var newImagePaths = images.Select(i => i.FullName).ToList();
-
- var deleted = existingImages
- .FindAll(i => i.IsLocalFile && !newImagePaths.Contains(i.Path.AsSpan(), StringComparison.OrdinalIgnoreCase) && !File.Exists(i.Path));
-
- if (deleted.Count > 0)
- {
- ImageInfos = ImageInfos.Except(deleted).ToArray();
- }
- }
-
if (newImageList.Count > 0)
{
ImageInfos = ImageInfos.Concat(newImageList.Select(i => GetImageInfo(i, imageType))).ToArray();
@@ -2565,7 +2281,7 @@ namespace MediaBrowser.Controller.Entities
public bool AllowsMultipleImages(ImageType type)
{
- return type == ImageType.Backdrop || type == ImageType.Screenshot || type == ImageType.Chapter;
+ return type == ImageType.Backdrop || type == ImageType.Chapter;
}
public Task SwapImagesAsync(ImageType type, int index1, int index2)
@@ -2683,7 +2399,7 @@ namespace MediaBrowser.Controller.Entities
protected static string GetMappedPath(BaseItem item, string path, MediaProtocol? protocol)
{
- if (protocol.HasValue && protocol.Value == MediaProtocol.File)
+ if (protocol == MediaProtocol.File)
{
return LibraryManager.GetPathAfterNetworkSubstitution(path, item);
}
@@ -2711,8 +2427,10 @@ namespace MediaBrowser.Controller.Entities
protected Task RefreshMetadataForOwnedItem(BaseItem ownedItem, bool copyTitleMetadata, MetadataRefreshOptions options, CancellationToken cancellationToken)
{
- var newOptions = new MetadataRefreshOptions(options);
- newOptions.SearchResult = null;
+ var newOptions = new MetadataRefreshOptions(options)
+ {
+ SearchResult = null
+ };
var item = this;
@@ -2773,8 +2491,10 @@ namespace MediaBrowser.Controller.Entities
protected Task RefreshMetadataForOwnedVideo(MetadataRefreshOptions options, bool copyTitleMetadata, string path, CancellationToken cancellationToken)
{
- var newOptions = new MetadataRefreshOptions(options);
- newOptions.SearchResult = null;
+ var newOptions = new MetadataRefreshOptions(options)
+ {
+ SearchResult = null
+ };
var id = LibraryManager.GetNewItemId(path, typeof(Video));
@@ -2788,14 +2508,6 @@ namespace MediaBrowser.Controller.Entities
newOptions.ForceSave = true;
}
- // var parentId = Id;
- // if (!video.IsOwnedItem || video.ParentId != parentId)
- // {
- // video.IsOwnedItem = true;
- // video.ParentId = parentId;
- // newOptions.ForceSave = true;
- // }
-
if (video == null)
{
return Task.FromResult(true);
@@ -2834,39 +2546,6 @@ namespace MediaBrowser.Controller.Entities
return GetParents().FirstOrDefault(parent => parent.IsTopParent);
}
- [JsonIgnore]
- public virtual bool IsTopParent
- {
- get
- {
- if (this is BasePluginFolder || this is Channel)
- {
- return true;
- }
-
- if (this is IHasCollectionType view)
- {
- if (string.Equals(view.CollectionType, CollectionType.LiveTv, StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- if (GetParent() is AggregateFolder)
- {
- return true;
- }
-
- return false;
- }
- }
-
- [JsonIgnore]
- public virtual bool SupportsAncestors => true;
-
- [JsonIgnore]
- public virtual bool StopRefreshIfLocalMetadataFound => true;
-
public virtual IEnumerable<Guid> GetIdsForAncestorQuery()
{
return new[] { Id };
@@ -2901,6 +2580,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Updates the official rating based on content and returns true or false indicating if it changed.
/// </summary>
+ /// <param name="children">Media children.</param>
/// <returns><c>true</c> if the rating was updated; otherwise <c>false</c>.</returns>
public bool UpdateRatingToItems(IList<BaseItem> children)
{
@@ -2911,7 +2591,7 @@ namespace MediaBrowser.Controller.Entities
.Select(i => i.OfficialRating)
.Where(i => !string.IsNullOrEmpty(i))
.Distinct(StringComparer.OrdinalIgnoreCase)
- .Select(i => new Tuple<string, int?>(i, LocalizationManager.GetRatingLevel(i)))
+ .Select(i => (i, LocalizationManager.GetRatingLevel(i)))
.OrderBy(i => i.Item2 ?? 1000)
.Select(i => i.Item1);
@@ -2923,23 +2603,17 @@ namespace MediaBrowser.Controller.Entities
StringComparison.OrdinalIgnoreCase);
}
- public IEnumerable<BaseItem> GetThemeSongs()
+ public IReadOnlyList<BaseItem> GetThemeSongs()
{
- return ThemeSongIds.Select(LibraryManager.GetItemById);
+ return GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeSong).ToArray();
}
- public IEnumerable<BaseItem> GetThemeVideos()
+ public IReadOnlyList<BaseItem> GetThemeVideos()
{
- return ThemeVideoIds.Select(LibraryManager.GetItemById);
+ return GetExtras().Where(e => e.ExtraType == Model.Entities.ExtraType.ThemeVideo).ToArray();
}
/// <summary>
- /// Gets or sets the remote trailers.
- /// </summary>
- /// <value>The remote trailers.</value>
- public IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
-
- /// <summary>
/// Get all extras associated with this item, sorted by <see cref="SortName"/>.
/// </summary>
/// <returns>An enumerable containing the items.</returns>
@@ -2964,51 +2638,11 @@ namespace MediaBrowser.Controller.Entities
.Where(i => i.ExtraType.HasValue && extraTypes.Contains(i.ExtraType.Value));
}
- public IEnumerable<BaseItem> GetTrailers()
- {
- if (this is IHasTrailers)
- {
- return ((IHasTrailers)this).LocalTrailerIds.Select(LibraryManager.GetItemById).Where(i => i != null).OrderBy(i => i.SortName);
- }
- else
- {
- return Array.Empty<BaseItem>();
- }
- }
-
- public virtual bool IsHD => Height >= 720;
-
- public bool IsShortcut { get; set; }
-
- public string ShortcutPath { get; set; }
-
- public int Width { get; set; }
-
- public int Height { get; set; }
-
- public Guid[] ExtraIds { get; set; }
-
public virtual long GetRunTimeTicksForPlayState()
{
return RunTimeTicks ?? 0;
}
- /// <summary>
- /// Extra types that should be counted and displayed as "Special Features" in the UI.
- /// </summary>
- public static readonly IReadOnlyCollection<ExtraType> DisplayExtraTypes = new HashSet<ExtraType>
- {
- Model.Entities.ExtraType.Unknown,
- Model.Entities.ExtraType.BehindTheScenes,
- Model.Entities.ExtraType.Clip,
- Model.Entities.ExtraType.DeletedScene,
- Model.Entities.ExtraType.Interview,
- Model.Entities.ExtraType.Sample,
- Model.Entities.ExtraType.Scene
- };
-
- public virtual bool SupportsExternalTransfer => false;
-
/// <inheritdoc />
public override bool Equals(object obj)
{
@@ -3016,7 +2650,7 @@ namespace MediaBrowser.Controller.Entities
}
/// <inheritdoc />
- public bool Equals(BaseItem other) => object.Equals(Id, other?.Id);
+ public bool Equals(BaseItem other) => Id == other?.Id;
/// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(Id);
diff --git a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
index 89ad392a4..33870e2fb 100644
--- a/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
+++ b/MediaBrowser.Controller/Entities/BaseItemExtensions.cs
@@ -44,7 +44,7 @@ namespace MediaBrowser.Controller.Entities
/// <param name="file">The file.</param>
public static void SetImagePath(this BaseItem item, ImageType imageType, string file)
{
- if (file.StartsWith("http", System.StringComparison.OrdinalIgnoreCase))
+ if (file.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
item.SetImage(
new ItemImageInfo
@@ -64,6 +64,8 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
/// <param name="source">The source object.</param>
/// <param name="dest">The destination object.</param>
+ /// <typeparam name="T">Source type.</typeparam>
+ /// <typeparam name="TU">Destination type.</typeparam>
public static void DeepCopy<T, TU>(this T source, TU dest)
where T : BaseItem
where TU : BaseItem
@@ -109,6 +111,9 @@ namespace MediaBrowser.Controller.Entities
/// Copies all properties on newly created object. Skips properties that do not exist.
/// </summary>
/// <param name="source">The source object.</param>
+ /// <typeparam name="T">Source type.</typeparam>
+ /// <typeparam name="TU">Destination type.</typeparam>
+ /// <returns>Destination object.</returns>
public static TU DeepCopy<T, TU>(this T source)
where T : BaseItem
where TU : BaseItem, new()
diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
index 1bd25042f..272a37df1 100644
--- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs
+++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs
@@ -15,6 +15,12 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public virtual string CollectionType => null;
+ [JsonIgnore]
+ public override bool SupportsInheritedParentImages => false;
+
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
public override bool CanDelete()
{
return false;
@@ -24,11 +30,5 @@ namespace MediaBrowser.Controller.Entities
{
return true;
}
-
- [JsonIgnore]
- public override bool SupportsInheritedParentImages => false;
-
- [JsonIgnore]
- public override bool SupportsPeople => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 4a721ca44..7dc7f774d 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -10,7 +10,7 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Json;
+using Jellyfin.Extensions.Json;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
@@ -41,6 +41,23 @@ namespace MediaBrowser.Controller.Entities
PhysicalFolderIds = Array.Empty<Guid>();
}
+ /// <summary>
+ /// Gets the display preferences id.
+ /// </summary>
+ /// <remarks>
+ /// Allow different display preferences for each collection folder.
+ /// </remarks>
+ /// <value>The display prefs id.</value>
+ [JsonIgnore]
+ public override Guid DisplayPreferencesId => Id;
+
+ [JsonIgnore]
+ public override string[] PhysicalLocations => PhysicalLocationsList;
+
+ public string[] PhysicalLocationsList { get; set; }
+
+ public Guid[] PhysicalFolderIds { get; set; }
+
public static IXmlSerializer XmlSerializer { get; set; }
public static IServerApplicationHost ApplicationHost { get; set; }
@@ -63,6 +80,9 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override IEnumerable<BaseItem> Children => GetActualChildren();
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
public override bool CanDelete()
{
return false;
@@ -77,8 +97,7 @@ namespace MediaBrowser.Controller.Entities
{
try
{
- var result = XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) as LibraryOptions;
- if (result == null)
+ if (XmlSerializer.DeserializeFromFile(typeof(LibraryOptions), GetLibraryOptionsPath(path)) is not LibraryOptions result)
{
return new LibraryOptions();
}
@@ -160,23 +179,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- /// <summary>
- /// Gets the display preferences id.
- /// </summary>
- /// <remarks>
- /// Allow different display preferences for each collection folder.
- /// </remarks>
- /// <value>The display prefs id.</value>
- [JsonIgnore]
- public override Guid DisplayPreferencesId => Id;
-
- [JsonIgnore]
- public override string[] PhysicalLocations => PhysicalLocationsList;
-
- public string[] PhysicalLocationsList { get; set; }
-
- public Guid[] PhysicalFolderIds { get; set; }
-
public override bool IsSaveLocalMetadataEnabled()
{
return true;
@@ -373,8 +375,5 @@ namespace MediaBrowser.Controller.Entities
return result;
}
-
- [JsonIgnore]
- public override bool SupportsPeople => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/Extensions.cs b/MediaBrowser.Controller/Entities/Extensions.cs
index 244cc00be..9ce8eebe3 100644
--- a/MediaBrowser.Controller/Entities/Extensions.cs
+++ b/MediaBrowser.Controller/Entities/Extensions.cs
@@ -2,7 +2,7 @@
using System;
using System.Linq;
-using MediaBrowser.Common.Extensions;
+using Jellyfin.Extensions;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Entities
@@ -15,6 +15,8 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Adds the trailer URL.
/// </summary>
+ /// <param name="item">Media item.</param>
+ /// <param name="url">Trailer URL.</param>
public static void AddTrailerUrl(this BaseItem item, string url)
{
if (string.IsNullOrEmpty(url))
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 541747422..55551e70e 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1002, CA1721, CA1819, CS1591
using System;
using System.Collections.Generic;
@@ -165,6 +165,8 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public static ICollectionManager CollectionManager { get; set; }
+
public override bool CanDelete()
{
if (IsRoot)
@@ -206,9 +208,8 @@ namespace MediaBrowser.Controller.Entities
/// Adds the child.
/// </summary>
/// <param name="item">The item.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
/// <exception cref="InvalidOperationException">Unable to add + item.Name.</exception>
- public void AddChild(BaseItem item, CancellationToken cancellationToken)
+ public void AddChild(BaseItem item)
{
item.SetParent(this);
@@ -232,7 +233,7 @@ namespace MediaBrowser.Controller.Entities
public override bool IsVisible(User user)
{
- if (this is ICollectionFolder && !(this is BasePluginFolder))
+ if (this is ICollectionFolder && this is not BasePluginFolder)
{
var blockedMediaFolders = user.GetPreferenceValues<Guid>(PreferenceKind.BlockedMediaFolders);
if (blockedMediaFolders.Length > 0)
@@ -259,6 +260,7 @@ namespace MediaBrowser.Controller.Entities
/// Loads our children. Validation will occur externally.
/// We want this synchronous.
/// </summary>
+ /// <returns>Returns children.</returns>
protected virtual List<BaseItem> LoadChildren()
{
// logger.LogDebug("Loading children from {0} {1} {2}", GetType().Name, Id, Path);
@@ -301,7 +303,7 @@ namespace MediaBrowser.Controller.Entities
if (dictionary.ContainsKey(id))
{
Logger.LogError(
- "Found folder containing items with duplicate id. Path: {path}, Child Name: {ChildName}",
+ "Found folder containing items with duplicate id. Path: {Path}, Child Name: {ChildName}",
Path ?? Name,
child.Path ?? child.Name);
}
@@ -423,7 +425,7 @@ namespace MediaBrowser.Controller.Entities
{
if (item.IsFileProtocol)
{
- Logger.LogDebug("Removed item: " + item.Path);
+ Logger.LogDebug("Removed item: {Path}", item.Path);
item.SetParent(null);
LibraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }, this, false);
@@ -643,6 +645,8 @@ namespace MediaBrowser.Controller.Entities
/// Get the children of this folder from the actual file system.
/// </summary>
/// <returns>IEnumerable{BaseItem}.</returns>
+ /// <param name="directoryService">The directory service to use for operation.</param>
+ /// <returns>Returns set of base items.</returns>
protected virtual IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
{
var collectionType = LibraryManager.GetContentType(this);
@@ -669,7 +673,7 @@ namespace MediaBrowser.Controller.Entities
{
if (LinkedChildren.Length > 0)
{
- if (!(this is ICollectionFolder))
+ if (this is not ICollectionFolder)
{
return GetChildren(user, true).Count;
}
@@ -726,7 +730,7 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(items, query, true);
}
- if (!(this is UserRootFolder) && !(this is AggregateFolder) && query.ParentId == Guid.Empty)
+ if (this is not UserRootFolder && this is not AggregateFolder && query.ParentId == Guid.Empty)
{
query.Parent = this;
}
@@ -788,7 +792,7 @@ namespace MediaBrowser.Controller.Entities
private bool RequiresPostFiltering2(InternalItemsQuery query)
{
- if (query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.BoxSet)
{
Logger.LogDebug("Query requires post-filtering due to BoxSet query");
return true;
@@ -801,9 +805,9 @@ namespace MediaBrowser.Controller.Entities
{
if (LinkedChildren.Length > 0)
{
- if (!(this is ICollectionFolder))
+ if (this is not ICollectionFolder)
{
- Logger.LogDebug("Query requires post-filtering due to LinkedChildren. Type: " + GetType().Name);
+ Logger.LogDebug("{Type}: Query requires post-filtering due to LinkedChildren.", GetType().Name);
return true;
}
}
@@ -878,7 +882,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IsPlayed.HasValue)
{
- if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(nameof(Series)))
+ if (query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes.Contains(BaseItemKind.Series))
{
Logger.LogDebug("Query requires post-filtering due to IsPlayed");
return true;
@@ -999,8 +1003,6 @@ namespace MediaBrowser.Controller.Entities
return PostFilterAndSort(items, query, true);
}
- public static ICollectionManager CollectionManager { get; set; }
-
protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query, bool enableSorting)
{
var user = query.User;
@@ -1011,20 +1013,22 @@ namespace MediaBrowser.Controller.Entities
items = CollapseBoxSetItemsIfNeeded(items, query, this, user, ConfigurationManager, CollectionManager);
}
+ #pragma warning disable CA1309
if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater))
{
- items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
+ items = items.Where(i => string.Compare(query.NameStartsWithOrGreater, i.SortName, StringComparison.InvariantCultureIgnoreCase) < 1);
}
if (!string.IsNullOrEmpty(query.NameStartsWith))
{
- items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.CurrentCultureIgnoreCase));
+ items = items.Where(i => i.SortName.StartsWith(query.NameStartsWith, StringComparison.InvariantCultureIgnoreCase));
}
if (!string.IsNullOrEmpty(query.NameLessThan))
{
- items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1);
+ items = items.Where(i => string.Compare(query.NameLessThan, i.SortName, StringComparison.InvariantCultureIgnoreCase) == 1);
}
+ #pragma warning restore CA1309
// This must be the last filter
if (!string.IsNullOrEmpty(query.AdjacentTo))
@@ -1097,7 +1101,7 @@ namespace MediaBrowser.Controller.Entities
return false;
}
- if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains("Movie", StringComparer.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(BaseItemKind.Movie))
{
param = true;
}
@@ -1385,18 +1389,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- /// <summary>
- /// Gets allowed recursive children of an item.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="includeLinkedChildren">if set to <c>true</c> [include linked children].</param>
- /// <returns>IEnumerable{BaseItem}.</returns>
- /// <exception cref="ArgumentNullException"></exception>
- public IEnumerable<BaseItem> GetRecursiveChildren(User user, bool includeLinkedChildren = true)
- {
- return GetRecursiveChildren(user, null);
- }
-
public virtual IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
if (user == null)
@@ -1555,7 +1547,7 @@ namespace MediaBrowser.Controller.Entities
var childOwner = child.GetOwner() ?? child;
- if (childOwner != null && !(child is IItemByName))
+ if (child is not IItemByName)
{
var childProtocol = childOwner.PathProtocol;
if (!childProtocol.HasValue || childProtocol.Value != Model.MediaInfo.MediaProtocol.File)
@@ -1679,7 +1671,6 @@ namespace MediaBrowser.Controller.Entities
/// <param name="user">The user.</param>
/// <param name="datePlayed">The date played.</param>
/// <param name="resetPosition">if set to <c>true</c> [reset position].</param>
- /// <returns>Task.</returns>
public override void MarkPlayed(
User user,
DateTime? datePlayed,
@@ -1721,7 +1712,6 @@ namespace MediaBrowser.Controller.Entities
/// Marks the unplayed.
/// </summary>
/// <param name="user">The user.</param>
- /// <returns>Task.</returns>
public override void MarkUnplayed(User user)
{
var itemsResult = GetItemList(new InternalItemsQuery
diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs
index b80a5be3b..4be673237 100644
--- a/MediaBrowser.Controller/Entities/Genre.cs
+++ b/MediaBrowser.Controller/Entities/Genre.cs
@@ -5,8 +5,8 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
+using Jellyfin.Data.Enums;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -66,10 +66,10 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { Id };
query.ExcludeItemTypes = new[]
{
- nameof(MusicVideo),
- nameof(Entities.Audio.Audio),
- nameof(MusicAlbum),
- nameof(MusicArtist)
+ BaseItemKind.MusicVideo,
+ BaseItemKind.Audio,
+ BaseItemKind.MusicAlbum,
+ BaseItemKind.MusicArtist
};
return LibraryManager.GetItemList(query);
diff --git a/MediaBrowser.Controller/Entities/ICollectionFolder.cs b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
index 2304570fd..89e494ebc 100644
--- a/MediaBrowser.Controller/Entities/ICollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/ICollectionFolder.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1819, CS1591
using System;
diff --git a/MediaBrowser.Controller/Entities/IHasMediaSources.cs b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
index 98c3b3edf..90d9bdd2d 100644
--- a/MediaBrowser.Controller/Entities/IHasMediaSources.cs
+++ b/MediaBrowser.Controller/Entities/IHasMediaSources.cs
@@ -20,6 +20,8 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Gets the media sources.
/// </summary>
+ /// <param name="enablePathSubstitution"><c>true</c> to enable path substitution, <c>false</c> to not.</param>
+ /// <returns>A list of media sources.</returns>
List<MediaSourceInfo> GetMediaSources(bool enablePathSubstitution);
List<MediaStream> GetMediaStreams();
diff --git a/MediaBrowser.Controller/Entities/IHasScreenshots.cs b/MediaBrowser.Controller/Entities/IHasScreenshots.cs
deleted file mode 100644
index ae01c223e..000000000
--- a/MediaBrowser.Controller/Entities/IHasScreenshots.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace MediaBrowser.Controller.Entities
-{
- /// <summary>
- /// The item has screenshots.
- /// </summary>
- public interface IHasScreenshots
- {
- }
-}
diff --git a/MediaBrowser.Controller/Entities/IHasShares.cs b/MediaBrowser.Controller/Entities/IHasShares.cs
index bdde744a3..dca5af873 100644
--- a/MediaBrowser.Controller/Entities/IHasShares.cs
+++ b/MediaBrowser.Controller/Entities/IHasShares.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1819, CS1591
namespace MediaBrowser.Controller.Entities
{
diff --git a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
index f317a02ff..f47d2162f 100644
--- a/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
+++ b/MediaBrowser.Controller/Entities/IHasSpecialFeatures.cs
@@ -10,9 +10,9 @@ namespace MediaBrowser.Controller.Entities
public interface IHasSpecialFeatures
{
/// <summary>
- /// Gets or sets the special feature ids.
+ /// Gets the special feature ids.
/// </summary>
/// <value>The special feature ids.</value>
- IReadOnlyList<Guid> SpecialFeatureIds { get; set; }
+ IReadOnlyList<Guid> SpecialFeatureIds { get; }
}
}
diff --git a/MediaBrowser.Controller/Entities/IHasTrailers.cs b/MediaBrowser.Controller/Entities/IHasTrailers.cs
index 2bd9ded33..bb4a6ea94 100644
--- a/MediaBrowser.Controller/Entities/IHasTrailers.cs
+++ b/MediaBrowser.Controller/Entities/IHasTrailers.cs
@@ -2,7 +2,6 @@
#pragma warning disable CS1591
-using System;
using System.Collections.Generic;
using MediaBrowser.Model.Entities;
@@ -17,18 +16,10 @@ namespace MediaBrowser.Controller.Entities
IReadOnlyList<MediaUrl> RemoteTrailers { get; set; }
/// <summary>
- /// Gets or sets the local trailer ids.
+ /// Gets the local trailers.
/// </summary>
- /// <value>The local trailer ids.</value>
- IReadOnlyList<Guid> LocalTrailerIds { get; set; }
-
- /// <summary>
- /// Gets or sets the remote trailer ids.
- /// </summary>
- /// <value>The remote trailer ids.</value>
- IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
-
- Guid Id { get; set; }
+ /// <value>The local trailers.</value>
+ IReadOnlyList<BaseItem> LocalTrailers { get; }
}
/// <summary>
@@ -39,57 +30,9 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// Gets the trailer count.
/// </summary>
+ /// <param name="item">Media item.</param>
/// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
public static int GetTrailerCount(this IHasTrailers item)
- => item.LocalTrailerIds.Count + item.RemoteTrailerIds.Count;
-
- /// <summary>
- /// Gets the trailer ids.
- /// </summary>
- /// <returns><see cref="IReadOnlyList{Guid}" />.</returns>
- public static IReadOnlyList<Guid> GetTrailerIds(this IHasTrailers item)
- {
- var localIds = item.LocalTrailerIds;
- var remoteIds = item.RemoteTrailerIds;
-
- var all = new Guid[localIds.Count + remoteIds.Count];
- var index = 0;
- foreach (var id in localIds)
- {
- all[index++] = id;
- }
-
- foreach (var id in remoteIds)
- {
- all[index++] = id;
- }
-
- return all;
- }
-
- /// <summary>
- /// Gets the trailers.
- /// </summary>
- /// <returns><see cref="IReadOnlyList{BaseItem}" />.</returns>
- public static IReadOnlyList<BaseItem> GetTrailers(this IHasTrailers item)
- {
- var localIds = item.LocalTrailerIds;
- var remoteIds = item.RemoteTrailerIds;
- var libraryManager = BaseItem.LibraryManager;
-
- var all = new BaseItem[localIds.Count + remoteIds.Count];
- var index = 0;
- foreach (var id in localIds)
- {
- all[index++] = libraryManager.GetItemById(id);
- }
-
- foreach (var id in remoteIds)
- {
- all[index++] = libraryManager.GetItemById(id);
- }
-
- return all;
- }
+ => item.LocalTrailers.Count + item.RemoteTrailers.Count;
}
}
diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
index ebaf5506d..f06b5c787 100644
--- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
+++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs
@@ -1,4 +1,4 @@
-#pragma warning disable CS1591
+#pragma warning disable CA1044, CA1819, CA2227, CS1591
using System;
using System.Collections.Generic;
@@ -12,6 +12,55 @@ namespace MediaBrowser.Controller.Entities
{
public class InternalItemsQuery
{
+ public InternalItemsQuery()
+ {
+ AlbumArtistIds = Array.Empty<Guid>();
+ AlbumIds = Array.Empty<Guid>();
+ AncestorIds = Array.Empty<Guid>();
+ ArtistIds = Array.Empty<Guid>();
+ BlockUnratedItems = Array.Empty<UnratedItem>();
+ BoxSetLibraryFolders = Array.Empty<Guid>();
+ ChannelIds = Array.Empty<Guid>();
+ ContributingArtistIds = Array.Empty<Guid>();
+ DtoOptions = new DtoOptions();
+ EnableTotalRecordCount = true;
+ ExcludeArtistIds = Array.Empty<Guid>();
+ ExcludeInheritedTags = Array.Empty<string>();
+ ExcludeItemIds = Array.Empty<Guid>();
+ ExcludeItemTypes = Array.Empty<BaseItemKind>();
+ ExcludeTags = Array.Empty<string>();
+ GenreIds = Array.Empty<Guid>();
+ Genres = Array.Empty<string>();
+ GroupByPresentationUniqueKey = true;
+ ImageTypes = Array.Empty<ImageType>();
+ IncludeItemTypes = Array.Empty<BaseItemKind>();
+ ItemIds = Array.Empty<Guid>();
+ MediaTypes = Array.Empty<string>();
+ MinSimilarityScore = 20;
+ OfficialRatings = Array.Empty<string>();
+ OrderBy = Array.Empty<ValueTuple<string, SortOrder>>();
+ PersonIds = Array.Empty<Guid>();
+ PersonTypes = Array.Empty<string>();
+ PresetViews = Array.Empty<string>();
+ SeriesStatuses = Array.Empty<SeriesStatus>();
+ SourceTypes = Array.Empty<SourceType>();
+ StudioIds = Array.Empty<Guid>();
+ Tags = Array.Empty<string>();
+ TopParentIds = Array.Empty<Guid>();
+ TrailerTypes = Array.Empty<TrailerType>();
+ VideoTypes = Array.Empty<VideoType>();
+ Years = Array.Empty<int>();
+ }
+
+ public InternalItemsQuery(User? user)
+ : this()
+ {
+ if (user != null)
+ {
+ SetUser(user);
+ }
+ }
+
public bool Recursive { get; set; }
public int? StartIndex { get; set; }
@@ -38,9 +87,9 @@ namespace MediaBrowser.Controller.Entities
public string[] MediaTypes { get; set; }
- public string[] IncludeItemTypes { get; set; }
+ public BaseItemKind[] IncludeItemTypes { get; set; }
- public string[] ExcludeItemTypes { get; set; }
+ public BaseItemKind[] ExcludeItemTypes { get; set; }
public string[] ExcludeTags { get; set; }
@@ -180,29 +229,12 @@ namespace MediaBrowser.Controller.Entities
public Guid ParentId { get; set; }
- public string? ParentType { get; set; }
+ public BaseItemKind? ParentType { get; set; }
public Guid[] AncestorIds { get; set; }
public Guid[] TopParentIds { get; set; }
- public BaseItem? Parent
- {
- set
- {
- if (value == null)
- {
- ParentId = Guid.Empty;
- ParentType = null;
- }
- else
- {
- ParentId = value.Id;
- ParentType = value.GetType().Name;
- }
- }
- }
-
public string[] PresetViews { get; set; }
public TrailerType[] TrailerTypes { get; set; }
@@ -270,70 +302,21 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public bool? DisplayAlbumFolders { get; set; }
- public InternalItemsQuery()
- {
- AlbumArtistIds = Array.Empty<Guid>();
- AlbumIds = Array.Empty<Guid>();
- AncestorIds = Array.Empty<Guid>();
- ArtistIds = Array.Empty<Guid>();
- BlockUnratedItems = Array.Empty<UnratedItem>();
- BoxSetLibraryFolders = Array.Empty<Guid>();
- ChannelIds = Array.Empty<Guid>();
- ContributingArtistIds = Array.Empty<Guid>();
- DtoOptions = new DtoOptions();
- EnableTotalRecordCount = true;
- ExcludeArtistIds = Array.Empty<Guid>();
- ExcludeInheritedTags = Array.Empty<string>();
- ExcludeItemIds = Array.Empty<Guid>();
- ExcludeItemTypes = Array.Empty<string>();
- ExcludeTags = Array.Empty<string>();
- GenreIds = Array.Empty<Guid>();
- Genres = Array.Empty<string>();
- GroupByPresentationUniqueKey = true;
- ImageTypes = Array.Empty<ImageType>();
- IncludeItemTypes = Array.Empty<string>();
- ItemIds = Array.Empty<Guid>();
- MediaTypes = Array.Empty<string>();
- MinSimilarityScore = 20;
- OfficialRatings = Array.Empty<string>();
- OrderBy = Array.Empty<ValueTuple<string, SortOrder>>();
- PersonIds = Array.Empty<Guid>();
- PersonTypes = Array.Empty<string>();
- PresetViews = Array.Empty<string>();
- SeriesStatuses = Array.Empty<SeriesStatus>();
- SourceTypes = Array.Empty<SourceType>();
- StudioIds = Array.Empty<Guid>();
- Tags = Array.Empty<string>();
- TopParentIds = Array.Empty<Guid>();
- TrailerTypes = Array.Empty<TrailerType>();
- VideoTypes = Array.Empty<VideoType>();
- Years = Array.Empty<int>();
- }
-
- public InternalItemsQuery(User? user)
- : this()
- {
- if (user != null)
- {
- SetUser(user);
- }
- }
-
- public void SetUser(User user)
+ public BaseItem? Parent
{
- MaxParentalRating = user.MaxParentalAgeRating;
-
- if (MaxParentalRating.HasValue)
+ set
{
- string other = UnratedItem.Other.ToString();
- BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
- .Where(i => i != other)
- .Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
+ if (value == null)
+ {
+ ParentId = Guid.Empty;
+ ParentType = null;
+ }
+ else
+ {
+ ParentId = value.Id;
+ ParentType = value.GetBaseItemKind();
+ }
}
-
- ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
-
- User = user;
}
public Dictionary<string, string>? HasAnyProviderId { get; set; }
@@ -361,5 +344,22 @@ namespace MediaBrowser.Controller.Entities
public string? SearchTerm { get; set; }
public string? SeriesTimerId { get; set; }
+
+ public void SetUser(User user)
+ {
+ MaxParentalRating = user.MaxParentalAgeRating;
+
+ if (MaxParentalRating.HasValue)
+ {
+ string other = UnratedItem.Other.ToString();
+ BlockUnratedItems = user.GetPreference(PreferenceKind.BlockUnratedItems)
+ .Where(i => i != other)
+ .Select(e => Enum.Parse<UnratedItem>(e, true)).ToArray();
+ }
+
+ ExcludeInheritedTags = user.GetPreference(PreferenceKind.BlockedTags);
+
+ User = user;
+ }
}
}
diff --git a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
index 74e84288d..6b93d8d87 100644
--- a/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
+++ b/MediaBrowser.Controller/Entities/Movies/BoxSet.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1721, CA1819, CS1591
using System;
using System.Collections.Generic;
@@ -9,7 +9,6 @@ using System.Text.Json.Serialization;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Controller.Entities.Movies
@@ -21,10 +20,6 @@ namespace MediaBrowser.Controller.Entities.Movies
{
public BoxSet()
{
- RemoteTrailers = Array.Empty<MediaUrl>();
- LocalTrailerIds = Array.Empty<Guid>();
- RemoteTrailerIds = Array.Empty<Guid>();
-
DisplayOrder = ItemSortBy.PremiereDate;
}
@@ -38,10 +33,9 @@ namespace MediaBrowser.Controller.Entities.Movies
public override bool SupportsPeople => true;
/// <inheritdoc />
- public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
-
- /// <inheritdoc />
- public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
+ public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
+ .ToArray();
/// <summary>
/// Gets or sets the display order.
@@ -49,6 +43,30 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <value>The display order.</value>
public string DisplayOrder { get; set; }
+ [JsonIgnore]
+ private bool IsLegacyBoxSet
+ {
+ get
+ {
+ if (string.IsNullOrEmpty(Path))
+ {
+ return false;
+ }
+
+ if (LinkedChildren.Length > 0)
+ {
+ return false;
+ }
+
+ return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path);
+ }
+ }
+
+ [JsonIgnore]
+ public override bool IsPreSorted => true;
+
+ public Guid[] LibraryFolderIds { get; set; }
+
protected override bool GetBlockUnratedValue(User user)
{
return user.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems).Contains(UnratedItem.Movie);
@@ -83,28 +101,6 @@ namespace MediaBrowser.Controller.Entities.Movies
return new List<BaseItem>();
}
- [JsonIgnore]
- private bool IsLegacyBoxSet
- {
- get
- {
- if (string.IsNullOrEmpty(Path))
- {
- return false;
- }
-
- if (LinkedChildren.Length > 0)
- {
- return false;
- }
-
- return !FileSystem.ContainsSubPath(ConfigurationManager.ApplicationPaths.DataPath, Path);
- }
- }
-
- [JsonIgnore]
- public override bool IsPreSorted => true;
-
public override bool IsAuthorizedToDelete(User user, List<Folder> allCollectionFolders)
{
return true;
@@ -191,8 +187,6 @@ namespace MediaBrowser.Controller.Entities.Movies
return IsVisible(user);
}
- public Guid[] LibraryFolderIds { get; set; }
-
private Guid[] GetLibraryFolderIds(User user)
{
return LibraryManager.GetUserRootFolder().GetChildren(user, true)
diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs
index b54bbf5eb..dfaf03fda 100644
--- a/MediaBrowser.Controller/Entities/Movies/Movie.cs
+++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs
@@ -7,12 +7,9 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
-using System.Threading;
-using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities.Movies
@@ -22,22 +19,16 @@ namespace MediaBrowser.Controller.Entities.Movies
/// </summary>
public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
{
- public Movie()
- {
- SpecialFeatureIds = Array.Empty<Guid>();
- RemoteTrailers = Array.Empty<MediaUrl>();
- LocalTrailerIds = Array.Empty<Guid>();
- RemoteTrailerIds = Array.Empty<Guid>();
- }
-
- /// <inheritdoc />
- public IReadOnlyList<Guid> SpecialFeatureIds { get; set; }
-
/// <inheritdoc />
- public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
+ public IReadOnlyList<Guid> SpecialFeatureIds => GetExtras()
+ .Where(extra => extra.ExtraType != null && extra is Video)
+ .Select(extra => extra.Id)
+ .ToArray();
/// <inheritdoc />
- public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
+ public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
+ .ToArray();
/// <summary>
/// Gets or sets the name of the TMDB collection.
@@ -66,54 +57,6 @@ namespace MediaBrowser.Controller.Entities.Movies
return 2.0 / 3;
}
- protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
- {
- var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
-
- // Must have a parent to have special features
- // In other words, it must be part of the Parent/Child tree
- if (IsFileProtocol && SupportsOwnedItems && !IsInMixedFolder)
- {
- var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
-
- if (specialFeaturesChanged)
- {
- hasChanges = true;
- }
- }
-
- return hasChanges;
- }
-
- private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
- {
- var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
- var newItemIds = newItems.Select(i => i.Id).ToArray();
-
- var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
-
- var ownerId = Id;
-
- var tasks = newItems.Select(i =>
- {
- var subOptions = new MetadataRefreshOptions(options);
-
- if (i.OwnerId != ownerId)
- {
- i.OwnerId = ownerId;
- subOptions.ForceSave = true;
- }
-
- return RefreshMetadataForOwnedItem(i, false, subOptions, cancellationToken);
- });
-
- await Task.WhenAll(tasks).ConfigureAwait(false);
-
- SpecialFeatureIds = newItemIds;
-
- return itemsChanged;
- }
-
/// <inheritdoc />
public override UnratedItem GetBlockUnratedType()
{
diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs
index 913f76d3b..045c1b89f 100644
--- a/MediaBrowser.Controller/Entities/Person.cs
+++ b/MediaBrowser.Controller/Entities/Person.cs
@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
@@ -16,6 +16,26 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Person : BaseItem, IItemByName, IHasLookupInfo<PersonLookupInfo>
{
+ /// <summary>
+ /// Gets the folder containing the item.
+ /// If the item is a folder, it returns the folder itself.
+ /// </summary>
+ /// <value>The containing folder path.</value>
+ [JsonIgnore]
+ public override string ContainingFolderPath => Path;
+
+ /// <summary>
+ /// Gets a value indicating whether to enable alpha numeric sorting.
+ /// </summary>
+ [JsonIgnore]
+ public override bool EnableAlphaNumericSorting => false;
+
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ [JsonIgnore]
+ public override bool SupportsAncestors => false;
+
public override List<string> GetUserDataKeys()
{
var list = base.GetUserDataKeys();
@@ -49,14 +69,6 @@ namespace MediaBrowser.Controller.Entities
return LibraryManager.GetItemList(query);
}
- /// <summary>
- /// Gets the folder containing the item.
- /// If the item is a folder, it returns the folder itself.
- /// </summary>
- /// <value>The containing folder path.</value>
- [JsonIgnore]
- public override string ContainingFolderPath => Path;
-
public override bool CanDelete()
{
return false;
@@ -67,18 +79,6 @@ namespace MediaBrowser.Controller.Entities
return true;
}
- /// <summary>
- /// Gets a value indicating whether to enable alpha numeric sorting.
- /// </summary>
- [JsonIgnore]
- public override bool EnableAlphaNumericSorting => false;
-
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
- [JsonIgnore]
- public override bool SupportsAncestors => false;
-
public static string GetPath(string name)
{
return GetPath(name, true);
@@ -129,6 +129,8 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
+ /// <param name="replaceAllMetadata"><c>true</c> to replace all metadata, <c>false</c> to not.</param>
+ /// <returns><c>true</c> if changes were made, <c>false</c> if not.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
diff --git a/MediaBrowser.Controller/Entities/PersonInfo.cs b/MediaBrowser.Controller/Entities/PersonInfo.cs
index fb79323f8..2b689ae7e 100644
--- a/MediaBrowser.Controller/Entities/PersonInfo.cs
+++ b/MediaBrowser.Controller/Entities/PersonInfo.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA2227, CS1591
using System;
using System.Collections.Generic;
diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs
index 3312a0e3e..ba6ce189a 100644
--- a/MediaBrowser.Controller/Entities/Photo.cs
+++ b/MediaBrowser.Controller/Entities/Photo.cs
@@ -36,6 +36,30 @@ namespace MediaBrowser.Controller.Entities
}
}
+ public string CameraMake { get; set; }
+
+ public string CameraModel { get; set; }
+
+ public string Software { get; set; }
+
+ public double? ExposureTime { get; set; }
+
+ public double? FocalLength { get; set; }
+
+ public ImageOrientation? Orientation { get; set; }
+
+ public double? Aperture { get; set; }
+
+ public double? ShutterSpeed { get; set; }
+
+ public double? Latitude { get; set; }
+
+ public double? Longitude { get; set; }
+
+ public double? Altitude { get; set; }
+
+ public int? IsoSpeedRating { get; set; }
+
public override bool CanDownload()
{
return true;
@@ -69,29 +93,5 @@ namespace MediaBrowser.Controller.Entities
return base.GetDefaultPrimaryImageAspectRatio();
}
-
- public string CameraMake { get; set; }
-
- public string CameraModel { get; set; }
-
- public string Software { get; set; }
-
- public double? ExposureTime { get; set; }
-
- public double? FocalLength { get; set; }
-
- public ImageOrientation? Orientation { get; set; }
-
- public double? Aperture { get; set; }
-
- public double? ShutterSpeed { get; set; }
-
- public double? Latitude { get; set; }
-
- public double? Longitude { get; set; }
-
- public double? Altitude { get; set; }
-
- public int? IsoSpeedRating { get; set; }
}
}
diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs
index 6fd0a6c6c..c8feb1c94 100644
--- a/MediaBrowser.Controller/Entities/Studio.cs
+++ b/MediaBrowser.Controller/Entities/Studio.cs
@@ -5,7 +5,7 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
-using MediaBrowser.Controller.Extensions;
+using Diacritics.Extensions;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities
@@ -15,19 +15,6 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Studio : BaseItem, IItemByName
{
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
-
- list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
- return list;
- }
-
- public override string CreatePresentationUniqueKey()
- {
- return GetUserDataKeys()[0];
- }
-
/// <summary>
/// Gets the folder containing the item.
/// If the item is a folder, it returns the folder itself.
@@ -42,6 +29,22 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override bool SupportsAncestors => false;
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, GetType().Name + "-" + (Name ?? string.Empty).RemoveDiacritics());
+ return list;
+ }
+
+ public override string CreatePresentationUniqueKey()
+ {
+ return GetUserDataKeys()[0];
+ }
+
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 16;
@@ -67,9 +70,6 @@ namespace MediaBrowser.Controller.Entities
return LibraryManager.GetItemList(query);
}
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
public static string GetPath(string name)
{
return GetPath(name, true);
@@ -105,6 +105,8 @@ namespace MediaBrowser.Controller.Entities
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
+ /// <param name="replaceAllMetadata"><c>true</c> to replace all metadata, <c>false</c> to not.</param>
+ /// <returns><c>true</c> if changes were made, <c>false</c> if not.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
var hasChanges = base.BeforeMetadataRefresh(replaceAllMetadata);
diff --git a/MediaBrowser.Controller/Entities/TV/Episode.cs b/MediaBrowser.Controller/Entities/TV/Episode.cs
index 31c179bca..dcc752f8c 100644
--- a/MediaBrowser.Controller/Entities/TV/Episode.cs
+++ b/MediaBrowser.Controller/Entities/TV/Episode.cs
@@ -20,18 +20,10 @@ namespace MediaBrowser.Controller.Entities.TV
/// </summary>
public class Episode : Video, IHasTrailers, IHasLookupInfo<EpisodeInfo>, IHasSeries
{
- public Episode()
- {
- RemoteTrailers = Array.Empty<MediaUrl>();
- LocalTrailerIds = Array.Empty<Guid>();
- RemoteTrailerIds = Array.Empty<Guid>();
- }
-
- /// <inheritdoc />
- public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
-
/// <inheritdoc />
- public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
+ public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
+ .ToArray();
/// <summary>
/// Gets or sets the season in which it aired.
@@ -49,12 +41,6 @@ namespace MediaBrowser.Controller.Entities.TV
/// <value>The index number.</value>
public int? IndexNumberEnd { get; set; }
- public string FindSeriesSortName()
- {
- var series = Series;
- return series == null ? SeriesName : series.SortName;
- }
-
[JsonIgnore]
protected override bool SupportsOwnedItems => IsStacked || MediaSourceCount > 1;
@@ -76,45 +62,6 @@ namespace MediaBrowser.Controller.Entities.TV
[JsonIgnore]
protected override bool EnableDefaultVideoUserDataKeys => false;
- public override double GetDefaultPrimaryImageAspectRatio()
- {
- // hack for tv plugins
- if (SourceType == SourceType.Channel)
- {
- return 0;
- }
-
- return 16.0 / 9;
- }
-
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
-
- var series = Series;
- if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
- {
- var seriesUserDataKeys = series.GetUserDataKeys();
- var take = seriesUserDataKeys.Count;
- if (seriesUserDataKeys.Count > 1)
- {
- take--;
- }
-
- var newList = seriesUserDataKeys.GetRange(0, take);
- var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
- for (int i = 0; i < take; i++)
- {
- newList[i] = newList[i] + suffix;
- }
-
- newList.AddRange(list);
- list = newList;
- }
-
- return list;
- }
-
/// <summary>
/// Gets the Episode's Series Instance.
/// </summary>
@@ -161,6 +108,74 @@ namespace MediaBrowser.Controller.Entities.TV
[JsonIgnore]
public string SeasonName { get; set; }
+ [JsonIgnore]
+ public override bool SupportsRemoteImageDownloading
+ {
+ get
+ {
+ if (IsMissingEpisode)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ [JsonIgnore]
+ public bool IsMissingEpisode => LocationType == LocationType.Virtual;
+
+ [JsonIgnore]
+ public Guid SeasonId { get; set; }
+
+ [JsonIgnore]
+ public Guid SeriesId { get; set; }
+
+ public string FindSeriesSortName()
+ {
+ var series = Series;
+ return series == null ? SeriesName : series.SortName;
+ }
+
+ public override double GetDefaultPrimaryImageAspectRatio()
+ {
+ // hack for tv plugins
+ if (SourceType == SourceType.Channel)
+ {
+ return 0;
+ }
+
+ return 16.0 / 9;
+ }
+
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ var series = Series;
+ if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue)
+ {
+ var seriesUserDataKeys = series.GetUserDataKeys();
+ var take = seriesUserDataKeys.Count;
+ if (seriesUserDataKeys.Count > 1)
+ {
+ take--;
+ }
+
+ var newList = seriesUserDataKeys.GetRange(0, take);
+ var suffix = ParentIndexNumber.Value.ToString("000", CultureInfo.InvariantCulture) + IndexNumber.Value.ToString("000", CultureInfo.InvariantCulture);
+ for (int i = 0; i < take; i++)
+ {
+ newList[i] = newList[i] + suffix;
+ }
+
+ newList.AddRange(list);
+ list = newList;
+ }
+
+ return list;
+ }
+
public string FindSeriesPresentationUniqueKey()
{
var series = Series;
@@ -242,29 +257,6 @@ namespace MediaBrowser.Controller.Entities.TV
return false;
}
- [JsonIgnore]
- public override bool SupportsRemoteImageDownloading
- {
- get
- {
- if (IsMissingEpisode)
- {
- return false;
- }
-
- return true;
- }
- }
-
- [JsonIgnore]
- public bool IsMissingEpisode => LocationType == LocationType.Virtual;
-
- [JsonIgnore]
- public Guid SeasonId { get; set; }
-
- [JsonIgnore]
- public Guid SeriesId { get; set; }
-
public Guid FindSeriesId()
{
var series = FindParent<Series>();
diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs
index aa62bb35b..926c7b045 100644
--- a/MediaBrowser.Controller/Entities/TV/Season.cs
+++ b/MediaBrowser.Controller/Entities/TV/Season.cs
@@ -38,6 +38,50 @@ namespace MediaBrowser.Controller.Entities.TV
[JsonIgnore]
public override Guid DisplayParentId => SeriesId;
+ /// <summary>
+ /// Gets this Episode's Series Instance.
+ /// </summary>
+ /// <value>The series.</value>
+ [JsonIgnore]
+ public Series Series
+ {
+ get
+ {
+ var seriesId = SeriesId;
+ if (seriesId == Guid.Empty)
+ {
+ seriesId = FindSeriesId();
+ }
+
+ return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series);
+ }
+ }
+
+ [JsonIgnore]
+ public string SeriesPath
+ {
+ get
+ {
+ var series = Series;
+
+ if (series != null)
+ {
+ return series.Path;
+ }
+
+ return System.IO.Path.GetDirectoryName(Path);
+ }
+ }
+
+ [JsonIgnore]
+ public string SeriesPresentationUniqueKey { get; set; }
+
+ [JsonIgnore]
+ public string SeriesName { get; set; }
+
+ [JsonIgnore]
+ public Guid SeriesId { get; set; }
+
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
@@ -80,41 +124,6 @@ namespace MediaBrowser.Controller.Entities.TV
return result;
}
- /// <summary>
- /// Gets this Episode's Series Instance.
- /// </summary>
- /// <value>The series.</value>
- [JsonIgnore]
- public Series Series
- {
- get
- {
- var seriesId = SeriesId;
- if (seriesId == Guid.Empty)
- {
- seriesId = FindSeriesId();
- }
-
- return seriesId == Guid.Empty ? null : (LibraryManager.GetItemById(seriesId) as Series);
- }
- }
-
- [JsonIgnore]
- public string SeriesPath
- {
- get
- {
- var series = Series;
-
- if (series != null)
- {
- return series.Path;
- }
-
- return System.IO.Path.GetDirectoryName(Path);
- }
- }
-
public override string CreatePresentationUniqueKey()
{
if (IndexNumber.HasValue)
@@ -157,6 +166,9 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Gets the episodes.
/// </summary>
+ /// <param name="user">The user.</param>
+ /// <param name="options">The options to use.</param>
+ /// <returns>Set of episodes.</returns>
public List<BaseItem> GetEpisodes(User user, DtoOptions options)
{
return GetEpisodes(Series, user, options);
@@ -193,15 +205,6 @@ namespace MediaBrowser.Controller.Entities.TV
return UnratedItem.Series;
}
- [JsonIgnore]
- public string SeriesPresentationUniqueKey { get; set; }
-
- [JsonIgnore]
- public string SeriesName { get; set; }
-
- [JsonIgnore]
- public Guid SeriesId { get; set; }
-
public string FindSeriesPresentationUniqueKey()
{
var series = Series;
@@ -241,6 +244,7 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// This is called before any metadata refresh and returns true or false indicating if changes were made.
/// </summary>
+ /// <param name="replaceAllMetadata"><c>true</c> to replace metdata, <c>false</c> to not.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
{
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 44d07b4a4..bdadc2775 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -27,9 +27,6 @@ namespace MediaBrowser.Controller.Entities.TV
{
public Series()
{
- RemoteTrailers = Array.Empty<MediaUrl>();
- LocalTrailerIds = Array.Empty<Guid>();
- RemoteTrailerIds = Array.Empty<Guid>();
AirDays = Array.Empty<DayOfWeek>();
}
@@ -53,10 +50,9 @@ namespace MediaBrowser.Controller.Entities.TV
public override bool SupportsPeople => true;
/// <inheritdoc />
- public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
-
- /// <inheritdoc />
- public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
+ public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
+ .Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
+ .ToArray();
/// <summary>
/// Gets or sets the display order.
@@ -72,6 +68,9 @@ namespace MediaBrowser.Controller.Entities.TV
/// <value>The status.</value>
public SeriesStatus? Status { get; set; }
+ [JsonIgnore]
+ public override bool StopRefreshIfLocalMetadataFound => false;
+
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
@@ -128,7 +127,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Season) },
+ IncludeItemTypes = new[] { BaseItemKind.Season },
IsVirtualItem = false,
Limit = 0,
DtoOptions = new DtoOptions(false)
@@ -156,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
}
query.IsVirtualItem = false;
@@ -210,7 +209,7 @@ namespace MediaBrowser.Controller.Entities.TV
query.AncestorWithPresentationUniqueKey = null;
query.SeriesPresentationUniqueKey = seriesKey;
- query.IncludeItemTypes = new[] { nameof(Season) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Season };
query.OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) };
if (user != null && !user.DisplayMissingEpisodes)
@@ -236,7 +235,7 @@ namespace MediaBrowser.Controller.Entities.TV
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Episode), nameof(Season) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season };
}
query.IsVirtualItem = false;
@@ -256,7 +255,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { nameof(Episode), nameof(Season) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
@@ -293,7 +292,7 @@ namespace MediaBrowser.Controller.Entities.TV
// Refresh seasons
foreach (var item in items)
{
- if (!(item is Season))
+ if (item is not Season)
{
continue;
}
@@ -360,7 +359,7 @@ namespace MediaBrowser.Controller.Entities.TV
{
AncestorWithPresentationUniqueKey = queryFromSeries ? null : seriesKey,
SeriesPresentationUniqueKey = queryFromSeries ? seriesKey : null,
- IncludeItemTypes = new[] { nameof(Episode) },
+ IncludeItemTypes = new[] { BaseItemKind.Episode },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
};
@@ -394,6 +393,10 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Filters the episodes by season.
/// </summary>
+ /// <param name="episodes">The episodes.</param>
+ /// <param name="parentSeason">The season.</param>
+ /// <param name="includeSpecials"><c>true</c> to include special, <c>false</c> to not.</param>
+ /// <returns>The set of episodes.</returns>
public static IEnumerable<BaseItem> FilterEpisodesBySeason(IEnumerable<BaseItem> episodes, Season parentSeason, bool includeSpecials)
{
var seasonNumber = parentSeason.IndexNumber;
@@ -424,6 +427,10 @@ namespace MediaBrowser.Controller.Entities.TV
/// <summary>
/// Filters the episodes by season.
/// </summary>
+ /// <param name="episodes">The episodes.</param>
+ /// <param name="seasonNumber">The season.</param>
+ /// <param name="includeSpecials"><c>true</c> to include special, <c>false</c> to not.</param>
+ /// <returns>The set of episodes.</returns>
public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, int seasonNumber, bool includeSpecials)
{
if (!includeSpecials || seasonNumber < 1)
@@ -499,8 +506,5 @@ namespace MediaBrowser.Controller.Entities.TV
return list;
}
-
- [JsonIgnore]
- public override bool StopRefreshIfLocalMetadataFound => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/TagExtensions.cs b/MediaBrowser.Controller/Entities/TagExtensions.cs
index 2ce396daf..ec3eb0f70 100644
--- a/MediaBrowser.Controller/Entities/TagExtensions.cs
+++ b/MediaBrowser.Controller/Entities/TagExtensions.cs
@@ -2,6 +2,7 @@
using System;
using System.Linq;
+using Jellyfin.Extensions;
namespace MediaBrowser.Controller.Entities
{
@@ -16,7 +17,7 @@ namespace MediaBrowser.Controller.Entities
var current = item.Tags;
- if (!current.Contains(name, StringComparer.OrdinalIgnoreCase))
+ if (!current.Contains(name, StringComparison.OrdinalIgnoreCase))
{
if (current.Length == 0)
{
diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs
index 732b45521..1c558d419 100644
--- a/MediaBrowser.Controller/Entities/Trailer.cs
+++ b/MediaBrowser.Controller/Entities/Trailer.cs
@@ -1,6 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+#pragma warning disable CA1819, CS1591
using System;
using System.Collections.Generic;
@@ -23,6 +23,9 @@ namespace MediaBrowser.Controller.Entities
TrailerTypes = Array.Empty<TrailerType>();
}
+ [JsonIgnore]
+ public override bool StopRefreshIfLocalMetadataFound => false;
+
public TrailerType[] TrailerTypes { get; set; }
public override double GetDefaultPrimaryImageAspectRatio()
@@ -97,8 +100,5 @@ namespace MediaBrowser.Controller.Entities
return list;
}
-
- [JsonIgnore]
- public override bool StopRefreshIfLocalMetadataFound => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/UserItemData.cs b/MediaBrowser.Controller/Entities/UserItemData.cs
index 6ab2116d7..50ba9ef30 100644
--- a/MediaBrowser.Controller/Entities/UserItemData.cs
+++ b/MediaBrowser.Controller/Entities/UserItemData.cs
@@ -12,6 +12,13 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class UserItemData
{
+ public const double MinLikeValue = 6.5;
+
+ /// <summary>
+ /// The _rating.
+ /// </summary>
+ private double? _rating;
+
/// <summary>
/// Gets or sets the user id.
/// </summary>
@@ -25,11 +32,6 @@ namespace MediaBrowser.Controller.Entities
public string Key { get; set; }
/// <summary>
- /// The _rating.
- /// </summary>
- private double? _rating;
-
- /// <summary>
/// Gets or sets the users 0-10 rating.
/// </summary>
/// <value>The rating.</value>
@@ -93,8 +95,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The index of the subtitle stream.</value>
public int? SubtitleStreamIndex { get; set; }
- public const double MinLikeValue = 6.5;
-
/// <summary>
/// Gets or sets a value indicating whether the item is liked or not.
/// This should never be serialized.
diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs
index 2b15a52f0..e547db523 100644
--- a/MediaBrowser.Controller/Entities/UserRootFolder.cs
+++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs
@@ -21,22 +21,15 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class UserRootFolder : Folder
{
- private List<Guid> _childrenIds = null;
private readonly object _childIdsLock = new object();
+ private List<Guid> _childrenIds = null;
- protected override List<BaseItem> LoadChildren()
+ /// <summary>
+ /// Initializes a new instance of the <see cref="UserRootFolder"/> class.
+ /// </summary>
+ public UserRootFolder()
{
- lock (_childIdsLock)
- {
- if (_childrenIds == null)
- {
- var list = base.LoadChildren();
- _childrenIds = list.Select(i => i.Id).ToList();
- return list;
- }
-
- return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList();
- }
+ IsRoot = true;
}
[JsonIgnore]
@@ -45,6 +38,12 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override bool SupportsPlayedStatus => false;
+ [JsonIgnore]
+ protected override bool SupportsShortcutChildren => true;
+
+ [JsonIgnore]
+ public override bool IsPreSorted => true;
+
private void ClearCache()
{
lock (_childIdsLock)
@@ -53,6 +52,21 @@ namespace MediaBrowser.Controller.Entities
}
}
+ protected override List<BaseItem> LoadChildren()
+ {
+ lock (_childIdsLock)
+ {
+ if (_childrenIds == null)
+ {
+ var list = base.LoadChildren();
+ _childrenIds = list.Select(i => i.Id).ToList();
+ return list;
+ }
+
+ return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList();
+ }
+ }
+
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
{
if (query.Recursive)
@@ -74,12 +88,6 @@ namespace MediaBrowser.Controller.Entities
return GetChildren(user, true).Count;
}
- [JsonIgnore]
- protected override bool SupportsShortcutChildren => true;
-
- [JsonIgnore]
- public override bool IsPreSorted => true;
-
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
{
var list = base.GetEligibleChildrenForRecursiveChildren(user).ToList();
diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs
index 57dc9b59b..5c9be7337 100644
--- a/MediaBrowser.Controller/Entities/UserView.cs
+++ b/MediaBrowser.Controller/Entities/UserView.cs
@@ -8,6 +8,7 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Querying;
@@ -15,6 +16,25 @@ namespace MediaBrowser.Controller.Entities
{
public class UserView : Folder, IHasCollectionType
{
+ private static readonly string[] _viewTypesEligibleForGrouping = new string[]
+ {
+ Model.Entities.CollectionType.Movies,
+ Model.Entities.CollectionType.TvShows,
+ string.Empty
+ };
+
+ private static readonly string[] _originalFolderViewTypes = new string[]
+ {
+ Model.Entities.CollectionType.Books,
+ Model.Entities.CollectionType.MusicVideos,
+ Model.Entities.CollectionType.HomeVideos,
+ Model.Entities.CollectionType.Photos,
+ Model.Entities.CollectionType.Music,
+ Model.Entities.CollectionType.BoxSets
+ };
+
+ public static ITVSeriesManager TVSeriesManager { get; set; }
+
/// <summary>
/// Gets or sets the view type.
/// </summary>
@@ -30,13 +50,23 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public Guid? UserId { get; set; }
- public static ITVSeriesManager TVSeriesManager;
-
/// <inheritdoc />
[JsonIgnore]
public string CollectionType => ViewType;
/// <inheritdoc />
+ [JsonIgnore]
+ public override bool SupportsInheritedParentImages => false;
+
+ /// <inheritdoc />
+ [JsonIgnore]
+ public override bool SupportsPlayedStatus => false;
+
+ /// <inheritdoc />
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
+
+ /// <inheritdoc />
public override IEnumerable<Guid> GetIdsForAncestorQuery()
{
if (!DisplayParentId.Equals(Guid.Empty))
@@ -53,17 +83,13 @@ namespace MediaBrowser.Controller.Entities
}
}
- [JsonIgnore]
- public override bool SupportsInheritedParentImages => false;
-
- [JsonIgnore]
- public override bool SupportsPlayedStatus => false;
-
+ /// <inheritdoc />
public override int GetChildCount(User user)
{
return GetChildren(user, true).Count;
}
+ /// <inheritdoc />
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
{
var parent = this as Folder;
@@ -77,10 +103,11 @@ namespace MediaBrowser.Controller.Entities
parent = LibraryManager.GetItemById(ParentId) as Folder ?? parent;
}
- return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager, ConfigurationManager)
+ return new UserViewBuilder(UserViewManager, LibraryManager, Logger, UserDataManager, TVSeriesManager)
.GetUserItems(parent, this, CollectionType, query);
}
+ /// <inheritdoc />
public override List<BaseItem> GetChildren(User user, bool includeLinkedChildren, InternalItemsQuery query)
{
query ??= new InternalItemsQuery(user);
@@ -91,16 +118,19 @@ namespace MediaBrowser.Controller.Entities
return result.ToList();
}
+ /// <inheritdoc />
public override bool CanDelete()
{
return false;
}
+ /// <inheritdoc />
public override bool IsSaveLocalMetadataEnabled()
{
return true;
}
+ /// <inheritdoc />
public override IEnumerable<BaseItem> GetRecursiveChildren(User user, InternalItemsQuery query)
{
query.SetUser(user);
@@ -111,32 +141,26 @@ namespace MediaBrowser.Controller.Entities
return GetItemList(query);
}
+ /// <inheritdoc />
protected override IEnumerable<BaseItem> GetEligibleChildrenForRecursiveChildren(User user)
{
return GetChildren(user, false);
}
- private static readonly string[] UserSpecificViewTypes = new string[]
- {
- Model.Entities.CollectionType.Playlists
- };
-
public static bool IsUserSpecific(Folder folder)
{
- var collectionFolder = folder as ICollectionFolder;
-
- if (collectionFolder == null)
+ if (folder is not ICollectionFolder collectionFolder)
{
return false;
}
- var supportsUserSpecific = folder as ISupportsUserSpecificView;
- if (supportsUserSpecific != null && supportsUserSpecific.EnableUserSpecificView)
+ if (folder is ISupportsUserSpecificView supportsUserSpecific
+ && supportsUserSpecific.EnableUserSpecificView)
{
return true;
}
- return UserSpecificViewTypes.Contains(collectionFolder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ return string.Equals(Model.Entities.CollectionType.Playlists, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase);
}
public static bool IsEligibleForGrouping(Folder folder)
@@ -145,39 +169,19 @@ namespace MediaBrowser.Controller.Entities
&& IsEligibleForGrouping(collectionFolder.CollectionType);
}
- private static string[] ViewTypesEligibleForGrouping = new string[]
- {
- Model.Entities.CollectionType.Movies,
- Model.Entities.CollectionType.TvShows,
- string.Empty
- };
-
public static bool IsEligibleForGrouping(string viewType)
{
- return ViewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ return _viewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
- private static string[] OriginalFolderViewTypes = new string[]
- {
- Model.Entities.CollectionType.Books,
- Model.Entities.CollectionType.MusicVideos,
- Model.Entities.CollectionType.HomeVideos,
- Model.Entities.CollectionType.Photos,
- Model.Entities.CollectionType.Music,
- Model.Entities.CollectionType.BoxSets
- };
-
public static bool EnableOriginalFolder(string viewType)
{
- return OriginalFolderViewTypes.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ return _originalFolderViewTypes.Contains(viewType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
protected override Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshChildMetadata, Providers.MetadataRefreshOptions refreshOptions, Providers.IDirectoryService directoryService, System.Threading.CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
-
- [JsonIgnore]
- public override bool SupportsPeople => false;
}
}
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
index add734f62..fe44f1169 100644
--- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs
+++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs
@@ -8,8 +8,7 @@ using System.Globalization;
using System.Linq;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities.Movies;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Entities;
@@ -17,8 +16,6 @@ using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
-using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
-using Season = MediaBrowser.Controller.Entities.TV.Season;
using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace MediaBrowser.Controller.Entities
@@ -30,22 +27,19 @@ namespace MediaBrowser.Controller.Entities
private readonly ILogger<BaseItem> _logger;
private readonly IUserDataManager _userDataManager;
private readonly ITVSeriesManager _tvSeriesManager;
- private readonly IServerConfigurationManager _config;
public UserViewBuilder(
IUserViewManager userViewManager,
ILibraryManager libraryManager,
ILogger<BaseItem> logger,
IUserDataManager userDataManager,
- ITVSeriesManager tvSeriesManager,
- IServerConfigurationManager config)
+ ITVSeriesManager tvSeriesManager)
{
_userViewManager = userViewManager;
_libraryManager = libraryManager;
_logger = logger;
_userDataManager = userDataManager;
_tvSeriesManager = tvSeriesManager;
- _config = config;
}
public QueryResult<BaseItem> GetUserItems(Folder queryParent, Folder displayParent, string viewType, InternalItemsQuery query)
@@ -65,7 +59,7 @@ namespace MediaBrowser.Controller.Entities
switch (viewType)
{
case CollectionType.Folders:
- return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), queryParent, query);
+ return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query);
case CollectionType.TvShows:
return GetTvView(queryParent, user, query);
@@ -110,7 +104,7 @@ namespace MediaBrowser.Controller.Entities
return GetMovieMovies(queryParent, user, query);
case SpecialFolder.MovieCollections:
- return GetMovieCollections(queryParent, user, query);
+ return GetMovieCollections(user, query);
case SpecialFolder.TvFavoriteEpisodes:
return GetFavoriteEpisodes(queryParent, user, query);
@@ -122,7 +116,7 @@ namespace MediaBrowser.Controller.Entities
{
if (queryParent is UserView)
{
- return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), queryParent, query);
+ return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, true)), query);
}
return queryParent.GetItems(query);
@@ -144,7 +138,7 @@ namespace MediaBrowser.Controller.Entities
if (query.IncludeItemTypes.Length == 0)
{
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
}
return parent.QueryRecursive(query);
@@ -160,7 +154,7 @@ namespace MediaBrowser.Controller.Entities
GetUserView(SpecialFolder.MovieGenres, "Genres", "5", parent)
};
- return GetResult(list, parent, query);
+ return GetResult(list, query);
}
private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
@@ -169,7 +163,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -180,7 +174,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -191,7 +185,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IsFavorite = true;
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
return _libraryManager.GetItemsResult(query);
}
@@ -202,15 +196,15 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
- private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query)
+ private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
{
query.Parent = null;
- query.IncludeItemTypes = new[] { nameof(BoxSet) };
+ query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
query.SetUser(user);
query.Recursive = true;
@@ -224,7 +218,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -237,7 +231,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -256,7 +250,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Movie) },
+ IncludeItemTypes = new[] { BaseItemKind.Movie },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -275,9 +269,9 @@ namespace MediaBrowser.Controller.Entities
}
})
.Where(i => i != null)
- .Select(i => GetUserViewWithName(i.Name, SpecialFolder.MovieGenre, i.SortName, parent));
+ .Select(i => GetUserViewWithName(SpecialFolder.MovieGenre, i.SortName, parent));
- return GetResult(genres, parent, query);
+ return GetResult(genres, query);
}
private QueryResult<BaseItem> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
@@ -287,7 +281,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Movie) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -303,9 +297,9 @@ namespace MediaBrowser.Controller.Entities
{
query.IncludeItemTypes = new[]
{
- nameof(Series),
- nameof(Season),
- nameof(Episode)
+ BaseItemKind.Series,
+ BaseItemKind.Season,
+ BaseItemKind.Episode
};
}
@@ -323,7 +317,7 @@ namespace MediaBrowser.Controller.Entities
GetUserView(SpecialFolder.TvGenres, "Genres", "6", parent)
};
- return GetResult(list, parent, query);
+ return GetResult(list, query);
}
private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
@@ -333,7 +327,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
query.IsVirtualItem = false;
return ConvertToResult(_libraryManager.GetItemList(query));
@@ -364,7 +358,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.Limit = GetSpecialItemsLimit();
- query.IncludeItemTypes = new[] { nameof(Episode) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Episode };
return ConvertToResult(_libraryManager.GetItemList(query));
}
@@ -375,7 +369,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -384,7 +378,7 @@ namespace MediaBrowser.Controller.Entities
{
var genres = parent.QueryRecursive(new InternalItemsQuery(user)
{
- IncludeItemTypes = new[] { nameof(Series) },
+ IncludeItemTypes = new[] { BaseItemKind.Series },
Recursive = true,
EnableTotalRecordCount = false
}).Items
@@ -403,9 +397,9 @@ namespace MediaBrowser.Controller.Entities
}
})
.Where(i => i != null)
- .Select(i => GetUserViewWithName(i.Name, SpecialFolder.TvGenre, i.SortName, parent));
+ .Select(i => GetUserViewWithName(SpecialFolder.TvGenre, i.SortName, parent));
- return GetResult(genres, parent, query);
+ return GetResult(genres, query);
}
private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query)
@@ -415,7 +409,7 @@ namespace MediaBrowser.Controller.Entities
query.GenreIds = new[] { displayParent.Id };
query.SetUser(user);
- query.IncludeItemTypes = new[] { nameof(Series) };
+ query.IncludeItemTypes = new[] { BaseItemKind.Series };
return _libraryManager.GetItemsResult(query);
}
@@ -432,13 +426,12 @@ namespace MediaBrowser.Controller.Entities
private QueryResult<BaseItem> GetResult<T>(
IEnumerable<T> items,
- BaseItem queryParent,
InternalItemsQuery query)
where T : BaseItem
{
items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
- return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config);
+ return PostFilterAndSort(items, null, query, _libraryManager);
}
public static bool FilterItem(BaseItem item, InternalItemsQuery query)
@@ -448,11 +441,9 @@ namespace MediaBrowser.Controller.Entities
public static QueryResult<BaseItem> PostFilterAndSort(
IEnumerable<BaseItem> items,
- BaseItem queryParent,
int? totalRecordLimit,
InternalItemsQuery query,
- ILibraryManager libraryManager,
- IServerConfigurationManager configurationManager)
+ ILibraryManager libraryManager)
{
var user = query.User;
@@ -501,17 +492,17 @@ namespace MediaBrowser.Controller.Entities
public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager)
{
- if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparison.OrdinalIgnoreCase))
{
return false;
}
- if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
+ if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
{
return false;
}
- if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
+ if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
{
return false;
}
@@ -752,10 +743,9 @@ namespace MediaBrowser.Controller.Entities
var val = query.HasTrailer.Value;
var trailerCount = 0;
- var hasTrailers = item as IHasTrailers;
- if (hasTrailers != null)
+ if (item is IHasTrailers hasTrailers)
{
- trailerCount = hasTrailers.GetTrailerIds().Count;
+ trailerCount = hasTrailers.GetTrailerCount();
}
var ok = val ? trailerCount > 0 : trailerCount == 0;
@@ -770,7 +760,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeSong.Value;
- var themeCount = item.ThemeSongIds.Length;
+ var themeCount = item.GetThemeSongs().Count;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -783,7 +773,7 @@ namespace MediaBrowser.Controller.Entities
{
var filterValue = query.HasThemeVideo.Value;
- var themeCount = item.ThemeVideoIds.Length;
+ var themeCount = item.GetThemeVideos().Count;
var ok = filterValue ? themeCount > 0 : themeCount == 0;
if (!ok)
@@ -793,7 +783,7 @@ namespace MediaBrowser.Controller.Entities
}
// Apply genre filter
- if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
+ if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
@@ -817,7 +807,7 @@ namespace MediaBrowser.Controller.Entities
if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
{
var studioItem = libraryManager.GetItemById(id);
- return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparer.OrdinalIgnoreCase);
+ return studioItem != null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCase);
}))
{
return false;
@@ -827,7 +817,7 @@ namespace MediaBrowser.Controller.Entities
if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
{
var genreItem = libraryManager.GetItemById(id);
- return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparer.OrdinalIgnoreCase);
+ return genreItem != null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase);
}))
{
return false;
@@ -860,7 +850,7 @@ namespace MediaBrowser.Controller.Entities
var tags = query.Tags;
if (tags.Length > 0)
{
- if (!tags.Any(v => item.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))
+ if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
{
return false;
}
@@ -978,7 +968,7 @@ namespace MediaBrowser.Controller.Entities
{
var folder = i as ICollectionFolder;
- return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}).ToArray();
}
@@ -987,7 +977,7 @@ namespace MediaBrowser.Controller.Entities
{
var folder = i as ICollectionFolder;
- return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
+ return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}).ToArray();
}
@@ -1001,7 +991,7 @@ namespace MediaBrowser.Controller.Entities
return new BaseItem[] { parent };
}
- private UserView GetUserViewWithName(string name, string type, string sortName, BaseItem parent)
+ private UserView GetUserViewWithName(string type, string sortName, BaseItem parent)
{
return _userViewManager.GetUserSubView(parent.Id, parent.Id.ToString("N", CultureInfo.InvariantCulture), type, sortName);
}
diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs
index d05b5df2f..4f7614f96 100644
--- a/MediaBrowser.Controller/Entities/Video.cs
+++ b/MediaBrowser.Controller/Entities/Video.cs
@@ -9,6 +9,7 @@ using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
@@ -28,6 +29,15 @@ namespace MediaBrowser.Controller.Entities
ISupportsPlaceHolders,
IHasMediaSources
{
+ public Video()
+ {
+ AdditionalParts = Array.Empty<string>();
+ LocalAlternateVersions = Array.Empty<string>();
+ SubtitleFiles = Array.Empty<string>();
+ AudioFiles = Array.Empty<string>();
+ LinkedAlternateVersions = Array.Empty<LinkedChild>();
+ }
+
[JsonIgnore]
public string PrimaryVersionId { get; set; }
@@ -74,30 +84,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- public void SetPrimaryVersionId(string id)
- {
- if (string.IsNullOrEmpty(id))
- {
- PrimaryVersionId = null;
- }
- else
- {
- PrimaryVersionId = id;
- }
-
- PresentationUniqueKey = CreatePresentationUniqueKey();
- }
-
- public override string CreatePresentationUniqueKey()
- {
- if (!string.IsNullOrEmpty(PrimaryVersionId))
- {
- return PrimaryVersionId;
- }
-
- return base.CreatePresentationUniqueKey();
- }
-
[JsonIgnore]
public override bool SupportsThemeMedia => true;
@@ -114,6 +100,12 @@ namespace MediaBrowser.Controller.Entities
public string[] SubtitleFiles { get; set; }
/// <summary>
+ /// Gets or sets the audio paths.
+ /// </summary>
+ /// <value>The audio paths.</value>
+ public string[] AudioFiles { get; set; }
+
+ /// <summary>
/// Gets or sets a value indicating whether this instance has subtitles.
/// </summary>
/// <value><c>true</c> if this instance has subtitles; otherwise, <c>false</c>.</value>
@@ -151,24 +143,6 @@ namespace MediaBrowser.Controller.Entities
/// <value>The aspect ratio.</value>
public string AspectRatio { get; set; }
- public Video()
- {
- AdditionalParts = Array.Empty<string>();
- LocalAlternateVersions = Array.Empty<string>();
- SubtitleFiles = Array.Empty<string>();
- LinkedAlternateVersions = Array.Empty<LinkedChild>();
- }
-
- public override bool CanDownload()
- {
- if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
- {
- return false;
- }
-
- return IsFileProtocol;
- }
-
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
@@ -196,16 +170,6 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override bool HasLocalAlternateVersions => LocalAlternateVersions.Length > 0;
- public IEnumerable<Guid> GetAdditionalPartIds()
- {
- return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
- }
-
- public IEnumerable<Guid> GetLocalAlternateVersionIds()
- {
- return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
- }
-
public static ILiveTvManager LiveTvManager { get; set; }
[JsonIgnore]
@@ -222,37 +186,77 @@ namespace MediaBrowser.Controller.Entities
}
}
- protected override bool IsActiveRecording()
+ [JsonIgnore]
+ public bool IsCompleteMedia
{
- return LiveTvManager.GetActiveRecordingInfo(Path) != null;
+ get
+ {
+ if (SourceType == SourceType.Channel)
+ {
+ return !Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase);
+ }
+
+ return !IsActiveRecording();
+ }
}
- public override bool CanDelete()
+ [JsonIgnore]
+ protected virtual bool EnableDefaultVideoUserDataKeys => true;
+
+ [JsonIgnore]
+ public override string ContainingFolderPath
{
- if (IsActiveRecording())
+ get
{
- return false;
- }
+ if (IsStacked)
+ {
+ return System.IO.Path.GetDirectoryName(Path);
+ }
- return base.CanDelete();
+ if (!IsPlaceHolder)
+ {
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
+ {
+ return Path;
+ }
+ }
+
+ return base.ContainingFolderPath;
+ }
}
[JsonIgnore]
- public bool IsCompleteMedia
+ public override string FileNameWithoutExtension
{
get
{
- if (SourceType == SourceType.Channel)
+ if (IsFileProtocol)
{
- return !Tags.Contains("livestream", StringComparer.OrdinalIgnoreCase);
+ if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
+ {
+ return System.IO.Path.GetFileName(Path);
+ }
+
+ return System.IO.Path.GetFileNameWithoutExtension(Path);
}
- return !IsActiveRecording();
+ return null;
}
}
+ /// <summary>
+ /// Gets a value indicating whether [is3 D].
+ /// </summary>
+ /// <value><c>true</c> if [is3 D]; otherwise, <c>false</c>.</value>
[JsonIgnore]
- protected virtual bool EnableDefaultVideoUserDataKeys => true;
+ public bool Is3D => Video3DFormat.HasValue;
+
+ /// <summary>
+ /// Gets the type of the media.
+ /// </summary>
+ /// <value>The type of the media.</value>
+ [JsonIgnore]
+ public override string MediaType => Model.Entities.MediaType.Video;
public override List<string> GetUserDataKeys()
{
@@ -293,6 +297,65 @@ namespace MediaBrowser.Controller.Entities
return list;
}
+ public void SetPrimaryVersionId(string id)
+ {
+ if (string.IsNullOrEmpty(id))
+ {
+ PrimaryVersionId = null;
+ }
+ else
+ {
+ PrimaryVersionId = id;
+ }
+
+ PresentationUniqueKey = CreatePresentationUniqueKey();
+ }
+
+ public override string CreatePresentationUniqueKey()
+ {
+ if (!string.IsNullOrEmpty(PrimaryVersionId))
+ {
+ return PrimaryVersionId;
+ }
+
+ return base.CreatePresentationUniqueKey();
+ }
+
+ public override bool CanDownload()
+ {
+ if (VideoType == VideoType.Dvd || VideoType == VideoType.BluRay)
+ {
+ return false;
+ }
+
+ return IsFileProtocol;
+ }
+
+ protected override bool IsActiveRecording()
+ {
+ return LiveTvManager.GetActiveRecordingInfo(Path) != null;
+ }
+
+ public override bool CanDelete()
+ {
+ if (IsActiveRecording())
+ {
+ return false;
+ }
+
+ return base.CanDelete();
+ }
+
+ public IEnumerable<Guid> GetAdditionalPartIds()
+ {
+ return AdditionalParts.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
+ }
+
+ public IEnumerable<Guid> GetLocalAlternateVersionIds()
+ {
+ return LocalAlternateVersions.Select(i => LibraryManager.GetNewItemId(i, typeof(Video)));
+ }
+
private string GetUserDataKey(string providerId)
{
var key = providerId + "-" + ExtraType.ToString().ToLowerInvariant();
@@ -328,47 +391,6 @@ namespace MediaBrowser.Controller.Entities
.OrderBy(i => i.SortName);
}
- [JsonIgnore]
- public override string ContainingFolderPath
- {
- get
- {
- if (IsStacked)
- {
- return System.IO.Path.GetDirectoryName(Path);
- }
-
- if (!IsPlaceHolder)
- {
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
- {
- return Path;
- }
- }
-
- return base.ContainingFolderPath;
- }
- }
-
- [JsonIgnore]
- public override string FileNameWithoutExtension
- {
- get
- {
- if (IsFileProtocol)
- {
- if (VideoType == VideoType.BluRay || VideoType == VideoType.Dvd)
- {
- return System.IO.Path.GetFileName(Path);
- }
-
- return System.IO.Path.GetFileNameWithoutExtension(Path);
- }
-
- return null;
- }
- }
-
internal override ItemUpdateType UpdateFromResolvedItem(BaseItem newItem)
{
var updateType = base.UpdateFromResolvedItem(newItem);
@@ -397,20 +419,6 @@ namespace MediaBrowser.Controller.Entities
return updateType;
}
- /// <summary>
- /// Gets a value indicating whether [is3 D].
- /// </summary>
- /// <value><c>true</c> if [is3 D]; otherwise, <c>false</c>.</value>
- [JsonIgnore]
- public bool Is3D => Video3DFormat.HasValue;
-
- /// <summary>
- /// Gets the type of the media.
- /// </summary>
- /// <value>The type of the media.</value>
- [JsonIgnore]
- public override string MediaType => Model.Entities.MediaType.Video;
-
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
@@ -509,35 +517,35 @@ namespace MediaBrowser.Controller.Entities
}).FirstOrDefault();
}
- protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
+ protected override IEnumerable<(BaseItem, MediaSourceType)> GetAllItemsForMediaSources()
{
- var list = new List<Tuple<BaseItem, MediaSourceType>>();
+ var list = new List<(BaseItem, MediaSourceType)>
+ {
+ (this, MediaSourceType.Default)
+ };
- list.Add(new Tuple<BaseItem, MediaSourceType>(this, MediaSourceType.Default));
- list.AddRange(GetLinkedAlternateVersions().Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Grouping)));
+ list.AddRange(GetLinkedAlternateVersions().Select(i => ((BaseItem)i, MediaSourceType.Grouping)));
if (!string.IsNullOrEmpty(PrimaryVersionId))
{
- var primary = LibraryManager.GetItemById(PrimaryVersionId) as Video;
- if (primary != null)
+ if (LibraryManager.GetItemById(PrimaryVersionId) is Video primary)
{
var existingIds = list.Select(i => i.Item1.Id).ToList();
- list.Add(new Tuple<BaseItem, MediaSourceType>(primary, MediaSourceType.Grouping));
- list.AddRange(primary.GetLinkedAlternateVersions().Where(i => !existingIds.Contains(i.Id)).Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Grouping)));
+ list.Add((primary, MediaSourceType.Grouping));
+ list.AddRange(primary.GetLinkedAlternateVersions().Where(i => !existingIds.Contains(i.Id)).Select(i => ((BaseItem)i, MediaSourceType.Grouping)));
}
}
var localAlternates = list
.SelectMany(i =>
{
- var video = i.Item1 as Video;
- return video == null ? new List<Guid>() : video.GetLocalAlternateVersionIds();
+ return i.Item1 is Video video ? video.GetLocalAlternateVersionIds() : Enumerable.Empty<Guid>();
})
.Select(LibraryManager.GetItemById)
.Where(i => i != null)
.ToList();
- list.AddRange(localAlternates.Select(i => new Tuple<BaseItem, MediaSourceType>(i, MediaSourceType.Default)));
+ list.AddRange(localAlternates.Select(i => (i, MediaSourceType.Default)));
return list;
}
diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs
index f268bc939..afdaf448b 100644
--- a/MediaBrowser.Controller/Entities/Year.cs
+++ b/MediaBrowser.Controller/Entities/Year.cs
@@ -15,13 +15,11 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public class Year : BaseItem, IItemByName
{
- public override List<string> GetUserDataKeys()
- {
- var list = base.GetUserDataKeys();
+ [JsonIgnore]
+ public override bool SupportsAncestors => false;
- list.Insert(0, "Year-" + Name);
- return list;
- }
+ [JsonIgnore]
+ public override bool SupportsPeople => false;
/// <summary>
/// Gets the folder containing the item.
@@ -31,6 +29,19 @@ namespace MediaBrowser.Controller.Entities
[JsonIgnore]
public override string ContainingFolderPath => Path;
+ public override bool CanDelete()
+ {
+ return false;
+ }
+
+ public override List<string> GetUserDataKeys()
+ {
+ var list = base.GetUserDataKeys();
+
+ list.Insert(0, "Year-" + Name);
+ return list;
+ }
+
public override double GetDefaultPrimaryImageAspectRatio()
{
double value = 2;
@@ -39,14 +50,6 @@ namespace MediaBrowser.Controller.Entities
return value;
}
- [JsonIgnore]
- public override bool SupportsAncestors => false;
-
- public override bool CanDelete()
- {
- return false;
- }
-
public override bool IsSaveLocalMetadataEnabled()
{
return true;
@@ -54,9 +57,7 @@ namespace MediaBrowser.Controller.Entities
public IList<BaseItem> GetTaggedItems(InternalItemsQuery query)
{
- var usCulture = new CultureInfo("en-US");
-
- if (!int.TryParse(Name, NumberStyles.Integer, usCulture, out var year))
+ if (!int.TryParse(Name, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
{
return new List<BaseItem>();
}
@@ -76,9 +77,6 @@ namespace MediaBrowser.Controller.Entities
return null;
}
- [JsonIgnore]
- public override bool SupportsPeople => false;
-
public static string GetPath(string name)
{
return GetPath(name, true);