diff options
| author | Luke Foust <luke@foust.com> | 2020-03-20 12:53:52 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-03-20 12:53:52 -0700 |
| commit | dcd0d93f44bf1befea5e61993bc868b5846102a0 (patch) | |
| tree | 740f132fce52947fc8a73621588ca36c3447922a /MediaBrowser.Controller | |
| parent | 80dfc78ba5ec3895fd374a5bd761d0d0e9e6a862 (diff) | |
| parent | e028fb6fdefa6120fc6109c63d883d21412c31bd (diff) | |
Merge pull request #1 from jellyfin/master
merge with upstream master
Diffstat (limited to 'MediaBrowser.Controller')
69 files changed, 522 insertions, 560 deletions
diff --git a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs index 3c65156e3..4249a9a66 100644 --- a/MediaBrowser.Controller/Authentication/AuthenticationResult.cs +++ b/MediaBrowser.Controller/Authentication/AuthenticationResult.cs @@ -1,14 +1,18 @@ +#pragma warning disable CS1591 + using MediaBrowser.Controller.Session; using MediaBrowser.Model.Dto; - namespace MediaBrowser.Controller.Authentication { public class AuthenticationResult { public UserDto User { get; set; } + public SessionInfo SessionInfo { get; set; } + public string AccessToken { get; set; } + public string ServerId { get; set; } } } diff --git a/MediaBrowser.Controller/Channels/IChannel.cs b/MediaBrowser.Controller/Channels/IChannel.cs index f8ed98a45..c44e20d1a 100644 --- a/MediaBrowser.Controller/Channels/IChannel.cs +++ b/MediaBrowser.Controller/Channels/IChannel.cs @@ -64,7 +64,7 @@ namespace MediaBrowser.Controller.Channels /// </summary> /// <param name="type">The type.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{DynamicImageInfo}.</returns> + /// <returns>Task{DynamicImageResponse}.</returns> Task<DynamicImageResponse> GetChannelImage(ImageType type, CancellationToken cancellationToken); /// <summary> diff --git a/MediaBrowser.Controller/Drawing/IImageProcessor.cs b/MediaBrowser.Controller/Drawing/IImageProcessor.cs index a58a11bd1..79399807f 100644 --- a/MediaBrowser.Controller/Drawing/IImageProcessor.cs +++ b/MediaBrowser.Controller/Drawing/IImageProcessor.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; @@ -21,19 +20,11 @@ namespace MediaBrowser.Controller.Drawing IReadOnlyCollection<string> SupportedInputFormats { get; } /// <summary> - /// Gets the image enhancers. - /// </summary> - /// <value>The image enhancers.</value> - IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; } - - /// <summary> /// Gets a value indicating whether [supports image collage creation]. /// </summary> /// <value><c>true</c> if [supports image collage creation]; otherwise, <c>false</c>.</value> bool SupportsImageCollageCreation { get; } - IImageEncoder ImageEncoder { get; set; } - /// <summary> /// Gets the dimensions of the image. /// </summary> @@ -59,14 +50,6 @@ namespace MediaBrowser.Controller.Drawing ImageDimensions GetImageDimensions(BaseItem item, ItemImageInfo info, bool updateItem); /// <summary> - /// Gets the supported enhancers. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <returns>IEnumerable{IImageEnhancer}.</returns> - IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType); - - /// <summary> /// Gets the image cache tag. /// </summary> /// <param name="item">The item.</param> @@ -76,15 +59,6 @@ namespace MediaBrowser.Controller.Drawing string GetImageCacheTag(BaseItem item, ChapterInfo info); /// <summary> - /// Gets the image cache tag. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="image">The image.</param> - /// <param name="imageEnhancers">The image enhancers.</param> - /// <returns>Guid.</returns> - string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers); - - /// <summary> /// Processes the image. /// </summary> /// <param name="options">The options.</param> @@ -100,15 +74,6 @@ namespace MediaBrowser.Controller.Drawing Task<(string path, string mimeType, DateTime dateModified)> ProcessImage(ImageProcessingOptions options); /// <summary> - /// Gets the enhanced image. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <param name="imageIndex">Index of the image.</param> - /// <returns>Task{System.String}.</returns> - Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex); - - /// <summary> /// Gets the supported image output formats. /// </summary> /// <returns><see cref="IReadOnlyCollection{ImageOutput}" />.</returns> diff --git a/MediaBrowser.Controller/Drawing/ImageHelper.cs b/MediaBrowser.Controller/Drawing/ImageHelper.cs index 432cf8042..d5a5f547e 100644 --- a/MediaBrowser.Controller/Drawing/ImageHelper.cs +++ b/MediaBrowser.Controller/Drawing/ImageHelper.cs @@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Drawing return GetSizeEstimate(options); } - public static IImageProcessor ImageProcessor { get; set; } - private static ImageDimensions GetSizeEstimate(ImageProcessingOptions options) { if (options.Width.HasValue && options.Height.HasValue) diff --git a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs index 29addf6e6..870e0278e 100644 --- a/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs +++ b/MediaBrowser.Controller/Drawing/ImageProcessingOptions.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Drawing; namespace MediaBrowser.Controller.Drawing @@ -34,8 +33,6 @@ namespace MediaBrowser.Controller.Drawing public int Quality { get; set; } - public IReadOnlyCollection<IImageEnhancer> Enhancers { get; set; } - public IReadOnlyCollection<ImageFormat> SupportedOutputFormats { get; set; } public bool AddPlayedIndicator { get; set; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index efe0d3cf7..5e3056ccb 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -198,6 +198,7 @@ namespace MediaBrowser.Controller.Entities.Audio return true; } } + return base.RequiresRefresh(); } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 1fd706857..623262407 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -19,7 +19,6 @@ using MediaBrowser.Controller.Sorting; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Library; @@ -34,7 +33,7 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Class BaseItem /// </summary> - public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo> + public abstract class BaseItem : IHasProviderIds, IHasLookupInfo<ItemLookupInfo>, IEquatable<BaseItem> { /// <summary> /// The supported image extensions @@ -388,15 +387,12 @@ namespace MediaBrowser.Controller.Entities while (thisMarker < s1.Length) { - if (thisMarker >= s1.Length) - { - break; - } char thisCh = s1[thisMarker]; var thisChunk = new StringBuilder(); + bool isNumeric = char.IsDigit(thisCh); - while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || SortHelper.InChunk(thisCh, thisChunk[0]))) + while (thisMarker < s1.Length && char.IsDigit(thisCh) == isNumeric) { thisChunk.Append(thisCh); thisMarker++; @@ -407,7 +403,6 @@ namespace MediaBrowser.Controller.Entities } } - var isNumeric = thisChunk.Length > 0 && char.IsDigit(thisChunk[0]); list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric)); } @@ -1098,6 +1093,7 @@ namespace MediaBrowser.Controller.Entities Id = item.Id.ToString("N", CultureInfo.InvariantCulture), Protocol = protocol ?? MediaProtocol.File, MediaStreams = MediaSourceManager.GetMediaStreams(item.Id), + MediaAttachments = MediaSourceManager.GetMediaAttachments(item.Id), Name = GetMediaSourceName(item), Path = enablePathSubstitution ? GetMappedPath(item, item.Path, protocol) : item.Path, RunTimeTicks = item.RunTimeTicks, @@ -2194,13 +2190,9 @@ namespace MediaBrowser.Controller.Entities /// <summary> /// Do whatever refreshing is necessary when the filesystem pertaining to this item has changed. /// </summary> - /// <returns>Task.</returns> public virtual void ChangedExternally() { - ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(new DirectoryService(FileSystem)) - { - - }, RefreshPriority.High); + ProviderManager.QueueRefresh(Id, new MetadataRefreshOptions(new DirectoryService(FileSystem)), RefreshPriority.High); } /// <summary> @@ -2231,7 +2223,6 @@ namespace MediaBrowser.Controller.Entities existingImage.Width = image.Width; existingImage.Height = image.Height; } - else { var current = ImageInfos; @@ -2274,7 +2265,6 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="type">The type.</param> /// <param name="index">The index.</param> - /// <returns>Task.</returns> public void DeleteImage(ImageType type, int index) { var info = GetImageInfo(type, index); @@ -2312,7 +2302,7 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// Validates that images within the item are still on the file system + /// Validates that images within the item are still on the filesystem. /// </summary> public bool ValidateImages(IDirectoryService directoryService) { @@ -2606,7 +2596,7 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// This is called before any metadata refresh and returns true if changes were made. /// </summary> public virtual bool BeforeMetadataRefresh(bool replaceAllMetdata) { @@ -2666,36 +2656,43 @@ namespace MediaBrowser.Controller.Entities newOptions.ForceSave = true; ownedItem.Genres = item.Genres; } + if (!item.Studios.SequenceEqual(ownedItem.Studios, StringComparer.Ordinal)) { newOptions.ForceSave = true; ownedItem.Studios = item.Studios; } + if (!item.ProductionLocations.SequenceEqual(ownedItem.ProductionLocations, StringComparer.Ordinal)) { newOptions.ForceSave = true; ownedItem.ProductionLocations = item.ProductionLocations; } + if (item.CommunityRating != ownedItem.CommunityRating) { ownedItem.CommunityRating = item.CommunityRating; newOptions.ForceSave = true; } + if (item.CriticRating != ownedItem.CriticRating) { ownedItem.CriticRating = item.CriticRating; newOptions.ForceSave = true; } + if (!string.Equals(item.Overview, ownedItem.Overview, StringComparison.Ordinal)) { ownedItem.Overview = item.Overview; newOptions.ForceSave = true; } + if (!string.Equals(item.OfficialRating, ownedItem.OfficialRating, StringComparison.Ordinal)) { ownedItem.OfficialRating = item.OfficialRating; newOptions.ForceSave = true; } + if (!string.Equals(item.CustomRating, ownedItem.CustomRating, StringComparison.Ordinal)) { ownedItem.CustomRating = item.CustomRating; @@ -2904,11 +2901,17 @@ namespace MediaBrowser.Controller.Entities } public virtual bool IsHD => Height >= 720; + public bool IsShortcut { get; set; } + public string ShortcutPath { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public Guid[] ExtraIds { get; set; } + public virtual long GetRunTimeTicksForPlayState() { return RunTimeTicks ?? 0; @@ -2918,5 +2921,17 @@ namespace MediaBrowser.Controller.Entities public static readonly IReadOnlyCollection<ExtraType> DisplayExtraTypes = new[] { Model.Entities.ExtraType.BehindTheScenes, Model.Entities.ExtraType.Clip, Model.Entities.ExtraType.DeletedScene, Model.Entities.ExtraType.Interview, Model.Entities.ExtraType.Sample, Model.Entities.ExtraType.Scene }; public virtual bool SupportsExternalTransfer => false; + + /// <inheritdoc /> + public override bool Equals(object obj) + { + return obj is BaseItem baseItem && this.Equals(baseItem); + } + + /// <inheritdoc /> + public bool Equals(BaseItem item) => Object.Equals(Id, item?.Id); + + /// <inheritdoc /> + public override int GetHashCode() => HashCode.Combine(Id); } } diff --git a/MediaBrowser.Controller/Entities/Book.cs b/MediaBrowser.Controller/Entities/Book.cs index 44c35374d..dcad2554b 100644 --- a/MediaBrowser.Controller/Entities/Book.cs +++ b/MediaBrowser.Controller/Entities/Book.cs @@ -13,8 +13,10 @@ namespace MediaBrowser.Controller.Entities [JsonIgnore] public string SeriesPresentationUniqueKey { get; set; } + [JsonIgnore] public string SeriesName { get; set; } + [JsonIgnore] public Guid SeriesId { get; set; } @@ -22,10 +24,12 @@ namespace MediaBrowser.Controller.Entities { return SeriesName; } + public string FindSeriesName() { return SeriesName; } + public string FindSeriesPresentationUniqueKey() { return SeriesPresentationUniqueKey; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 07fbe6035..c72bd487e 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -322,10 +322,10 @@ namespace MediaBrowser.Controller.Entities ProviderManager.OnRefreshProgress(this, 5); } - //build a dictionary of the current children we have now by Id so we can compare quickly and easily + // Build a dictionary of the current children we have now by Id so we can compare quickly and easily var currentChildren = GetActualChildrenDictionary(); - //create a list for our validated children + // Create a list for our validated children var newItems = new List<BaseItem>(); cancellationToken.ThrowIfCancellationRequested(); @@ -391,7 +391,7 @@ namespace MediaBrowser.Controller.Entities var folder = this; innerProgress.RegisterAction(p => { - double newPct = .80 * p + 10; + double newPct = 0.80 * p + 10; progress.Report(newPct); ProviderManager.OnRefreshProgress(folder, newPct); }); @@ -421,7 +421,7 @@ namespace MediaBrowser.Controller.Entities var folder = this; innerProgress.RegisterAction(p => { - double newPct = .10 * p + 90; + double newPct = 0.10 * p + 90; progress.Report(newPct); if (recursive) { @@ -807,11 +807,45 @@ namespace MediaBrowser.Controller.Entities return false; } + private static BaseItem[] SortItemsByRequest(InternalItemsQuery query, IReadOnlyList<BaseItem> items) + { + var ids = query.ItemIds; + int size = items.Count; + + // ids can potentially contain non-unique guids, but query result cannot, + // so we include only first occurrence of each guid + var positions = new Dictionary<Guid, int>(size); + int index = 0; + for (int i = 0; i < ids.Length; i++) + { + if (positions.TryAdd(ids[i], index)) + { + index++; + } + } + + var newItems = new BaseItem[size]; + for (int i = 0; i < size; i++) + { + var item = items[i]; + newItems[positions[item.Id]] = item; + } + + return newItems; + } + public QueryResult<BaseItem> GetItems(InternalItemsQuery query) { if (query.ItemIds.Length > 0) { - return LibraryManager.GetItemsResult(query); + var result = LibraryManager.GetItemsResult(query); + + if (query.OrderBy.Count == 0 && query.ItemIds.Length > 1) + { + result.Items = SortItemsByRequest(query, result.Items); + } + + return result; } return GetItemsInternal(query); @@ -823,7 +857,14 @@ namespace MediaBrowser.Controller.Entities if (query.ItemIds.Length > 0) { - return LibraryManager.GetItemList(query); + var result = LibraryManager.GetItemList(query); + + if (query.OrderBy.Count == 0 && query.ItemIds.Length > 1) + { + return SortItemsByRequest(query, result); + } + + return result.ToArray(); } return GetItemsInternal(query).Items; diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index d9b4b2206..64e216e69 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -135,57 +135,4 @@ namespace MediaBrowser.Controller.Entities return hasChanges; } } - - /// <summary> - /// This is the small Person stub that is attached to BaseItems - /// </summary> - public class PersonInfo : IHasProviderIds - { - public PersonInfo() - { - ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - } - - public Guid ItemId { get; set; } - - /// <summary> - /// Gets or sets the name. - /// </summary> - /// <value>The name.</value> - public string Name { get; set; } - /// <summary> - /// Gets or sets the role. - /// </summary> - /// <value>The role.</value> - public string Role { get; set; } - /// <summary> - /// Gets or sets the type. - /// </summary> - /// <value>The type.</value> - public string Type { get; set; } - - /// <summary> - /// Gets or sets the sort order - ascending - /// </summary> - /// <value>The sort order.</value> - public int? SortOrder { get; set; } - - public string ImageUrl { get; set; } - - public Dictionary<string, string> ProviderIds { get; set; } - - /// <summary> - /// Returns a <see cref="string" /> that represents this instance. - /// </summary> - /// <returns>A <see cref="string" /> that represents this instance.</returns> - public override string ToString() - { - return Name; - } - - public bool IsType(string type) - { - return string.Equals(Type, type, StringComparison.OrdinalIgnoreCase) || string.Equals(Role, type, StringComparison.OrdinalIgnoreCase); - } - } } diff --git a/MediaBrowser.Controller/Entities/PersonInfo.cs b/MediaBrowser.Controller/Entities/PersonInfo.cs new file mode 100644 index 000000000..e90c55a8a --- /dev/null +++ b/MediaBrowser.Controller/Entities/PersonInfo.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.Entities +{ + /// <summary> + /// This is a small Person stub that is attached to BaseItems. + /// </summary> + public sealed class PersonInfo : IHasProviderIds + { + public PersonInfo() + { + ProviderIds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); + } + + public Guid ItemId { get; set; } + + /// <summary> + /// Gets or sets the name. + /// </summary> + /// <value>The name.</value> + public string Name { get; set; } + + /// <summary> + /// Gets or sets the role. + /// </summary> + /// <value>The role.</value> + public string Role { get; set; } + + /// <summary> + /// Gets or sets the type. + /// </summary> + /// <value>The type.</value> + public string Type { get; set; } + + /// <summary> + /// Gets or sets the ascending sort order. + /// </summary> + /// <value>The sort order.</value> + public int? SortOrder { get; set; } + + public string ImageUrl { get; set; } + + public Dictionary<string, string> ProviderIds { get; set; } + + /// <summary> + /// Returns a <see cref="string" /> that represents this instance. + /// </summary> + /// <returns>A <see cref="string" /> that represents this instance.</returns> + public override string ToString() + { + return Name; + } + + public bool IsType(string type) + { + return string.Equals(Type, type, StringComparison.OrdinalIgnoreCase) + || string.Equals(Role, type, StringComparison.OrdinalIgnoreCase); + } + } +} diff --git a/MediaBrowser.Controller/Entities/Photo.cs b/MediaBrowser.Controller/Entities/Photo.cs index 86d62add9..5ebc9f16a 100644 --- a/MediaBrowser.Controller/Entities/Photo.cs +++ b/MediaBrowser.Controller/Entities/Photo.cs @@ -41,10 +41,10 @@ namespace MediaBrowser.Controller.Entities public override double GetDefaultPrimaryImageAspectRatio() { // REVIEW: @bond - if (Width.HasValue && Height.HasValue) + if (Width != 0 && Height != 0) { - double width = Width.Value; - double height = Height.Value; + double width = Width; + double height = Height; if (Orientation.HasValue) { @@ -67,8 +67,6 @@ namespace MediaBrowser.Controller.Entities return base.GetDefaultPrimaryImageAspectRatio(); } - public new int? Width { get; set; } - public new int? Height { get; set; } public string CameraMake { get; set; } public string CameraModel { get; set; } public string Software { get; set; } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index 7fcf48a48..8a68f830c 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -60,14 +60,7 @@ namespace MediaBrowser.Controller.Entities PresetViews = query.PresetViews }); - var itemsArray = result; - var totalCount = itemsArray.Length; - - return new QueryResult<BaseItem> - { - TotalRecordCount = totalCount, - Items = itemsArray //TODO Fix The co-variant conversion between Folder[] and BaseItem[], this can generate runtime issues. - }; + return UserViewBuilder.SortAndPage(result, null, query, LibraryManager, true); } public override int GetChildCount(User user) diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index af4d227bc..c3ea7f347 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -7,7 +7,6 @@ using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index 76c9b4b26..48316499a 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -13,24 +13,37 @@ namespace MediaBrowser.Controller.Extensions public const string FfmpegProbeSizeKey = "FFmpeg:probesize"; /// <summary> - /// The key for the FFmpeg analyse duration option. + /// The key for the FFmpeg analyze duration option. /// </summary> public const string FfmpegAnalyzeDurationKey = "FFmpeg:analyzeduration"; /// <summary> - /// Retrieves the FFmpeg probe size from the <see cref="IConfiguration" />. + /// The key for a setting that indicates whether playlists should allow duplicate entries. /// </summary> - /// <param name="configuration">This configuration.</param> + public const string PlaylistsAllowDuplicatesKey = "playlists:allowDuplicates"; + + /// <summary> + /// Gets the FFmpeg probe size from the <see cref="IConfiguration" />. + /// </summary> + /// <param name="configuration">The configuration to read the setting from.</param> /// <returns>The FFmpeg probe size option.</returns> public static string GetFFmpegProbeSize(this IConfiguration configuration) => configuration[FfmpegProbeSizeKey]; /// <summary> - /// Retrieves the FFmpeg analyse duration from the <see cref="IConfiguration" />. + /// Gets the FFmpeg analyze duration from the <see cref="IConfiguration" />. /// </summary> - /// <param name="configuration">This configuration.</param> - /// <returns>The FFmpeg analyse duration option.</returns> + /// <param name="configuration">The configuration to read the setting from.</param> + /// <returns>The FFmpeg analyze duration option.</returns> public static string GetFFmpegAnalyzeDuration(this IConfiguration configuration) => configuration[FfmpegAnalyzeDurationKey]; + + /// <summary> + /// Gets a value indicating whether playlists should allow duplicate entries from the <see cref="IConfiguration"/>. + /// </summary> + /// <param name="configuration">The configuration to read the setting from.</param> + /// <returns>True if playlists should allow duplicates, otherwise false.</returns> + public static bool DoPlaylistsAllowDuplicates(this IConfiguration configuration) + => configuration.GetValue<bool>(PlaylistsAllowDuplicatesKey); } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index b3c56bdd5..25f0905eb 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -71,13 +71,15 @@ namespace MediaBrowser.Controller /// <summary> /// Gets the local API URL. /// </summary> - /// <param name="host">The host.</param> - /// <returns>System.String.</returns> - string GetLocalApiUrl(string host); + /// <param name="hostname">The hostname.</param> + /// <returns>The local API URL.</returns> + string GetLocalApiUrl(ReadOnlySpan<char> hostname); /// <summary> /// Gets the local API URL. /// </summary> + /// <param name="address">The IP address.</param> + /// <returns>The local API URL.</returns> string GetLocalApiUrl(IPAddress address); void LaunchUrl(string url); diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index 511356aa4..2e1c97f67 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -157,7 +157,8 @@ namespace MediaBrowser.Controller.Library /// <param name="introProviders">The intro providers.</param> /// <param name="itemComparers">The item comparers.</param> /// <param name="postscanTasks">The postscan tasks.</param> - void AddParts(IEnumerable<IResolverIgnoreRule> rules, + void AddParts( + IEnumerable<IResolverIgnoreRule> rules, IEnumerable<IItemResolver> resolvers, IEnumerable<IIntroProvider> introProviders, IEnumerable<IBaseItemComparer> itemComparers, @@ -349,9 +350,6 @@ namespace MediaBrowser.Controller.Library /// <returns><c>true</c> if [is audio file] [the specified path]; otherwise, <c>false</c>.</returns> bool IsAudioFile(string path); - bool IsAudioFile(string path, LibraryOptions libraryOptions); - bool IsVideoFile(string path, LibraryOptions libraryOptions); - /// <summary> /// Gets the season number from path. /// </summary> diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index fbae4edb0..0ceabd0e6 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -39,9 +39,23 @@ namespace MediaBrowser.Controller.Library List<MediaStream> GetMediaStreams(MediaStreamQuery query); /// <summary> + /// Gets the media attachments. + /// </summary> + /// <param name="itemId">The item identifier.</param> + /// <returns>IEnumerable<MediaAttachment>.</returns> + List<MediaAttachment> GetMediaAttachments(Guid itemId); + + /// <summary> + /// Gets the media attachments. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>IEnumerable<MediaAttachment>.</returns> + List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query); + + /// <summary> /// Gets the playack media sources. /// </summary> - Task<List<MediaSourceInfo>> GetPlayackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); + Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken); /// <summary> /// Gets the static media sources. diff --git a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs index 9e74879fc..ec7798551 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceProvider.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceProvider.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; diff --git a/MediaBrowser.Controller/Library/Profiler.cs b/MediaBrowser.Controller/Library/Profiler.cs index 9fe175a7c..46a97d181 100644 --- a/MediaBrowser.Controller/Library/Profiler.cs +++ b/MediaBrowser.Controller/Library/Profiler.cs @@ -28,7 +28,7 @@ namespace MediaBrowser.Controller.Library /// </summary> /// <param name="name">The name.</param> /// <param name="logger">The logger.</param> - public Profiler(string name, ILogger logger) + public Profiler(string name, ILogger<Profiler> logger) { this._name = name; diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 60c76ef7d..bcca9e4a1 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -8,7 +8,8 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.0" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.1" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.1" /> </ItemGroup> <ItemGroup> @@ -26,4 +27,16 @@ <GenerateDocumentationFile>true</GenerateDocumentationFile> </PropertyGroup> + <!-- Code Analyzers--> + <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> + <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> + <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" /> + <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> + </ItemGroup> + + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + </Project> diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 020f0553e..342c76414 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -475,7 +475,7 @@ namespace MediaBrowser.Controller.MediaEncoding .Append(' '); } - if (state.IsVideoRequest + if (state.IsVideoRequest && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) { var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); @@ -486,11 +486,11 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)) { arg.Append("-hwaccel qsv "); - } - else + } + else { arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); - } + } } arg.Append(videoDecoder + " "); @@ -653,7 +653,7 @@ namespace MediaBrowser.Controller.MediaEncoding // _fileSystem.CreateDirectory(_fileSystem.GetDirectoryName(fallbackFontPath)); // using (var stream = _assemblyInfo.GetManifestResourceStream(GetType(), GetType().Namespace + ".DroidSansFallback.ttf")) // { - // using (var fileStream = _fileSystem.GetFileStream(fallbackFontPath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read)) + // using (var fileStream = new FileStream(fallbackFontPath, FileMode.Create, FileAccess.Write, FileShare.Read)) // { // stream.CopyTo(fileStream); // } @@ -1624,22 +1624,22 @@ namespace MediaBrowser.Controller.MediaEncoding // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\""; - if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) { /* QSV in FFMpeg can now setup hardware overlay for transcodes. For software decoding and hardware encoding option, frames must be hwuploaded into hardware - with fixed frame size. + with fixed frame size. */ if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)) { retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; - } - else + } + else { retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwupload=extra_hw_frames=64[v];[v][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; } - } + } return string.Format( CultureInfo.InvariantCulture, @@ -1731,8 +1731,8 @@ namespace MediaBrowser.Controller.MediaEncoding vaapi_or_qsv, outputWidth, outputHeight)); - } - else + } + else { filters.Add(string.Format(CultureInfo.InvariantCulture, "scale_{0}=format=nv12", vaapi_or_qsv)); } @@ -1979,8 +1979,8 @@ namespace MediaBrowser.Controller.MediaEncoding var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); - // If we are software decoding, and hardware encoding - if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) + // If we are software decoding, and hardware encoding + if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase) && (string.IsNullOrEmpty(videoDecoder) || !videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase))) { filters.Add("format=nv12|qsv"); @@ -2642,22 +2642,9 @@ namespace MediaBrowser.Controller.MediaEncoding else return "-hwaccel dxva2"; } - - switch (videoStream.Codec.ToLowerInvariant()) + else { - case "avc": - case "h264": - if (_mediaEncoder.SupportsDecoder("h264_amf") && encodingOptions.HardwareDecodingCodecs.Contains("h264", StringComparer.OrdinalIgnoreCase)) - { - return "-c:v h264_amf"; - } - break; - case "mpeg2video": - if (_mediaEncoder.SupportsDecoder("hevc_amf") && encodingOptions.HardwareDecodingCodecs.Contains("mpeg2video", StringComparer.OrdinalIgnoreCase)) - { - return "-c:v mpeg2_mmal"; - } - break; + return "-hwaccel vaapi"; } } } @@ -2770,7 +2757,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (!state.RunTimeTicks.HasValue) { - args += " -flags -global_header -fflags +genpts"; + args += " -fflags +genpts"; } } else @@ -2815,11 +2802,6 @@ namespace MediaBrowser.Controller.MediaEncoding { args += " " + qualityParam.Trim(); } - - if (!state.RunTimeTicks.HasValue) - { - args += " -flags -global_header"; - } } if (!string.IsNullOrEmpty(state.OutputVideoSync)) diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index 34af3b156..38ef33caf 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -316,11 +316,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) { - var size = new ImageDimensions - { - Width = VideoStream.Width.Value, - Height = VideoStream.Height.Value - }; + var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value); var newSize = DrawingUtils.Resize(size, BaseRequest.Width ?? 0, @@ -346,11 +342,7 @@ namespace MediaBrowser.Controller.MediaEncoding { if (VideoStream != null && VideoStream.Width.HasValue && VideoStream.Height.HasValue) { - var size = new ImageDimensions - { - Width = VideoStream.Width.Value, - Height = VideoStream.Height.Value - }; + var size = new ImageDimensions(VideoStream.Width.Value, VideoStream.Height.Value); var newSize = DrawingUtils.Resize(size, BaseRequest.Width ?? 0, @@ -665,7 +657,7 @@ namespace MediaBrowser.Controller.MediaEncoding } public IProgress<double> Progress { get; set; } - public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float framerate, double? percentComplete, long bytesTranscoded, int? bitRate) + public virtual void ReportTranscodingProgress(TimeSpan? transcodingPosition, float? framerate, double? percentComplete, long? bytesTranscoded, int? bitRate) { Progress.Report(percentComplete.Value); } diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs index d64feb2f7..addc88174 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobOptions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Services; diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs new file mode 100644 index 000000000..7c7e84de6 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -0,0 +1,17 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.MediaEncoding +{ + public interface IAttachmentExtractor + { + Task<(MediaAttachment attachment, Stream stream)> GetAttachment( + BaseItem item, + string mediaSourceId, + int attachmentStreamIndex, + CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs index ac989f6ba..c9f64c707 100644 --- a/MediaBrowser.Controller/MediaEncoding/JobLogger.cs +++ b/MediaBrowser.Controller/MediaEncoding/JobLogger.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; -using MediaBrowser.Model.Extensions; using Microsoft.Extensions.Logging; namespace MediaBrowser.Controller.MediaEncoding @@ -90,6 +89,15 @@ namespace MediaBrowser.Controller.MediaEncoding framerate = val; } } + else if (part.StartsWith("fps=", StringComparison.OrdinalIgnoreCase)) + { + var rate = part.Split(new[] { '=' }, 2)[^1]; + + if (float.TryParse(rate, NumberStyles.Any, _usCulture, out var val)) + { + framerate = val; + } + } else if (state.RunTimeTicks.HasValue && part.StartsWith("time=", StringComparison.OrdinalIgnoreCase)) { @@ -146,7 +154,7 @@ namespace MediaBrowser.Controller.MediaEncoding if (framerate.HasValue || percent.HasValue) { - state.ReportTranscodingProgress(transcodingPosition, 0, percent, 0, bitRate); + state.ReportTranscodingProgress(transcodingPosition, framerate, percent, bytesTranscoded, bitRate); } } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index ee5c1a165..b710318ee 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -22,7 +22,7 @@ namespace MediaBrowser.Controller.Net /// <summary> /// The _active connections /// </summary> - protected readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> ActiveConnections = + private readonly List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>> _activeConnections = new List<Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>>(); /// <summary> @@ -100,9 +100,9 @@ namespace MediaBrowser.Controller.Net InitialDelayMs = dueTimeMs }; - lock (ActiveConnections) + lock (_activeConnections) { - ActiveConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>(message.Connection, cancellationTokenSource, state)); + _activeConnections.Add(new Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>(message.Connection, cancellationTokenSource, state)); } } @@ -110,9 +110,9 @@ namespace MediaBrowser.Controller.Net { Tuple<IWebSocketConnection, CancellationTokenSource, TStateType>[] tuples; - lock (ActiveConnections) + lock (_activeConnections) { - tuples = ActiveConnections + tuples = _activeConnections .Where(c => { if (c.Item1.State == WebSocketState.Open && !c.Item2.IsCancellationRequested) @@ -180,9 +180,9 @@ namespace MediaBrowser.Controller.Net /// <param name="message">The message.</param> private void Stop(WebSocketMessageInfo message) { - lock (ActiveConnections) + lock (_activeConnections) { - var connection = ActiveConnections.FirstOrDefault(c => c.Item1 == message.Connection); + var connection = _activeConnections.FirstOrDefault(c => c.Item1 == message.Connection); if (connection != null) { @@ -212,9 +212,9 @@ namespace MediaBrowser.Controller.Net //TODO Investigate and properly fix. } - lock (ActiveConnections) + lock (_activeConnections) { - ActiveConnections.Remove(connection); + _activeConnections.Remove(connection); } } @@ -226,9 +226,9 @@ namespace MediaBrowser.Controller.Net { if (dispose) { - lock (ActiveConnections) + lock (_activeConnections) { - foreach (var connection in ActiveConnections.ToArray()) + foreach (var connection in _activeConnections.ToArray()) { DisposeConnection(connection); } diff --git a/MediaBrowser.Controller/Net/IAuthService.cs b/MediaBrowser.Controller/Net/IAuthService.cs index 4c9120e0c..9132404a0 100644 --- a/MediaBrowser.Controller/Net/IAuthService.cs +++ b/MediaBrowser.Controller/Net/IAuthService.cs @@ -1,3 +1,5 @@ +#nullable enable + using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; @@ -7,6 +9,6 @@ namespace MediaBrowser.Controller.Net public interface IAuthService { void Authenticate(IRequest request, IAuthenticationAttributes authAttribtues); - User Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); + User? Authenticate(HttpRequest request, IAuthenticationAttributes authAttribtues); } } diff --git a/MediaBrowser.Controller/Net/IHttpResultFactory.cs b/MediaBrowser.Controller/Net/IHttpResultFactory.cs index ff9ecf8af..25404fa78 100644 --- a/MediaBrowser.Controller/Net/IHttpResultFactory.cs +++ b/MediaBrowser.Controller/Net/IHttpResultFactory.cs @@ -2,8 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; - -using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; namespace MediaBrowser.Controller.Net @@ -66,7 +64,7 @@ namespace MediaBrowser.Controller.Net /// <param name="path">The path.</param> /// <param name="fileShare">The file share.</param> /// <returns>System.Object.</returns> - Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShareMode fileShare = FileShareMode.Read); + Task<object> GetStaticFileResult(IRequest requestContext, string path, FileShare fileShare = FileShare.Read); /// <summary> /// Gets the static file result. diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 566897b31..31eb7ccb7 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -3,7 +3,6 @@ using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Net; -using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller.Net diff --git a/MediaBrowser.Controller/Net/StaticResultOptions.cs b/MediaBrowser.Controller/Net/StaticResultOptions.cs index 7a179913a..071beaed1 100644 --- a/MediaBrowser.Controller/Net/StaticResultOptions.cs +++ b/MediaBrowser.Controller/Net/StaticResultOptions.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; -using MediaBrowser.Model.IO; - namespace MediaBrowser.Controller.Net { public class StaticResultOptions @@ -24,12 +22,12 @@ namespace MediaBrowser.Controller.Net public string Path { get; set; } public long? ContentLength { get; set; } - public FileShareMode FileShare { get; set; } + public FileShare FileShare { get; set; } public StaticResultOptions() { ResponseHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); - FileShare = FileShareMode.Read; + FileShare = FileShare.Read; } } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 47e0f3453..5a5b7f58f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -79,6 +79,21 @@ namespace MediaBrowser.Controller.Persistence void SaveMediaStreams(Guid id, List<MediaStream> streams, CancellationToken cancellationToken); /// <summary> + /// Gets the media attachments. + /// </summary> + /// <param name="query">The query.</param> + /// <returns>IEnumerable{MediaAttachment}.</returns> + List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query); + + /// <summary> + /// Saves the media attachments. + /// </summary> + /// <param name="id">The identifier.</param> + /// <param name="attachments">The attachments.</param> + /// <param name="cancellationToken">The cancellation token.</param> + void SaveMediaAttachments(Guid id, IReadOnlyList<MediaAttachment> attachments, CancellationToken cancellationToken); + + /// <summary> /// Gets the item ids. /// </summary> /// <param name="query">The query.</param> diff --git a/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs new file mode 100644 index 000000000..e3b2d4665 --- /dev/null +++ b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs @@ -0,0 +1,19 @@ +using System; + +namespace MediaBrowser.Controller.Persistence +{ + public class MediaAttachmentQuery + { + /// <summary> + /// Gets or sets the index. + /// </summary> + /// <value>The index.</value> + public int? Index { get; set; } + + /// <summary> + /// Gets or sets the item identifier. + /// </summary> + /// <value>The item identifier.</value> + public Guid ItemId { get; set; } + } +} diff --git a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs index 5001f6842..544cd2643 100644 --- a/MediaBrowser.Controller/Playlists/IPlaylistManager.cs +++ b/MediaBrowser.Controller/Playlists/IPlaylistManager.cs @@ -29,7 +29,7 @@ namespace MediaBrowser.Controller.Playlists /// <param name="itemIds">The item ids.</param> /// <param name="userId">The user identifier.</param> /// <returns>Task.</returns> - void AddToPlaylist(string playlistId, IEnumerable<Guid> itemIds, Guid userId); + void AddToPlaylist(string playlistId, ICollection<Guid> itemIds, Guid userId); /// <summary> /// Removes from playlist. diff --git a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs index e57929989..1e8654c4d 100644 --- a/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs +++ b/MediaBrowser.Controller/Plugins/IServerEntryPoint.cs @@ -4,16 +4,22 @@ using System.Threading.Tasks; namespace MediaBrowser.Controller.Plugins { /// <summary> - /// Interface IServerEntryPoint + /// Represents an entry point for a module in the application. This interface is scanned for automatically and + /// provides a hook to initialize the module at application start. + /// The entry point can additionally be flagged as a pre-startup task by implementing the + /// <see cref="IRunBeforeStartup"/> interface. /// </summary> public interface IServerEntryPoint : IDisposable { /// <summary> - /// Runs this instance. + /// Run the initialization for this module. This method is invoked at application start. /// </summary> Task RunAsync(); } + /// <summary> + /// Indicates that a <see cref="IServerEntryPoint"/> should be invoked as a pre-startup task. + /// </summary> public interface IRunBeforeStartup { diff --git a/MediaBrowser.Controller/Providers/AlbumInfo.cs b/MediaBrowser.Controller/Providers/AlbumInfo.cs index ac6b86c1d..dbda4843f 100644 --- a/MediaBrowser.Controller/Providers/AlbumInfo.cs +++ b/MediaBrowser.Controller/Providers/AlbumInfo.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.Controller.Providers /// </summary> /// <value>The artist provider ids.</value> public Dictionary<string, string> ArtistProviderIds { get; set; } + public List<SongInfo> SongInfos { get; set; } public AlbumInfo() diff --git a/MediaBrowser.Controller/Providers/BoxSetInfo.cs b/MediaBrowser.Controller/Providers/BoxSetInfo.cs index 4cbe2d6ef..d23f2b9bf 100644 --- a/MediaBrowser.Controller/Providers/BoxSetInfo.cs +++ b/MediaBrowser.Controller/Providers/BoxSetInfo.cs @@ -2,6 +2,5 @@ namespace MediaBrowser.Controller.Providers { public class BoxSetInfo : ItemLookupInfo { - } } diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 303b03a21..ca470872b 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -26,7 +26,6 @@ namespace MediaBrowser.Controller.Providers { entries = _fileSystem.GetFileSystemEntries(path).ToArray(); - //_cache.TryAdd(path, entries); _cache[path] = entries; } @@ -56,7 +55,6 @@ namespace MediaBrowser.Controller.Providers if (file != null && file.Exists) { - //_fileCache.TryAdd(path, file); _fileCache[path] = file; } else @@ -66,7 +64,6 @@ namespace MediaBrowser.Controller.Providers } return file; - //return _fileSystem.GetFileInfo(path); } public List<string> GetFilePaths(string path) diff --git a/MediaBrowser.Controller/Providers/DynamicImageInfo.cs b/MediaBrowser.Controller/Providers/DynamicImageInfo.cs deleted file mode 100644 index 0791783c6..000000000 --- a/MediaBrowser.Controller/Providers/DynamicImageInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public class DynamicImageInfo - { - public string ImageId { get; set; } - public ImageType Type { get; set; } - } -} diff --git a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs index 11c7ccbe5..7c1371702 100644 --- a/MediaBrowser.Controller/Providers/DynamicImageResponse.cs +++ b/MediaBrowser.Controller/Providers/DynamicImageResponse.cs @@ -8,9 +8,13 @@ namespace MediaBrowser.Controller.Providers public class DynamicImageResponse { public string Path { get; set; } + public MediaProtocol Protocol { get; set; } + public Stream Stream { get; set; } + public ImageFormat Format { get; set; } + public bool HasImage { get; set; } public void SetFormatFromMimeType(string mimeType) diff --git a/MediaBrowser.Controller/Providers/EpisodeInfo.cs b/MediaBrowser.Controller/Providers/EpisodeInfo.cs index 6ecf4edc5..55c41ff82 100644 --- a/MediaBrowser.Controller/Providers/EpisodeInfo.cs +++ b/MediaBrowser.Controller/Providers/EpisodeInfo.cs @@ -10,6 +10,7 @@ namespace MediaBrowser.Controller.Providers public int? IndexNumberEnd { get; set; } public bool IsMissingEpisode { get; set; } + public string SeriesDisplayOrder { get; set; } public EpisodeInfo() diff --git a/MediaBrowser.Controller/Providers/ExtraInfo.cs b/MediaBrowser.Controller/Providers/ExtraInfo.cs deleted file mode 100644 index 413ff2e78..000000000 --- a/MediaBrowser.Controller/Providers/ExtraInfo.cs +++ /dev/null @@ -1,15 +0,0 @@ -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public class ExtraInfo - { - public string Path { get; set; } - - public LocationType LocationType { get; set; } - - public bool IsDownloadable { get; set; } - - public ExtraType ExtraType { get; set; } - } -} diff --git a/MediaBrowser.Controller/Providers/ExtraSource.cs b/MediaBrowser.Controller/Providers/ExtraSource.cs deleted file mode 100644 index 46b246fbc..000000000 --- a/MediaBrowser.Controller/Providers/ExtraSource.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - public enum ExtraSource - { - Local = 1, - Metadata = 2, - Remote = 3 - } -} diff --git a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs index 2d5a0b364..6b4c9feb5 100644 --- a/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/ICustomMetadataProvider.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.Controller.Providers where TItemType : BaseItem { /// <summary> - /// Fetches the asynchronous. + /// Fetches the metadata asynchronously. /// </summary> /// <param name="item">The item.</param> /// <param name="options">The options.</param> diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index 8059d2bd1..b304fc335 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -6,10 +6,13 @@ namespace MediaBrowser.Controller.Providers public interface IDirectoryService { FileSystemMetadata[] GetFileSystemEntries(string path); + List<FileSystemMetadata> GetFiles(string path); + FileSystemMetadata GetFile(string path); List<string> GetFilePaths(string path); + List<string> GetFilePaths(string path, bool clearCache); } } diff --git a/MediaBrowser.Controller/Providers/IExtrasProvider.cs b/MediaBrowser.Controller/Providers/IExtrasProvider.cs deleted file mode 100644 index fa31635cb..000000000 --- a/MediaBrowser.Controller/Providers/IExtrasProvider.cs +++ /dev/null @@ -1,20 +0,0 @@ -using MediaBrowser.Controller.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public interface IExtrasProvider - { - /// <summary> - /// Gets the name. - /// </summary> - /// <value>The name.</value> - string Name { get; } - - /// <summary> - /// Supportses the specified item. - /// </summary> - /// <param name="item">The item.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns> - bool Supports(BaseItem item); - } -} diff --git a/MediaBrowser.Controller/Providers/IForcedProvider.cs b/MediaBrowser.Controller/Providers/IForcedProvider.cs index 35fa29d94..5ae4a56ef 100644 --- a/MediaBrowser.Controller/Providers/IForcedProvider.cs +++ b/MediaBrowser.Controller/Providers/IForcedProvider.cs @@ -1,7 +1,7 @@ namespace MediaBrowser.Controller.Providers { /// <summary> - /// This is a marker interface that will cause a provider to run even if IsLocked=true + /// This is a marker interface that will cause a provider to run even if an item is locked from changes. /// </summary> public interface IForcedProvider { diff --git a/MediaBrowser.Controller/Providers/IImageEnhancer.cs b/MediaBrowser.Controller/Providers/IImageEnhancer.cs deleted file mode 100644 index c27c00ca2..000000000 --- a/MediaBrowser.Controller/Providers/IImageEnhancer.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.Drawing; -using MediaBrowser.Model.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public interface IImageEnhancer - { - /// <summary> - /// Return true only if the given image for the given item will be enhanced by this enhancer. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <returns><c>true</c> if this enhancer will enhance the supplied image for the supplied item, <c>false</c> otherwise</returns> - bool Supports(BaseItem item, ImageType imageType); - - /// <summary> - /// Gets the priority or order in which this enhancer should be run. - /// </summary> - /// <value>The priority.</value> - MetadataProviderPriority Priority { get; } - - /// <summary> - /// Return a key incorporating all configuration information related to this item - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <returns>Cache key relating to the current state of this item and configuration</returns> - string GetConfigurationCacheKey(BaseItem item, ImageType imageType); - - /// <summary> - /// Gets the size of the enhanced image. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <param name="imageIndex">Index of the image.</param> - /// <param name="originalImageSize">Size of the original image.</param> - /// <returns>ImageSize.</returns> - ImageDimensions GetEnhancedImageSize(BaseItem item, ImageType imageType, int imageIndex, ImageDimensions originalImageSize); - - EnhancedImageInfo GetEnhancedImageInfo(BaseItem item, string inputFile, ImageType imageType, int imageIndex); - - /// <summary> - /// Enhances the image async. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="inputFile">The input file.</param> - /// <param name="outputFile">The output file.</param> - /// <param name="imageType">Type of the image.</param> - /// <param name="imageIndex">Index of the image.</param> - /// <returns>Task{Image}.</returns> - /// <exception cref="System.ArgumentNullException"></exception> - Task EnhanceImageAsync(BaseItem item, string inputFile, string outputFile, ImageType imageType, int imageIndex); - } - - public class EnhancedImageInfo - { - public bool RequiresTransparency { get; set; } - } -} diff --git a/MediaBrowser.Controller/Providers/IImageProvider.cs b/MediaBrowser.Controller/Providers/IImageProvider.cs index 2df3d5ff8..29ab323f8 100644 --- a/MediaBrowser.Controller/Providers/IImageProvider.cs +++ b/MediaBrowser.Controller/Providers/IImageProvider.cs @@ -3,7 +3,7 @@ using MediaBrowser.Controller.Entities; namespace MediaBrowser.Controller.Providers { /// <summary> - /// Interface IImageProvider + /// Interface IImageProvider. /// </summary> public interface IImageProvider { @@ -14,10 +14,10 @@ namespace MediaBrowser.Controller.Providers string Name { get; } /// <summary> - /// Supportses the specified item. + /// Supports the specified item. /// </summary> /// <param name="item">The item.</param> - /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> + /// <returns><c>true</c> if the provider supports the item.</returns> bool Supports(BaseItem item); } } diff --git a/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs deleted file mode 100644 index 72bc56390..000000000 --- a/MediaBrowser.Controller/Providers/ILocalImageFileProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Controller.Entities; - -namespace MediaBrowser.Controller.Providers -{ - public interface ILocalImageFileProvider : ILocalImageProvider - { - List<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService); - } -} diff --git a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs index 09aaab3de..463c81376 100644 --- a/MediaBrowser.Controller/Providers/ILocalImageProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalImageProvider.cs @@ -1,9 +1,13 @@ +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; + namespace MediaBrowser.Controller.Providers { /// <summary> - /// This is just a marker interface + /// This is just a marker interface. /// </summary> public interface ILocalImageProvider : IImageProvider { + List<LocalImageInfo> GetImages(BaseItem item, IDirectoryService directoryService); } } diff --git a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs index 2a2c379f6..44fb1b394 100644 --- a/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/ILocalMetadataProvider.cs @@ -17,8 +17,9 @@ namespace MediaBrowser.Controller.Providers /// <param name="info">The information.</param> /// <param name="directoryService">The directory service.</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{MetadataResult{`0}}.</returns> - Task<MetadataResult<TItemType>> GetMetadata(ItemInfo info, + /// <returns>Task{MetadataResult{0}}.</returns> + Task<MetadataResult<TItemType>> GetMetadata( + ItemInfo info, IDirectoryService directoryService, CancellationToken cancellationToken); } diff --git a/MediaBrowser.Controller/Providers/IMetadataService.cs b/MediaBrowser.Controller/Providers/IMetadataService.cs index 49f6a7830..21204e6d3 100644 --- a/MediaBrowser.Controller/Providers/IMetadataService.cs +++ b/MediaBrowser.Controller/Providers/IMetadataService.cs @@ -12,8 +12,9 @@ namespace MediaBrowser.Controller.Providers /// Determines whether this instance can refresh the specified item. /// </summary> /// <param name="item">The item.</param> - /// <returns><c>true</c> if this instance can refresh the specified item; otherwise, <c>false</c>.</returns> + /// <returns><c>true</c> if this instance can refresh the specified item.</returns> bool CanRefresh(BaseItem item); + bool CanRefreshPrimary(Type type); /// <summary> diff --git a/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs index 058010e1a..28da27ae7 100644 --- a/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs +++ b/MediaBrowser.Controller/Providers/IPreRefreshProvider.cs @@ -2,6 +2,5 @@ namespace MediaBrowser.Controller.Providers { public interface IPreRefreshProvider : ICustomMetadataProvider { - } } diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 925ace895..254b27460 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -14,7 +14,7 @@ using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers { /// <summary> - /// Interface IProviderManager + /// Interface IProviderManager. /// </summary> public interface IProviderManager { @@ -159,13 +159,17 @@ namespace MediaBrowser.Controller.Providers Dictionary<Guid, Guid> GetRefreshQueue(); void OnRefreshStart(BaseItem item); + void OnRefreshProgress(BaseItem item, double progress); + void OnRefreshComplete(BaseItem item); double? GetRefreshProgress(Guid id); event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted; + event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted; + event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress; } diff --git a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs index e56bba3e3..68a968f90 100644 --- a/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs +++ b/MediaBrowser.Controller/Providers/IRemoteImageProvider.cs @@ -9,7 +9,7 @@ using MediaBrowser.Model.Providers; namespace MediaBrowser.Controller.Providers { /// <summary> - /// Interface IImageProvider + /// Interface IImageProvider. /// </summary> public interface IRemoteImageProvider : IImageProvider { diff --git a/MediaBrowser.Controller/Providers/ItemInfo.cs b/MediaBrowser.Controller/Providers/ItemInfo.cs index f29a8aa70..d61153dfa 100644 --- a/MediaBrowser.Controller/Providers/ItemInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemInfo.cs @@ -23,10 +23,15 @@ namespace MediaBrowser.Controller.Providers } public Type ItemType { get; set; } + public string Path { get; set; } + public string ContainingFolderPath { get; set; } + public VideoType VideoType { get; set; } + public bool IsInMixedFolder { get; set; } + public bool IsPlaceHolder { get; set; } } } diff --git a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs index 0aaab9a94..4707b0c7f 100644 --- a/MediaBrowser.Controller/Providers/ItemLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/ItemLookupInfo.cs @@ -11,29 +11,37 @@ namespace MediaBrowser.Controller.Providers /// </summary> /// <value>The name.</value> public string Name { get; set; } + /// <summary> /// Gets or sets the metadata language. /// </summary> /// <value>The metadata language.</value> public string MetadataLanguage { get; set; } + /// <summary> /// Gets or sets the metadata country code. /// </summary> /// <value>The metadata country code.</value> public string MetadataCountryCode { get; set; } + /// <summary> /// Gets or sets the provider ids. /// </summary> /// <value>The provider ids.</value> public Dictionary<string, string> ProviderIds { get; set; } + /// <summary> /// Gets or sets the year. /// </summary> /// <value>The year.</value> public int? Year { get; set; } + public int? IndexNumber { get; set; } + public int? ParentIndexNumber { get; set; } + public DateTime? PremiereDate { get; set; } + public bool IsAutomated { get; set; } public ItemLookupInfo() diff --git a/MediaBrowser.Controller/Providers/LocalImageInfo.cs b/MediaBrowser.Controller/Providers/LocalImageInfo.cs index 24cded79b..184281025 100644 --- a/MediaBrowser.Controller/Providers/LocalImageInfo.cs +++ b/MediaBrowser.Controller/Providers/LocalImageInfo.cs @@ -6,6 +6,7 @@ namespace MediaBrowser.Controller.Providers public class LocalImageInfo { public FileSystemMetadata FileInfo { get; set; } + public ImageType Type { get; set; } } } diff --git a/MediaBrowser.Controller/Providers/MetadataProviderPriority.cs b/MediaBrowser.Controller/Providers/MetadataProviderPriority.cs deleted file mode 100644 index 0076bb972..000000000 --- a/MediaBrowser.Controller/Providers/MetadataProviderPriority.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace MediaBrowser.Controller.Providers -{ - /// <summary> - /// Determines when a provider should execute, relative to others - /// </summary> - public enum MetadataProviderPriority - { - // Run this provider at the beginning - /// <summary> - /// The first - /// </summary> - First = 1, - - // Run this provider after all first priority providers - /// <summary> - /// The second - /// </summary> - Second = 2, - - // Run this provider after all second priority providers - /// <summary> - /// The third - /// </summary> - Third = 3, - - /// <summary> - /// The fourth - /// </summary> - Fourth = 4, - - Fifth = 5, - - // Run this provider last - /// <summary> - /// The last - /// </summary> - Last = 999 - } -} diff --git a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs index b3eb8cdd1..0a473b80c 100644 --- a/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs +++ b/MediaBrowser.Controller/Providers/MetadataRefreshOptions.cs @@ -13,11 +13,13 @@ namespace MediaBrowser.Controller.Providers public bool ReplaceAllMetadata { get; set; } public MetadataRefreshMode MetadataRefreshMode { get; set; } + public RemoteSearchResult SearchResult { get; set; } public string[] RefreshPaths { get; set; } public bool ForceSave { get; set; } + public bool EnableRemoteContentProbe { get; set; } public MetadataRefreshOptions(IDirectoryService directoryService) diff --git a/MediaBrowser.Controller/Providers/MetadataResult.cs b/MediaBrowser.Controller/Providers/MetadataResult.cs index ebff81b7f..59adaedfa 100644 --- a/MediaBrowser.Controller/Providers/MetadataResult.cs +++ b/MediaBrowser.Controller/Providers/MetadataResult.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Controller.Providers public class MetadataResult<T> { public List<LocalImageInfo> Images { get; set; } + public List<UserItemData> UserDataList { get; set; } public MetadataResult() @@ -19,10 +20,15 @@ namespace MediaBrowser.Controller.Providers public List<PersonInfo> People { get; set; } public bool HasMetadata { get; set; } + public T Item { get; set; } + public string ResultLanguage { get; set; } + public string Provider { get; set; } + public bool QueriedById { get; set; } + public void AddPerson(PersonInfo p) { if (People == null) diff --git a/MediaBrowser.Controller/Providers/MovieInfo.cs b/MediaBrowser.Controller/Providers/MovieInfo.cs index c9a766fe7..5b2c3ed03 100644 --- a/MediaBrowser.Controller/Providers/MovieInfo.cs +++ b/MediaBrowser.Controller/Providers/MovieInfo.cs @@ -2,6 +2,5 @@ namespace MediaBrowser.Controller.Providers { public class MovieInfo : ItemLookupInfo { - } } diff --git a/MediaBrowser.Controller/Providers/PersonLookupInfo.cs b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs index 3fa6e50b7..a6218c039 100644 --- a/MediaBrowser.Controller/Providers/PersonLookupInfo.cs +++ b/MediaBrowser.Controller/Providers/PersonLookupInfo.cs @@ -2,6 +2,5 @@ namespace MediaBrowser.Controller.Providers { public class PersonLookupInfo : ItemLookupInfo { - } } diff --git a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs index 078125673..a2ac6c9ae 100644 --- a/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs +++ b/MediaBrowser.Controller/Providers/RemoteSearchQuery.cs @@ -10,14 +10,14 @@ namespace MediaBrowser.Controller.Providers public Guid ItemId { get; set; } /// <summary> - /// If set will only search within the given provider + /// Will only search within the given provider when set. /// </summary> public string SearchProviderName { get; set; } /// <summary> - /// Gets or sets a value indicating whether [include disabled providers]. + /// Gets or sets a value indicating whether disabled providers should be included. /// </summary> - /// <value><c>true</c> if [include disabled providers]; otherwise, <c>false</c>.</value> + /// <value><c>true</c> if disabled providers should be included.</value> public bool IncludeDisabledProviders { get; set; } } } diff --git a/MediaBrowser.Controller/Session/SessionInfo.cs b/MediaBrowser.Controller/Session/SessionInfo.cs index acda6a416..f1f10a3a3 100644 --- a/MediaBrowser.Controller/Session/SessionInfo.cs +++ b/MediaBrowser.Controller/Session/SessionInfo.cs @@ -107,6 +107,8 @@ namespace MediaBrowser.Controller.Session public BaseItem FullNowPlayingItem { get; set; } + public BaseItemDto NowViewingItem { get; set; } + /// <summary> /// Gets or sets the device id. /// </summary> @@ -127,12 +129,6 @@ namespace MediaBrowser.Controller.Session public ISessionController[] SessionControllers { get; set; } /// <summary> - /// Gets or sets the application icon URL. - /// </summary> - /// <value>The application icon URL.</value> - public string AppIconUrl { get; set; } - - /// <summary> /// Gets or sets the supported commands. /// </summary> /// <value>The supported commands.</value> @@ -245,11 +241,6 @@ namespace MediaBrowser.Controller.Session SessionControllers = controllers.ToArray(); } - public bool ContainsUser(string userId) - { - return ContainsUser(new Guid(userId)); - } - public bool ContainsUser(Guid userId) { if (UserId.Equals(userId)) @@ -259,7 +250,7 @@ namespace MediaBrowser.Controller.Session foreach (var additionalUser in AdditionalUsers) { - if (userId.Equals(userId)) + if (additionalUser.UserId.Equals(userId)) { return true; } @@ -321,7 +312,7 @@ namespace MediaBrowser.Controller.Session var newPositionTicks = positionTicks + ProgressIncrement; var item = progressInfo.Item; - long? runtimeTicks = item == null ? null : item.RunTimeTicks; + long? runtimeTicks = item?.RunTimeTicks; // Don't report beyond the runtime if (runtimeTicks.HasValue && newPositionTicks >= runtimeTicks.Value) diff --git a/MediaBrowser.Controller/Sorting/AlphanumComparator.cs b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs new file mode 100644 index 000000000..de7f72d1c --- /dev/null +++ b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs @@ -0,0 +1,135 @@ +#nullable enable + +using System; +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Sorting +{ + public class AlphanumComparator : IComparer<string?> + { + public static int CompareValues(string? s1, string? s2) + { + if (s1 == null && s2 == null) + { + return 0; + } + else if (s1 == null) + { + return -1; + } + else if (s2 == null) + { + return 1; + } + + int len1 = s1.Length; + int len2 = s2.Length; + + // Early return for empty strings + if (len1 == 0 && len2 == 0) + { + return 0; + } + else if (len1 == 0) + { + return -1; + } + else if (len2 == 0) + { + return 1; + } + + int pos1 = 0; + int pos2 = 0; + + do + { + int start1 = pos1; + int start2 = pos2; + + bool isNum1 = char.IsDigit(s1[pos1++]); + bool isNum2 = char.IsDigit(s2[pos2++]); + + while (pos1 < len1 && char.IsDigit(s1[pos1]) == isNum1) + { + pos1++; + } + + while (pos2 < len2 && char.IsDigit(s2[pos2]) == isNum2) + { + pos2++; + } + + var span1 = s1.AsSpan(start1, pos1 - start1); + var span2 = s2.AsSpan(start2, pos2 - start2); + + if (isNum1 && isNum2) + { + // Trim leading zeros so we can compare the length + // of the strings to find the largest number + span1 = span1.TrimStart('0'); + span2 = span2.TrimStart('0'); + var span1Len = span1.Length; + var span2Len = span2.Length; + if (span1Len < span2Len) + { + return -1; + } + else if (span1Len > span2Len) + { + return 1; + } + else if (span1Len >= 20) // Number is probably too big for a ulong + { + // Trim all the first digits that are the same + int i = 0; + while (i < span1Len && span1[i] == span2[i]) + { + i++; + } + + // If there are no more digits it's the same number + if (i == span1Len) + { + continue; + } + + // Only need to compare the most significant digit + span1 = span1.Slice(i, 1); + span2 = span2.Slice(i, 1); + } + + if (!ulong.TryParse(span1, out var num1) + || !ulong.TryParse(span2, out var num2)) + { + return 0; + } + else if (num1 < num2) + { + return -1; + } + else if (num1 > num2) + { + return 1; + } + } + else + { + int result = span1.CompareTo(span2, StringComparison.InvariantCulture); + if (result != 0) + { + return result; + } + } + } while (pos1 < len1 && pos2 < len2); + + return len1 - len2; + } + + /// <inheritdoc /> + public int Compare(string x, string y) + { + return CompareValues(x, y); + } + } +} diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs index 111f4f17f..f5ee574a2 100644 --- a/MediaBrowser.Controller/Sorting/SortExtensions.cs +++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs @@ -7,137 +7,25 @@ namespace MediaBrowser.Controller.Sorting { public static class SortExtensions { + private static readonly AlphanumComparator _comparer = new AlphanumComparator(); public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName) { - return list.OrderBy(getName, new AlphanumComparator()); + return list.OrderBy(getName, _comparer); } public static IEnumerable<T> OrderByStringDescending<T>(this IEnumerable<T> list, Func<T, string> getName) { - return list.OrderByDescending(getName, new AlphanumComparator()); + return list.OrderByDescending(getName, _comparer); } public static IOrderedEnumerable<T> ThenByString<T>(this IOrderedEnumerable<T> list, Func<T, string> getName) { - return list.ThenBy(getName, new AlphanumComparator()); + return list.ThenBy(getName, _comparer); } public static IOrderedEnumerable<T> ThenByStringDescending<T>(this IOrderedEnumerable<T> list, Func<T, string> getName) { - return list.ThenByDescending(getName, new AlphanumComparator()); - } - - private class AlphanumComparator : IComparer<string> - { - private enum ChunkType { Alphanumeric, Numeric }; - - private static bool InChunk(char ch, char otherCh) - { - var type = ChunkType.Alphanumeric; - - if (char.IsDigit(otherCh)) - { - type = ChunkType.Numeric; - } - - if ((type == ChunkType.Alphanumeric && char.IsDigit(ch)) - || (type == ChunkType.Numeric && !char.IsDigit(ch))) - { - return false; - } - - return true; - } - - public static int CompareValues(string s1, string s2) - { - if (s1 == null || s2 == null) - { - return 0; - } - - int thisMarker = 0, thisNumericChunk = 0; - int thatMarker = 0, thatNumericChunk = 0; - - while ((thisMarker < s1.Length) || (thatMarker < s2.Length)) - { - if (thisMarker >= s1.Length) - { - return -1; - } - else if (thatMarker >= s2.Length) - { - return 1; - } - char thisCh = s1[thisMarker]; - char thatCh = s2[thatMarker]; - - var thisChunk = new StringBuilder(); - var thatChunk = new StringBuilder(); - - while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0]))) - { - thisChunk.Append(thisCh); - thisMarker++; - - if (thisMarker < s1.Length) - { - thisCh = s1[thisMarker]; - } - } - - while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0]))) - { - thatChunk.Append(thatCh); - thatMarker++; - - if (thatMarker < s2.Length) - { - thatCh = s2[thatMarker]; - } - } - - int result = 0; - // If both chunks contain numeric characters, sort them numerically - if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0])) - { - if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk)) - { - return 0; - } - if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk)) - { - return 0; - } - - if (thisNumericChunk < thatNumericChunk) - { - result = -1; - } - - if (thisNumericChunk > thatNumericChunk) - { - result = 1; - } - } - else - { - result = thisChunk.ToString().CompareTo(thatChunk.ToString()); - } - - if (result != 0) - { - return result; - } - } - - return 0; - } - - public int Compare(string x, string y) - { - return CompareValues(x, y); - } + return list.ThenByDescending(getName, _comparer); } } } diff --git a/MediaBrowser.Controller/Sorting/SortHelper.cs b/MediaBrowser.Controller/Sorting/SortHelper.cs deleted file mode 100644 index 05981d975..000000000 --- a/MediaBrowser.Controller/Sorting/SortHelper.cs +++ /dev/null @@ -1,25 +0,0 @@ -namespace MediaBrowser.Controller.Sorting -{ - public static class SortHelper - { - private enum ChunkType { Alphanumeric, Numeric }; - - public static bool InChunk(char ch, char otherCh) - { - var type = ChunkType.Alphanumeric; - - if (char.IsDigit(otherCh)) - { - type = ChunkType.Numeric; - } - - if ((type == ChunkType.Alphanumeric && char.IsDigit(ch)) - || (type == ChunkType.Numeric && !char.IsDigit(ch))) - { - return false; - } - - return true; - } - } -} |
