Merge branch 'master' into keyframe_extraction_v1

# Conflicts:
#	Jellyfin.Api/Controllers/DynamicHlsController.cs
#	MediaBrowser.Controller/MediaEncoding/IMediaEncoder.cs
#	MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
This commit is contained in:
cvium
2022-01-07 10:23:22 +01:00
736 changed files with 15159 additions and 11725 deletions

View File

@@ -55,12 +55,7 @@ namespace MediaBrowser.Controller.BaseItemManager
return typeOptions.MetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}
if (!libraryOptions.EnableInternetProviders)
{
return false;
}
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
return itemConfig == null || !itemConfig.DisabledMetadataFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}
@@ -86,12 +81,7 @@ namespace MediaBrowser.Controller.BaseItemManager
return typeOptions.ImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}
if (!libraryOptions.EnableInternetProviders)
{
return false;
}
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, GetType().Name, StringComparison.OrdinalIgnoreCase));
var itemConfig = _serverConfigurationManager.Configuration.MetadataOptions.FirstOrDefault(i => string.Equals(i.ItemType, baseItem.GetType().Name, StringComparison.OrdinalIgnoreCase));
return itemConfig == null || !itemConfig.DisabledImageFetchers.Contains(name.AsSpan(), StringComparison.OrdinalIgnoreCase);
}

View File

@@ -8,4 +8,4 @@ namespace MediaBrowser.Controller.Channels
{
public string UserId { get; set; }
}
}
}

View File

@@ -6,4 +6,4 @@ namespace MediaBrowser.Controller.Channels
{
string[] Attributes { get; }
}
}
}

View File

@@ -12,4 +12,4 @@ namespace MediaBrowser.Controller.Channels
Task DeleteItem(string id, CancellationToken cancellationToken);
}
}
}

View File

@@ -18,4 +18,4 @@ namespace MediaBrowser.Controller.Channels
/// <returns>The latest media.</returns>
Task<IEnumerable<ChannelItemInfo>> GetLatestMedia(ChannelLatestMediaSearch request, CancellationToken cancellationToken);
}
}
}

View File

@@ -0,0 +1,31 @@
using System;
using System.IO;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.ClientEvent
{
/// <inheritdoc />
public class ClientEventLogger : IClientEventLogger
{
private readonly IServerApplicationPaths _applicationPaths;
/// <summary>
/// Initializes a new instance of the <see cref="ClientEventLogger"/> class.
/// </summary>
/// <param name="applicationPaths">Instance of the <see cref="IServerApplicationPaths"/> interface.</param>
public ClientEventLogger(IServerApplicationPaths applicationPaths)
{
_applicationPaths = applicationPaths;
}
/// <inheritdoc />
public async Task<string> WriteDocumentAsync(string clientName, string clientVersion, Stream fileContents)
{
var fileName = $"upload_{clientName}_{clientVersion}_{DateTime.UtcNow:yyyyMMddHHmmss}_{Guid.NewGuid():N}.log";
var logFilePath = Path.Combine(_applicationPaths.LogDirectoryPath, fileName);
await using var fileStream = new FileStream(logFilePath, FileMode.CreateNew, FileAccess.Write, FileShare.None);
await fileContents.CopyToAsync(fileStream).ConfigureAwait(false);
return fileName;
}
}
}

View File

@@ -0,0 +1,23 @@
using System.IO;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.ClientEvent
{
/// <summary>
/// The client event logger.
/// </summary>
public interface IClientEventLogger
{
/// <summary>
/// Writes a file to the log directory.
/// </summary>
/// <param name="clientName">The client name writing the document.</param>
/// <param name="clientVersion">The client version writing the document.</param>
/// <param name="fileContents">The file contents to write.</param>
/// <returns>The created file name.</returns>
Task<string> WriteDocumentAsync(
string clientName,
string clientVersion,
Stream fileContents);
}
}

View File

@@ -21,4 +21,4 @@ namespace MediaBrowser.Controller.Collections
/// <value>The options.</value>
public CollectionCreationOptions Options { get; set; }
}
}
}

View File

@@ -37,8 +37,9 @@ namespace MediaBrowser.Controller.Dlna
/// <summary>
/// Updates the profile.
/// </summary>
/// <param name="profileId">The profile id.</param>
/// <param name="profile">The profile.</param>
void UpdateProfile(DeviceProfile profile);
void UpdateProfile(string profileId, DeviceProfile profile);
/// <summary>
/// Deletes the profile.

View File

@@ -75,7 +75,7 @@ namespace MediaBrowser.Controller.Drawing
/// </summary>
/// <param name="options">The options.</param>
/// <returns>Task.</returns>
Task<(string path, string? mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options);
Task<(string Path, string? MimeType, DateTime DateModified)> ProcessImage(ImageProcessingOptions options);
/// <summary>
/// Gets the supported image output formats.

View File

@@ -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
{
@@ -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 Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
=> new[] { ((BaseItem)this, MediaSourceType.Default) };
}
}

View File

@@ -88,7 +88,7 @@ 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 };
}

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Diacritics.Extensions;
using Jellyfin.Data.Enums;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Entities.Audio
@@ -66,7 +67,7 @@ namespace MediaBrowser.Controller.Entities.Audio
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);
}

View File

@@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
@@ -23,7 +22,6 @@ 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;
@@ -41,13 +39,9 @@ namespace MediaBrowser.Controller.Entities
/// </summary>
public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo>, IEquatable<BaseItem>
{
/// <summary>
/// The trailer folder name.
/// </summary>
public const string TrailersFolderName = "trailers";
public const string ThemeSongsFolderName = "theme-music";
private BaseItemKind? _baseItemKind;
public const string ThemeSongFileName = "theme";
public const string ThemeVideosFolderName = "backdrops";
/// <summary>
/// The supported image extensions.
@@ -84,26 +78,7 @@ namespace MediaBrowser.Controller.Entities
Model.Entities.ExtraType.Scene
};
public static readonly char[] SlugReplaceChars = { '?', '/', '&' };
/// <summary>
/// The supported extra folder names and types. See <see cref="Emby.Naming.Common.NamingOptions" />.
/// </summary>
public static readonly Dictionary<string, ExtraType> AllExtrasTypesFolderNames = new Dictionary<string, ExtraType>(StringComparer.OrdinalIgnoreCase)
{
["extras"] = MediaBrowser.Model.Entities.ExtraType.Unknown,
["behind the scenes"] = MediaBrowser.Model.Entities.ExtraType.BehindTheScenes,
["deleted scenes"] = MediaBrowser.Model.Entities.ExtraType.DeletedScene,
["interviews"] = MediaBrowser.Model.Entities.ExtraType.Interview,
["scenes"] = MediaBrowser.Model.Entities.ExtraType.Scene,
["samples"] = MediaBrowser.Model.Entities.ExtraType.Sample,
["shorts"] = MediaBrowser.Model.Entities.ExtraType.Clip,
["featurettes"] = MediaBrowser.Model.Entities.ExtraType.Clip
};
private string _sortName;
private Guid[] _themeSongIds;
private Guid[] _themeVideoIds;
private string _forcedSortName;
@@ -124,40 +99,6 @@ namespace MediaBrowser.Controller.Entities
ExtraIds = Array.Empty<Guid>();
}
[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; }
@@ -335,13 +276,6 @@ 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;
@@ -354,11 +288,6 @@ namespace MediaBrowser.Controller.Entities
{
get
{
// if (IsOffline)
// {
// return LocationType.Offline;
// }
var path = Path;
if (string.IsNullOrEmpty(path))
{
@@ -391,7 +320,7 @@ namespace MediaBrowser.Controller.Entities
}
[JsonIgnore]
public bool IsFileProtocol => IsPathProtocol(MediaProtocol.File);
public bool IsFileProtocol => PathProtocol == MediaProtocol.File;
[JsonIgnore]
public bool HasPathProtocol => PathProtocol.HasValue;
@@ -583,14 +512,7 @@ namespace MediaBrowser.Controller.Entities
}
[JsonIgnore]
public virtual Guid DisplayParentId
{
get
{
var parentId = ParentId;
return parentId;
}
}
public virtual Guid DisplayParentId => ParentId;
[JsonIgnore]
public BaseItem DisplayParent
@@ -853,13 +775,6 @@ namespace MediaBrowser.Controller.Entities
return Id.ToString("N", CultureInfo.InvariantCulture);
}
public bool IsPathProtocol(MediaProtocol protocol)
{
var current = PathProtocol;
return current.HasValue && current.Value == protocol;
}
private List<Tuple<StringBuilder, bool>> GetSortChunks(string s1)
{
var list = new List<Tuple<StringBuilder, bool>>();
@@ -987,7 +902,7 @@ namespace MediaBrowser.Controller.Entities
ReadOnlySpan<char> idString = Id.ToString("N", CultureInfo.InvariantCulture);
return System.IO.Path.Join(basePath, "library", idString.Slice(0, 2), idString);
return System.IO.Path.Join(basePath, "library", idString[..2], idString);
}
/// <summary>
@@ -1154,7 +1069,7 @@ namespace MediaBrowser.Controller.Entities
}
var list = GetAllItemsForMediaSources();
var result = list.Select(i => GetVersionInfo(enablePathSubstitution, i.Item1, i.Item2)).ToList();
var result = list.Select(i => GetVersionInfo(enablePathSubstitution, i.Item, i.MediaSourceType)).ToList();
if (IsActiveRecording())
{
@@ -1182,9 +1097,9 @@ namespace MediaBrowser.Controller.Entities
.ToList();
}
protected virtual List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
protected virtual IEnumerable<(BaseItem Item, MediaSourceType MediaSourceType)> GetAllItemsForMediaSources()
{
return new List<Tuple<BaseItem, MediaSourceType>>();
return Enumerable.Empty<(BaseItem, MediaSourceType)>();
}
private MediaSourceInfo GetVersionInfo(bool enablePathSubstitution, BaseItem item, MediaSourceType type)
@@ -1302,8 +1217,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)
{
@@ -1338,99 +1252,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)
{
return fileSystemChildren
.Where(child => child.IsDirectory && AllExtrasTypesFolderNames.ContainsKey(child.Name))
.SelectMany(folder => LibraryManager
.ResolvePaths(FileSystem.GetFiles(folder.FullName), directoryService, null, new LibraryOptions())
.OfType<Video>()
.Select(video =>
{
// Try to retrieve it from the db. If we don't find it, use the resolved version
if (LibraryManager.GetItemById(video.Id) is Video dbItem)
{
video = dbItem;
}
video.ExtraType = AllExtrasTypesFolderNames[folder.Name];
return video;
})
.OrderBy(video => video.Path)) // Sort them so that the list can be easily compared for changes
.ToArray();
return string.Join('/', terms);
}
public Task RefreshMetadata(CancellationToken cancellationToken)
@@ -1462,21 +1284,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);
}
}
@@ -1548,36 +1365,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)
@@ -1587,98 +1380,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;
@@ -1689,48 +1408,9 @@ 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;
return true;
}
public string GetPresentationUniqueKey()
@@ -1963,7 +1643,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;
}
@@ -2042,7 +1722,7 @@ namespace MediaBrowser.Controller.Entities
public BaseItemKind GetBaseItemKind()
{
return Enum.Parse<BaseItemKind>(GetClientTypeName());
return _baseItemKind ??= Enum.Parse<BaseItemKind>(GetClientTypeName());
}
/// <summary>
@@ -2132,7 +1812,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)
@@ -2167,7 +1847,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);
@@ -2268,7 +1948,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;
@@ -2276,15 +1960,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)
@@ -2298,7 +1973,7 @@ namespace MediaBrowser.Controller.Entities
if (image == null)
{
ImageInfos = ImageInfos.Concat(new[] { GetImageInfo(file, type) }).ToArray();
AddImage(GetImageInfo(file, type));
}
else
{
@@ -2342,14 +2017,24 @@ 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);
@@ -2368,12 +2053,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;
@@ -2495,11 +2180,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)
{
@@ -2512,7 +2197,6 @@ namespace MediaBrowser.Controller.Entities
.ToList();
var newImageList = new List<FileSystemMetadata>();
var imageAdded = false;
var imageUpdated = false;
foreach (var newImage in images)
@@ -2528,7 +2212,6 @@ namespace MediaBrowser.Controller.Entities
if (existing == null)
{
newImageList.Add(newImage);
imageAdded = true;
}
else
{
@@ -2549,19 +2232,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();
@@ -2612,7 +2282,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)
@@ -2730,7 +2400,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);
}
@@ -2758,8 +2428,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;
@@ -2820,8 +2492,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));
@@ -2835,14 +2509,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);
@@ -2926,9 +2592,9 @@ 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(rating => (rating, LocalizationManager.GetRatingLevel(rating)))
.OrderBy(i => i.Item2 ?? 1000)
.Select(i => i.Item1);
.Select(i => i.rating);
OfficialRating = ratings.FirstOrDefault() ?? currentOfficialRating;
@@ -2938,14 +2604,14 @@ 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>
@@ -2973,18 +2639,6 @@ 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 long GetRunTimeTicksForPlayState()
{
return RunTimeTicks ?? 0;
@@ -2997,7 +2651,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);

View File

@@ -44,14 +44,15 @@ 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
{
Path = file,
Type = imageType
}, 0);
new ItemImageInfo
{
Path = file,
Type = imageType
},
0);
}
else
{

View File

@@ -303,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);
}
@@ -425,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);
@@ -792,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;
@@ -807,7 +807,7 @@ namespace MediaBrowser.Controller.Entities
{
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;
}
}
@@ -882,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;
@@ -1013,6 +1013,7 @@ 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.InvariantCultureIgnoreCase) < 1);
@@ -1027,6 +1028,7 @@ namespace MediaBrowser.Controller.Entities
{
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))
@@ -1099,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;
}

View File

@@ -6,7 +6,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Diacritics.Extensions;
using MediaBrowser.Controller.Entities.Audio;
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);

View File

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

View File

@@ -8,4 +8,4 @@ namespace MediaBrowser.Controller.Entities
{
Share[] Shares { get; set; }
}
}
}

View File

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

View File

@@ -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>
@@ -42,57 +33,6 @@ namespace MediaBrowser.Controller.Entities
/// <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>
/// <param name="item">Media item.</param>
/// <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>
/// <param name="item">Media item.</param>
/// <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;
}
}

View File

@@ -27,18 +27,18 @@ namespace MediaBrowser.Controller.Entities
ExcludeArtistIds = Array.Empty<Guid>();
ExcludeInheritedTags = Array.Empty<string>();
ExcludeItemIds = Array.Empty<Guid>();
ExcludeItemTypes = Array.Empty<string>();
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<string>();
IncludeItemTypes = Array.Empty<BaseItemKind>();
ItemIds = Array.Empty<Guid>();
MediaTypes = Array.Empty<string>();
MinSimilarityScore = 20;
OfficialRatings = Array.Empty<string>();
OrderBy = Array.Empty<ValueTuple<string, SortOrder>>();
OrderBy = Array.Empty<(string, SortOrder)>();
PersonIds = Array.Empty<Guid>();
PersonTypes = Array.Empty<string>();
PresetViews = Array.Empty<string>();
@@ -87,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; }
@@ -229,7 +229,7 @@ namespace MediaBrowser.Controller.Entities
public Guid ParentId { get; set; }
public string? ParentType { get; set; }
public BaseItemKind? ParentType { get; set; }
public Guid[] AncestorIds { get; set; }
@@ -271,7 +271,7 @@ namespace MediaBrowser.Controller.Entities
public bool? HasChapterImages { get; set; }
public IReadOnlyList<(string, SortOrder)> OrderBy { get; set; }
public IReadOnlyList<(string OrderBy, SortOrder SortOrder)> OrderBy { get; set; }
public DateTime? MinDateCreated { get; set; }
@@ -314,7 +314,7 @@ namespace MediaBrowser.Controller.Entities
else
{
ParentId = value.Id;
ParentType = value.GetType().Name;
ParentType = value.GetBaseItemKind();
}
}
}

View File

@@ -32,4 +32,4 @@ namespace MediaBrowser.Controller.Entities
return ((obj.Path ?? string.Empty) + (obj.LibraryItemId ?? string.Empty) + obj.Type).GetHashCode(StringComparison.Ordinal);
}
}
}
}

View File

@@ -15,4 +15,4 @@
/// </summary>
Shortcut = 1
}
}
}

View File

@@ -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.

View File

@@ -7,12 +7,9 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Providers;
namespace MediaBrowser.Controller.Entities.Movies
@@ -22,22 +19,16 @@ namespace MediaBrowser.Controller.Entities.Movies
/// </summary>
public class Movie : Video, IHasSpecialFeatures, IHasTrailers, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
{
public Movie()
{
SpecialFeatureIds = Array.Empty<Guid>();
RemoteTrailers = Array.Empty<MediaUrl>();
LocalTrailerIds = Array.Empty<Guid>();
RemoteTrailerIds = Array.Empty<Guid>();
}
/// <inheritdoc />
public IReadOnlyList<Guid> SpecialFeatureIds => GetExtras()
.Where(extra => extra.ExtraType != null && extra is Video)
.Select(extra => extra.Id)
.ToArray();
/// <inheritdoc />
public IReadOnlyList<Guid> SpecialFeatureIds { get; set; }
/// <inheritdoc />
public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
/// <inheritdoc />
public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
public IReadOnlyList<BaseItem> LocalTrailers => GetExtras()
.Where(extra => extra.ExtraType == Model.Entities.ExtraType.Trailer)
.ToArray();
/// <summary>
/// Gets or sets the name of the TMDB collection.
@@ -66,54 +57,6 @@ namespace MediaBrowser.Controller.Entities.Movies
return 2.0 / 3;
}
protected override async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var hasChanges = await base.RefreshedOwnedItems(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
// Must have a parent to have special features
// In other words, it must be part of the Parent/Child tree
if (IsFileProtocol && SupportsOwnedItems && !IsInMixedFolder)
{
var specialFeaturesChanged = await RefreshSpecialFeatures(options, fileSystemChildren, cancellationToken).ConfigureAwait(false);
if (specialFeaturesChanged)
{
hasChanges = true;
}
}
return hasChanges;
}
private async Task<bool> RefreshSpecialFeatures(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
{
var newItems = LibraryManager.FindExtras(this, fileSystemChildren, options.DirectoryService).ToList();
var newItemIds = newItems.Select(i => i.Id).ToArray();
var itemsChanged = !SpecialFeatureIds.SequenceEqual(newItemIds);
var ownerId = Id;
var tasks = newItems.Select(i =>
{
var subOptions = new MetadataRefreshOptions(options);
if (i.OwnerId != ownerId)
{
i.OwnerId = ownerId;
subOptions.ForceSave = true;
}
return RefreshMetadataForOwnedItem(i, false, subOptions, cancellationToken);
});
await Task.WhenAll(tasks).ConfigureAwait(false);
SpecialFeatureIds = newItemIds;
return itemsChanged;
}
/// <inheritdoc />
public override UnratedItem GetBlockUnratedType()
{

View File

@@ -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.

View File

@@ -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.
@@ -131,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)
@@ -159,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;
@@ -213,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)
@@ -239,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;
@@ -259,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
};
@@ -363,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
};

View File

@@ -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)
{

View File

@@ -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;
@@ -102,7 +103,7 @@ 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);
}
@@ -170,12 +171,12 @@ namespace MediaBrowser.Controller.Entities
public static bool IsEligibleForGrouping(string viewType)
{
return _viewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
return _viewTypesEligibleForGrouping.Contains(viewType ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
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)

View File

@@ -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)
@@ -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);
@@ -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,7 +196,7 @@ namespace MediaBrowser.Controller.Entities
query.Parent = parent;
query.SetUser(user);
query.IncludeItemTypes = new[] { nameof(Movie) };
query.IncludeItemTypes = new[] { BaseItemKind.Movie };
return _libraryManager.GetItemsResult(query);
}
@@ -210,7 +204,7 @@ namespace MediaBrowser.Controller.Entities
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
@@ -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
};
}
@@ -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
@@ -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);
}
@@ -498,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;
}
@@ -749,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;
@@ -767,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)
@@ -780,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)
@@ -790,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;
}
@@ -814,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;
@@ -824,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;
@@ -857,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;
}
@@ -975,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();
}
@@ -984,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();
}

View File

@@ -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;
@@ -33,6 +34,7 @@ namespace MediaBrowser.Controller.Entities
AdditionalParts = Array.Empty<string>();
LocalAlternateVersions = Array.Empty<string>();
SubtitleFiles = Array.Empty<string>();
AudioFiles = Array.Empty<string>();
LinkedAlternateVersions = Array.Empty<LinkedChild>();
}
@@ -97,6 +99,12 @@ namespace MediaBrowser.Controller.Entities
/// <value>The subtitle paths.</value>
public string[] SubtitleFiles { get; set; }
/// <summary>
/// Gets or sets the audio paths.
/// </summary>
/// <value>The audio paths.</value>
public string[] AudioFiles { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance has subtitles.
/// </summary>
@@ -185,7 +193,7 @@ namespace MediaBrowser.Controller.Entities
{
if (SourceType == SourceType.Channel)
{
return !Tags.Contains("livestream", StringComparer.OrdinalIgnoreCase);
return !Tags.Contains("livestream", StringComparison.OrdinalIgnoreCase);
}
return !IsActiveRecording();
@@ -509,35 +517,35 @@ namespace MediaBrowser.Controller.Entities
}).FirstOrDefault();
}
protected override List<Tuple<BaseItem, MediaSourceType>> GetAllItemsForMediaSources()
protected override IEnumerable<(BaseItem Item, MediaSourceType 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;
}

View File

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

View File

@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.IO
if (string.IsNullOrEmpty(newPath))
{
// invalid shortcut - could be old or target could just be unavailable
logger.LogWarning("Encountered invalid shortcut: " + fullName);
logger.LogWarning("Encountered invalid shortcut: {Path}", fullName);
continue;
}
@@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO
}
catch (Exception ex)
{
logger.LogError(ex, "Error resolving shortcut from {path}", fullName);
logger.LogError(ex, "Error resolving shortcut from {Path}", fullName);
}
}
else if (flattenFolderDepth > 0 && isDirectory)

View File

@@ -2,7 +2,6 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Net;
using MediaBrowser.Common;
using MediaBrowser.Model.System;
@@ -42,50 +41,42 @@ namespace MediaBrowser.Controller
/// <value>The name of the friendly.</value>
string FriendlyName { get; }
/// <summary>
/// Gets the configured published server url.
/// </summary>
string PublishedServerUrl { get; }
/// <summary>
/// Gets the system info.
/// </summary>
/// <param name="source">The originator of the request.</param>
/// <param name="request">The HTTP request.</param>
/// <returns>SystemInfo.</returns>
SystemInfo GetSystemInfo(IPAddress source);
SystemInfo GetSystemInfo(HttpRequest request);
PublicSystemInfo GetPublicSystemInfo(IPAddress address);
PublicSystemInfo GetPublicSystemInfo(HttpRequest request);
/// <summary>
/// Gets a URL specific for the request.
/// </summary>
/// <param name="request">The <see cref="HttpRequest"/> instance.</param>
/// <param name="port">Optional port number.</param>
/// <returns>An accessible URL.</returns>
string GetSmartApiUrl(HttpRequest request, int? port = null);
string GetSmartApiUrl(HttpRequest request);
/// <summary>
/// Gets a URL specific for the request.
/// </summary>
/// <param name="remoteAddr">The remote <see cref="IPAddress"/> of the connection.</param>
/// <param name="port">Optional port number.</param>
/// <returns>An accessible URL.</returns>
string GetSmartApiUrl(IPAddress remoteAddr, int? port = null);
string GetSmartApiUrl(IPAddress remoteAddr);
/// <summary>
/// Gets a URL specific for the request.
/// </summary>
/// <param name="hostname">The hostname used in the connection.</param>
/// <param name="port">Optional port number.</param>
/// <returns>An accessible URL.</returns>
string GetSmartApiUrl(string hostname, int? port = null);
string GetSmartApiUrl(string hostname);
/// <summary>
/// Gets a localhost URL that can be used to access the API using the loop-back IP address.
/// over HTTP (not HTTPS).
/// Gets an URL that can be used to access the API over LAN.
/// </summary>
/// <param name="allowHttps">A value indicating whether to allow HTTPS.</param>
/// <returns>The API URL.</returns>
string GetLoopbackHttpApiUrl();
string GetApiUrlForLocalAccess(bool allowHttps = true);
/// <summary>
/// Gets a local (LAN) URL that can be used to access the API.
@@ -103,8 +94,6 @@ namespace MediaBrowser.Controller
/// <returns>The API URL.</returns>
string GetLocalApiUrl(string hostname, string scheme = null, int? port = null);
IEnumerable<WakeOnLanInfo> GetWakeOnLanInfo();
string ExpandVirtualPath(string path);
string ReverseVirtualPath(string path);

View File

@@ -6,7 +6,6 @@ using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Emby.Naming.Common;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Dto;
@@ -59,10 +58,12 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="fileInfo">The file information.</param>
/// <param name="parent">The parent.</param>
/// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
/// <returns>BaseItem.</returns>
BaseItem ResolvePath(
FileSystemMetadata fileInfo,
Folder parent = null);
Folder parent = null,
IDirectoryService directoryService = null);
/// <summary>
/// Resolves a set of files into a list of BaseItem.
@@ -211,7 +212,7 @@ namespace MediaBrowser.Controller.Library
/// <returns>IEnumerable{BaseItem}.</returns>
IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<string> sortBy, SortOrder sortOrder);
IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<ValueTuple<string, SortOrder>> orderBy);
IEnumerable<BaseItem> Sort(IEnumerable<BaseItem> items, User user, IEnumerable<(string OrderBy, SortOrder SortOrder)> orderBy);
/// <summary>
/// Gets the user root folder.
@@ -396,20 +397,6 @@ namespace MediaBrowser.Controller.Library
string viewType,
string sortName);
/// <summary>
/// Determines whether [is video file] [the specified path].
/// </summary>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if [is video file] [the specified path]; otherwise, <c>false</c>.</returns>
bool IsVideoFile(string path);
/// <summary>
/// Determines whether [is audio file] [the specified path].
/// </summary>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns>
bool IsAudioFile(string path);
/// <summary>
/// Gets the season number from path.
/// </summary>
@@ -440,29 +427,14 @@ namespace MediaBrowser.Controller.Library
/// <returns>Guid.</returns>
Guid GetNewItemId(string key, Type type);
/// <summary>
/// Finds the trailers.
/// </summary>
/// <param name="owner">The owner.</param>
/// <param name="fileSystemChildren">The file system children.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>IEnumerable&lt;Trailer&gt;.</returns>
IEnumerable<Video> FindTrailers(
BaseItem owner,
List<FileSystemMetadata> fileSystemChildren,
IDirectoryService directoryService);
/// <summary>
/// Finds the extras.
/// </summary>
/// <param name="owner">The owner.</param>
/// <param name="fileSystemChildren">The file system children.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>IEnumerable&lt;Video&gt;.</returns>
IEnumerable<Video> FindExtras(
BaseItem owner,
List<FileSystemMetadata> fileSystemChildren,
IDirectoryService directoryService);
/// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
/// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService);
/// <summary>
/// Gets the collection folders.
@@ -601,17 +573,17 @@ namespace MediaBrowser.Controller.Library
void RemoveMediaPath(string virtualFolderName, string mediaPath);
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetGenres(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetMusicGenres(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetStudios(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetArtists(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAllArtists(InternalItemsQuery query);
int GetCount(InternalItemsQuery query);
@@ -625,11 +597,5 @@ namespace MediaBrowser.Controller.Library
BaseItem GetParentItem(string parentId, Guid? userId);
BaseItem GetParentItem(Guid? parentId, Guid? userId);
/// <summary>
/// Gets or creates a static instance of <see cref="NamingOptions"/>.
/// </summary>
/// <returns>An instance of the <see cref="NamingOptions"/> class.</returns>
NamingOptions GetNamingOptions();
}
}

View File

@@ -30,13 +30,6 @@ namespace MediaBrowser.Controller.Library
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
List<MediaStream> GetMediaStreams(Guid itemId);
/// <summary>
/// Gets the media streams.
/// </summary>
/// <param name="mediaSourceId">The media source identifier.</param>
/// <returns>IEnumerable&lt;MediaStream&gt;.</returns>
List<MediaStream> GetMediaStreams(string mediaSourceId);
/// <summary>
/// Gets the media streams.
/// </summary>

View File

@@ -36,6 +36,7 @@ namespace MediaBrowser.Controller.Library
DirectoryService = directoryService;
}
// TODO remove dependencies as properties, they should be injected where it makes sense
public IDirectoryService DirectoryService { get; }
/// <summary>
@@ -236,6 +237,40 @@ namespace MediaBrowser.Controller.Library
return CollectionType;
}
/// <summary>
/// Gets the configured content type for the path.
/// </summary>
/// <remarks>
/// This is subject to future refactoring as it relies on a static property in BaseItem.
/// </remarks>
/// <returns>The configured content type.</returns>
public string GetConfiguredContentType()
{
return BaseItem.LibraryManager.GetConfiguredContentType(Path);
}
/// <summary>
/// Gets the file system children that do not hit the ignore file check.
/// </summary>
/// <remarks>
/// This is subject to future refactoring as it relies on a static property in BaseItem.
/// </remarks>
/// <returns>The file system children that are not ignored.</returns>
public IEnumerable<FileSystemMetadata> GetActualFileSystemChildren()
{
var numberOfChildren = FileSystemChildren.Length;
for (var i = 0; i < numberOfChildren; i++)
{
var child = FileSystemChildren[i];
if (BaseItem.LibraryManager.IgnoreFile(child, Parent))
{
continue;
}
yield return child;
}
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>

View File

@@ -16,4 +16,4 @@ namespace MediaBrowser.Controller.LiveTv
public CancellationTokenSource CancellationTokenSource { get; set; }
}
}
}

View File

@@ -251,7 +251,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="fields">The fields.</param>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem, BaseItemDto)> programs, IReadOnlyList<ItemFields> fields, User user = null);
Task AddInfoToProgramDto(IReadOnlyCollection<(BaseItem Item, BaseItemDto ItemDto)> programs, IReadOnlyList<ItemFields> fields, User user = null);
/// <summary>
/// Saves the tuner host.
@@ -292,7 +292,7 @@ namespace MediaBrowser.Controller.LiveTv
/// <param name="items">The items.</param>
/// <param name="options">The options.</param>
/// <param name="user">The user.</param>
void AddChannelInfo(IReadOnlyCollection<(BaseItemDto, LiveTvChannel)> items, DtoOptions options, User user);
void AddChannelInfo(IReadOnlyCollection<(BaseItemDto ItemDto, LiveTvChannel Channel)> items, DtoOptions options, User user);
Task<List<ChannelInfo>> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken);

View File

@@ -5,9 +5,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -74,7 +74,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
[JsonIgnore]
public bool IsRepeat { get; set; }
@@ -107,9 +107,7 @@ namespace MediaBrowser.Controller.LiveTv
{
if (!string.IsNullOrEmpty(Number))
{
double number = 0;
if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out number))
if (double.TryParse(Number, NumberStyles.Any, CultureInfo.InvariantCulture, out double number))
{
return string.Format(CultureInfo.InvariantCulture, "{0:00000.0}", number) + "-" + (Name ?? string.Empty);
}

View File

@@ -8,6 +8,7 @@ using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Data.Enums;
using Jellyfin.Extensions;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
@@ -66,7 +67,7 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>true</c> if this instance is sports; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsSports => Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
public bool IsSports => Tags.Contains("Sports", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets or sets a value indicating whether this instance is series.
@@ -80,28 +81,28 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
public bool IsLive => Tags.Contains("Live", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets a value indicating whether this instance is news.
/// </summary>
/// <value><c>true</c> if this instance is news; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
public bool IsNews => Tags.Contains("News", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets a value indicating whether this instance is kids.
/// </summary>
/// <value><c>true</c> if this instance is kids; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets a value indicating whether this instance is premiere.
/// </summary>
/// <value><c>true</c> if this instance is premiere; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
public bool IsPremiere => Tags.Contains("Premiere", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Gets the folder containing the item.

View File

@@ -4,8 +4,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using Jellyfin.Extensions;
using MediaBrowser.Model.LiveTv;
namespace MediaBrowser.Controller.LiveTv
@@ -123,11 +123,11 @@ namespace MediaBrowser.Controller.LiveTv
public bool IsMovie { get; set; }
public bool IsKids => Tags.Contains("Kids", StringComparer.OrdinalIgnoreCase);
public bool IsKids => Tags.Contains("Kids", StringComparison.OrdinalIgnoreCase);
public bool IsSports => Tags.Contains("Sports", StringComparer.OrdinalIgnoreCase);
public bool IsSports => Tags.Contains("Sports", StringComparison.OrdinalIgnoreCase);
public bool IsNews => Tags.Contains("News", StringComparer.OrdinalIgnoreCase);
public bool IsNews => Tags.Contains("News", StringComparison.OrdinalIgnoreCase);
public bool IsSeries { get; set; }
@@ -136,10 +136,10 @@ namespace MediaBrowser.Controller.LiveTv
/// </summary>
/// <value><c>true</c> if this instance is live; otherwise, <c>false</c>.</value>
[JsonIgnore]
public bool IsLive => Tags.Contains("Live", StringComparer.OrdinalIgnoreCase);
public bool IsLive => Tags.Contains("Live", StringComparison.OrdinalIgnoreCase);
[JsonIgnore]
public bool IsPremiere => Tags.Contains("Premiere", StringComparer.OrdinalIgnoreCase);
public bool IsPremiere => Tags.Contains("Premiere", StringComparison.OrdinalIgnoreCase);
public int? ProductionYear { get; set; }

View File

@@ -13,12 +13,16 @@
<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Diacritics" Version="2.1.20036.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="5.0.0" />
<PackageReference Include="Diacritics" Version="3.3.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="System.Threading.Tasks.Dataflow" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
@@ -39,11 +43,6 @@
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Stability)'=='Unstable'">
@@ -54,7 +53,7 @@
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.376" PrivateAssets="All" />
<PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
</ItemGroup>

View File

@@ -201,4 +201,4 @@ namespace MediaBrowser.Controller.MediaEncoding
return null;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -110,23 +110,7 @@ namespace MediaBrowser.Controller.MediaEncoding
public string OutputContainer { get; set; }
public string OutputVideoSync
{
get
{
// For live tv + in progress recordings
if (string.Equals(InputContainer, "mpegts", StringComparison.OrdinalIgnoreCase)
|| string.Equals(InputContainer, "ts", StringComparison.OrdinalIgnoreCase))
{
if (!MediaSource.RunTimeTicks.HasValue)
{
return "cfr";
}
}
return "-1";
}
}
public string OutputVideoSync { get; set; }
public string AlbumCoverPath { get; set; }

View File

@@ -18,6 +18,16 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <summary>
/// The tonemap_opencl_bt2390.
/// </summary>
TonemapOpenclBt2390 = 2
TonemapOpenclBt2390 = 2,
/// <summary>
/// The overlay_opencl_framesync.
/// </summary>
OverlayOpenclFrameSync = 3,
/// <summary>
/// The overlay_vaapi_framesync.
/// </summary>
OverlayVaapiFrameSync = 4
}
}

View File

@@ -12,7 +12,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
public interface IAttachmentExtractor
{
Task<(MediaAttachment attachment, Stream stream)> GetAttachment(
Task<(MediaAttachment Attachment, Stream Stream)> GetAttachment(
BaseItem item,
string mediaSourceId,
int attachmentStreamIndex,

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
@@ -30,6 +31,30 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <value>The probe path.</value>
string ProbePath { get; }
/// <summary>
/// Gets the version of encoder.
/// </summary>
/// <returns>The version of encoder.</returns>
Version EncoderVersion { get; }
/// <summary>
/// Gets a value indicating whether the configured Vaapi device is from AMD(radeonsi/r600 Mesa driver).
/// </summary>
/// <value><c>true</c> if the Vaapi device is an AMD(radeonsi/r600 Mesa driver) GPU, <c>false</c> otherwise.</value>
bool IsVaapiDeviceAmd { get; }
/// <summary>
/// Gets a value indicating whether the configured Vaapi device is from Intel(iHD driver).
/// </summary>
/// <value><c>true</c> if the Vaapi device is an Intel(iHD driver) GPU, <c>false</c> otherwise.</value>
bool IsVaapiDeviceInteliHD { get; }
/// <summary>
/// Gets a value indicating whether the configured Vaapi device is from Intel(legacy i965 driver).
/// </summary>
/// <value><c>true</c> if the Vaapi device is an Intel(legacy i965 driver) GPU, <c>false</c> otherwise.</value>
bool IsVaapiDeviceInteli965 { get; }
/// <summary>
/// Whether given encoder codec is supported.
/// </summary>
@@ -65,12 +90,6 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <returns><c>true</c> if the filter is supported, <c>false</c> otherwise.</returns>
bool SupportsFilterWithOption(FilterOptionType option);
/// <summary>
/// Get the version of media encoder.
/// </summary>
/// <returns>The version of media encoder.</returns>
Version GetMediaEncoderVersion();
/// <summary>
/// Extracts the audio image.
/// </summary>
@@ -101,35 +120,10 @@ namespace MediaBrowser.Controller.MediaEncoding
/// <param name="mediaSource">Media source information.</param>
/// <param name="imageStream">Media stream information.</param>
/// <param name="imageStreamIndex">Index of the stream to extract from.</param>
/// <param name="targetFormat">The format of the file to write.</param>
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
/// <returns>Location of video image.</returns>
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, CancellationToken cancellationToken);
/// <summary>
/// Extracts the video images on interval.
/// </summary>
/// <param name="inputFile">Input file.</param>
/// <param name="container">Video container type.</param>
/// <param name="videoStream">Media stream information.</param>
/// <param name="mediaSource">Media source information.</param>
/// <param name="threedFormat">Video 3D format.</param>
/// <param name="interval">Time interval.</param>
/// <param name="targetDirectory">Directory to write images.</param>
/// <param name="filenamePrefix">Filename prefix to use.</param>
/// <param name="maxWidth">Maximum width of image.</param>
/// <param name="cancellationToken">CancellationToken to use for operation.</param>
/// <returns>A task.</returns>
Task ExtractVideoImagesOnInterval(
string inputFile,
string container,
MediaStream videoStream,
MediaSourceInfo mediaSource,
Video3DFormat? threedFormat,
TimeSpan interval,
string targetDirectory,
string filenamePrefix,
int? maxWidth,
CancellationToken cancellationToken);
Task<string> ExtractVideoImage(string inputFile, string container, MediaSourceInfo mediaSource, MediaStream imageStream, int? imageStreamIndex, ImageFormat? targetFormat, CancellationToken cancellationToken);
/// <summary>
/// Gets the media info.

View File

@@ -13,7 +13,6 @@ namespace MediaBrowser.Controller.MediaEncoding
{
public class JobLogger
{
private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
private readonly ILogger _logger;
public JobLogger(ILogger logger)
@@ -42,7 +41,7 @@ namespace MediaBrowser.Controller.MediaEncoding
break;
}
await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false);
await target.WriteAsync(bytes).ConfigureAwait(false);
// Check again, the stream could have been closed
if (!target.CanWrite)
@@ -87,7 +86,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var rate = parts[i + 1];
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
{
framerate = val;
}
@@ -96,7 +95,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var rate = part.Split('=', 2)[^1];
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
{
framerate = val;
}
@@ -106,7 +105,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
var time = part.Split('=', 2)[^1];
if (TimeSpan.TryParse(time, _usCulture, out var val))
if (TimeSpan.TryParse(time, CultureInfo.InvariantCulture, out var val))
{
var currentMs = startMs + val.TotalMilliseconds;
@@ -128,7 +127,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (scale.HasValue)
{
if (long.TryParse(size, NumberStyles.Any, _usCulture, out var val))
if (long.TryParse(size, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
{
bytesTranscoded = val * scale.Value;
}
@@ -147,7 +146,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (scale.HasValue)
{
if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val))
if (float.TryParse(rate, NumberStyles.Any, CultureInfo.InvariantCulture, out var val))
{
bitRate = (int)Math.Ceiling(val * scale.Value);
}

View File

@@ -20,4 +20,4 @@
/// </summary>
Dash
}
}
}

View File

@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Controller.Net
@@ -95,7 +96,7 @@ namespace MediaBrowser.Controller.Net
}
/// <inheritdoc />
public Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection) => Task.CompletedTask;
public Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection, HttpContext httpContext) => Task.CompletedTask;
/// <summary>
/// Starts sending messages over a web socket.

View File

@@ -29,12 +29,6 @@ namespace MediaBrowser.Controller.Net
/// <value>The date of last Keeplive received.</value>
DateTime LastKeepAliveDate { get; set; }
/// <summary>
/// Gets the query string.
/// </summary>
/// <value>The query string.</value>
IQueryCollection QueryString { get; }
/// <summary>
/// Gets or sets the receive action.
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace MediaBrowser.Controller.Net
{
@@ -18,7 +19,8 @@ namespace MediaBrowser.Controller.Net
/// Processes a new web socket connection.
/// </summary>
/// <param name="connection">An instance of the <see cref="IWebSocketConnection"/> interface.</param>
/// <param name="httpContext">The current http context.</param>
/// <returns>Task.</returns>
Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection);
Task ProcessWebSocketConnectedAsync(IWebSocketConnection connection, HttpContext httpContext);
}
}

View File

@@ -14,4 +14,4 @@ namespace MediaBrowser.Controller.Net
public long IntervalMs { get; set; }
}
}
}

View File

@@ -161,17 +161,17 @@ namespace MediaBrowser.Controller.Persistence
int GetCount(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetGenres(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetGenres(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetMusicGenres(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetMusicGenres(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetStudios(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetStudios(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetArtists(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAlbumArtists(InternalItemsQuery query);
QueryResult<(BaseItem, ItemCounts)> GetAllArtists(InternalItemsQuery query);
QueryResult<(BaseItem Item, ItemCounts ItemCounts)> GetAllArtists(InternalItemsQuery query);
List<string> GetMusicGenreNames();

View File

@@ -189,7 +189,7 @@ namespace MediaBrowser.Controller.Playlists
return LibraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
IncludeItemTypes = new[] { nameof(Audio) },
IncludeItemTypes = new[] { BaseItemKind.Audio },
GenreIds = new[] { musicGenre.Id },
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options
@@ -201,7 +201,7 @@ namespace MediaBrowser.Controller.Playlists
return LibraryManager.GetItemList(new InternalItemsQuery(user)
{
Recursive = true,
IncludeItemTypes = new[] { nameof(Audio) },
IncludeItemTypes = new[] { BaseItemKind.Audio },
ArtistIds = new[] { musicArtist.Id },
OrderBy = new[] { (ItemSortBy.AlbumArtist, SortOrder.Ascending), (ItemSortBy.Album, SortOrder.Ascending), (ItemSortBy.SortName, SortOrder.Ascending) },
DtoOptions = options

View File

@@ -12,11 +12,11 @@ namespace MediaBrowser.Controller.Providers
{
private readonly IFileSystem _fileSystem;
private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new (StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, FileSystemMetadata[]> _cache = new(StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new (StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, FileSystemMetadata> _fileCache = new(StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new (StringComparer.Ordinal);
private readonly ConcurrentDictionary<string, List<string>> _filePathCache = new(StringComparer.Ordinal);
public DirectoryService(IFileSystem fileSystem)
{
@@ -25,7 +25,7 @@ namespace MediaBrowser.Controller.Providers
public FileSystemMetadata[] GetFileSystemEntries(string path)
{
return _cache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
return _cache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem);
}
public List<FileSystemMetadata> GetFiles(string path)
@@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.Providers
_filePathCache.TryRemove(path, out _);
}
var filePaths = _filePathCache.GetOrAdd(path, (p, fileSystem) => fileSystem.GetFilePaths(p).ToList(), _fileSystem);
var filePaths = _filePathCache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFilePaths(p).ToList(), _fileSystem);
if (sort)
{

View File

@@ -1,5 +1,3 @@
#nullable disable
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
@@ -35,7 +33,7 @@ namespace MediaBrowser.Controller.Providers
/// <summary>
/// Gets the URL format string for this id.
/// </summary>
string UrlFormatString { get; }
string? UrlFormatString { get; }
/// <summary>
/// Determines whether this id supports a given item type.

View File

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

View File

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

View File

@@ -4,6 +4,7 @@
using System;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Providers;
@@ -58,7 +59,7 @@ namespace MediaBrowser.Controller.Providers
{
if (RefreshPaths != null && RefreshPaths.Length > 0)
{
return RefreshPaths.Contains(item.Path ?? string.Empty, StringComparer.OrdinalIgnoreCase);
return RefreshPaths.Contains(item.Path ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
return true;

View File

@@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Providers
{
// Images aren't always used so the allocation is a waste a lot of the time
private List<LocalImageInfo> _images;
private List<(string url, ImageType type)> _remoteImages;
private List<(string Url, ImageType Type)> _remoteImages;
public MetadataResult()
{
@@ -27,9 +27,9 @@ namespace MediaBrowser.Controller.Providers
set => _images = value;
}
public List<(string url, ImageType type)> RemoteImages
public List<(string Url, ImageType Type)> RemoteImages
{
get => _remoteImages ??= new List<(string url, ImageType type)>();
get => _remoteImages ??= new List<(string Url, ImageType Type)>();
set => _remoteImages = value;
}

View File

@@ -20,4 +20,4 @@
/// </summary>
Low = 2
}
}
}

View File

@@ -31,12 +31,14 @@ namespace MediaBrowser.Controller.Subtitles
/// <param name="video">The video.</param>
/// <param name="language">Subtitle language.</param>
/// <param name="isPerfectMatch">Require perfect match.</param>
/// <param name="isAutomated">Request is automated.</param>
/// <param name="cancellationToken">CancellationToken to use for the operation.</param>
/// <returns>Subtitles, wrapped in task.</returns>
Task<RemoteSubtitleInfo[]> SearchSubtitles(
Video video,
string language,
bool? isPerfectMatch,
bool isAutomated,
CancellationToken cancellationToken);
/// <summary>

View File

@@ -51,5 +51,7 @@ namespace MediaBrowser.Controller.Subtitles
public string[] DisabledSubtitleFetchers { get; set; }
public string[] SubtitleFetcherOrder { get; set; }
public bool IsAutomated { get; set; }
}
}

View File

@@ -17,11 +17,6 @@ namespace MediaBrowser.Controller.SyncPlay.GroupStates
/// </remarks>
public class PausedGroupState : AbstractGroupState
{
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<PausedGroupState> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="PausedGroupState"/> class.
/// </summary>
@@ -29,7 +24,6 @@ namespace MediaBrowser.Controller.SyncPlay.GroupStates
public PausedGroupState(ILoggerFactory loggerFactory)
: base(loggerFactory)
{
_logger = LoggerFactory.CreateLogger<PausedGroupState>();
}
/// <inheritdoc />

View File

@@ -17,11 +17,6 @@ namespace MediaBrowser.Controller.SyncPlay.GroupStates
/// </remarks>
public class PlayingGroupState : AbstractGroupState
{
/// <summary>
/// The logger.
/// </summary>
private readonly ILogger<PlayingGroupState> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="PlayingGroupState"/> class.
/// </summary>
@@ -29,7 +24,6 @@ namespace MediaBrowser.Controller.SyncPlay.GroupStates
public PlayingGroupState(ILoggerFactory loggerFactory)
: base(loggerFactory)
{
_logger = LoggerFactory.CreateLogger<PlayingGroupState>();
}
/// <inheritdoc />

View File

@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Model.SyncPlay;
namespace MediaBrowser.Controller.SyncPlay.Queue
@@ -19,10 +20,16 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
private const int NoPlayingItemIndex = -1;
/// <summary>
/// Random number generator used to shuffle lists.
/// The sorted playlist.
/// </summary>
/// <value>The random number generator.</value>
private readonly Random _randomNumberGenerator = new Random();
/// <value>The sorted playlist, or play queue of the group.</value>
private List<QueueItem> _sortedPlaylist = new List<QueueItem>();
/// <summary>
/// The shuffled playlist.
/// </summary>
/// <value>The shuffled playlist, or play queue of the group.</value>
private List<QueueItem> _shuffledPlaylist = new List<QueueItem>();
/// <summary>
/// Initializes a new instance of the <see cref="PlayQueueManager" /> class.
@@ -56,18 +63,6 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// <value>The repeat mode.</value>
public GroupRepeatMode RepeatMode { get; private set; } = GroupRepeatMode.RepeatNone;
/// <summary>
/// Gets or sets the sorted playlist.
/// </summary>
/// <value>The sorted playlist, or play queue of the group.</value>
private List<QueueItem> SortedPlaylist { get; set; } = new List<QueueItem>();
/// <summary>
/// Gets or sets the shuffled playlist.
/// </summary>
/// <value>The shuffled playlist, or play queue of the group.</value>
private List<QueueItem> ShuffledPlaylist { get; set; } = new List<QueueItem>();
/// <summary>
/// Checks if an item is playing.
/// </summary>
@@ -92,14 +87,14 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// <param name="items">The new items of the playlist.</param>
public void SetPlaylist(IReadOnlyList<Guid> items)
{
SortedPlaylist.Clear();
ShuffledPlaylist.Clear();
_sortedPlaylist.Clear();
_shuffledPlaylist.Clear();
SortedPlaylist = CreateQueueItemsFromArray(items);
_sortedPlaylist = CreateQueueItemsFromArray(items);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist);
Shuffle(ShuffledPlaylist);
_shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
_shuffledPlaylist.Shuffle();
}
PlayingItemIndex = NoPlayingItemIndex;
@@ -114,10 +109,10 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
var newItems = CreateQueueItemsFromArray(items);
SortedPlaylist.AddRange(newItems);
_sortedPlaylist.AddRange(newItems);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
ShuffledPlaylist.AddRange(newItems);
_shuffledPlaylist.AddRange(newItems);
}
LastChange = DateTime.UtcNow;
@@ -130,26 +125,26 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
if (PlayingItemIndex == NoPlayingItemIndex)
{
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist);
Shuffle(ShuffledPlaylist);
_shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
_shuffledPlaylist.Shuffle();
}
else if (ShuffleMode.Equals(GroupShuffleMode.Sorted))
{
// First time shuffle.
var playingItem = SortedPlaylist[PlayingItemIndex];
ShuffledPlaylist = new List<QueueItem>(SortedPlaylist);
ShuffledPlaylist.RemoveAt(PlayingItemIndex);
Shuffle(ShuffledPlaylist);
ShuffledPlaylist.Insert(0, playingItem);
var playingItem = _sortedPlaylist[PlayingItemIndex];
_shuffledPlaylist = new List<QueueItem>(_sortedPlaylist);
_shuffledPlaylist.RemoveAt(PlayingItemIndex);
_shuffledPlaylist.Shuffle();
_shuffledPlaylist.Insert(0, playingItem);
PlayingItemIndex = 0;
}
else
{
// Re-shuffle playlist.
var playingItem = ShuffledPlaylist[PlayingItemIndex];
ShuffledPlaylist.RemoveAt(PlayingItemIndex);
Shuffle(ShuffledPlaylist);
ShuffledPlaylist.Insert(0, playingItem);
var playingItem = _shuffledPlaylist[PlayingItemIndex];
_shuffledPlaylist.RemoveAt(PlayingItemIndex);
_shuffledPlaylist.Shuffle();
_shuffledPlaylist.Insert(0, playingItem);
PlayingItemIndex = 0;
}
@@ -164,11 +159,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
if (PlayingItemIndex != NoPlayingItemIndex)
{
var playingItem = ShuffledPlaylist[PlayingItemIndex];
PlayingItemIndex = SortedPlaylist.IndexOf(playingItem);
var playingItem = _shuffledPlaylist[PlayingItemIndex];
PlayingItemIndex = _sortedPlaylist.IndexOf(playingItem);
}
ShuffledPlaylist.Clear();
_shuffledPlaylist.Clear();
ShuffleMode = GroupShuffleMode.Sorted;
LastChange = DateTime.UtcNow;
@@ -181,16 +176,16 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
public void ClearPlaylist(bool clearPlayingItem)
{
var playingItem = GetPlayingItem();
SortedPlaylist.Clear();
ShuffledPlaylist.Clear();
_sortedPlaylist.Clear();
_shuffledPlaylist.Clear();
LastChange = DateTime.UtcNow;
if (!clearPlayingItem && playingItem != null)
{
SortedPlaylist.Add(playingItem);
_sortedPlaylist.Add(playingItem);
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
ShuffledPlaylist.Add(playingItem);
_shuffledPlaylist.Add(playingItem);
}
PlayingItemIndex = 0;
@@ -212,14 +207,14 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
var playingItem = GetPlayingItem();
var sortedPlayingItemIndex = SortedPlaylist.IndexOf(playingItem);
var sortedPlayingItemIndex = _sortedPlaylist.IndexOf(playingItem);
// Append items to sorted and shuffled playlist as they are.
SortedPlaylist.InsertRange(sortedPlayingItemIndex + 1, newItems);
ShuffledPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
_sortedPlaylist.InsertRange(sortedPlayingItemIndex + 1, newItems);
_shuffledPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
}
else
{
SortedPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
_sortedPlaylist.InsertRange(PlayingItemIndex + 1, newItems);
}
LastChange = DateTime.UtcNow;
@@ -298,8 +293,8 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
var playingItem = GetPlayingItem();
SortedPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
ShuffledPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
_sortedPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
_shuffledPlaylist.RemoveAll(item => playlistItemIds.Contains(item.PlaylistItemId));
LastChange = DateTime.UtcNow;
@@ -313,7 +308,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
// Was first element, picking next if available.
// Default to no playing item otherwise.
PlayingItemIndex = SortedPlaylist.Count > 0 ? 0 : NoPlayingItemIndex;
PlayingItemIndex = _sortedPlaylist.Count > 0 ? 0 : NoPlayingItemIndex;
}
return true;
@@ -363,8 +358,8 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
/// </summary>
public void Reset()
{
SortedPlaylist.Clear();
ShuffledPlaylist.Clear();
_sortedPlaylist.Clear();
_shuffledPlaylist.Clear();
PlayingItemIndex = NoPlayingItemIndex;
ShuffleMode = GroupShuffleMode.Sorted;
RepeatMode = GroupRepeatMode.RepeatNone;
@@ -460,7 +455,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
}
PlayingItemIndex++;
if (PlayingItemIndex >= SortedPlaylist.Count)
if (PlayingItemIndex >= _sortedPlaylist.Count)
{
if (RepeatMode.Equals(GroupRepeatMode.RepeatAll))
{
@@ -468,7 +463,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
}
else
{
PlayingItemIndex = SortedPlaylist.Count - 1;
PlayingItemIndex = _sortedPlaylist.Count - 1;
return false;
}
}
@@ -494,7 +489,7 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
if (RepeatMode.Equals(GroupRepeatMode.RepeatAll))
{
PlayingItemIndex = SortedPlaylist.Count - 1;
PlayingItemIndex = _sortedPlaylist.Count - 1;
}
else
{
@@ -507,23 +502,6 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
return true;
}
/// <summary>
/// Shuffles a given list.
/// </summary>
/// <param name="list">The list to shuffle.</param>
private void Shuffle<T>(IList<T> list)
{
int n = list.Count;
while (n > 1)
{
n--;
int k = _randomNumberGenerator.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
/// <summary>
/// Creates a list from the array of items. Each item is given an unique playlist identifier.
/// </summary>
@@ -548,11 +526,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
{
if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
return ShuffledPlaylist;
return _shuffledPlaylist;
}
else
{
return SortedPlaylist;
return _sortedPlaylist;
}
}
@@ -568,11 +546,11 @@ namespace MediaBrowser.Controller.SyncPlay.Queue
}
else if (ShuffleMode.Equals(GroupShuffleMode.Shuffle))
{
return ShuffledPlaylist[PlayingItemIndex];
return _shuffledPlaylist[PlayingItemIndex];
}
else
{
return SortedPlaylist[PlayingItemIndex];
return _sortedPlaylist[PlayingItemIndex];
}
}
}