diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index 4eb75b82ff..51a3ba0c7f 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -1,7 +1,5 @@ #nullable disable -#pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.IO; @@ -18,182 +16,212 @@ using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; using PlaylistsNET.Content; -namespace MediaBrowser.Providers.Playlists +namespace MediaBrowser.Providers.Playlists; + +/// +/// Local playlist provider. +/// +public class PlaylistItemsProvider : ILocalMetadataProvider, + IHasOrder, + IForcedProvider, + IHasItemChangeMonitor { - public class PlaylistItemsProvider : ICustomMetadataProvider, - IHasOrder, - IForcedProvider, - IPreRefreshProvider, - IHasItemChangeMonitor + private readonly IFileSystem _fileSystem; + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly CollectionType[] _ignoredCollections = [CollectionType.livetv, CollectionType.boxsets, CollectionType.playlists]; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + /// Instance of the interface. + public PlaylistItemsProvider(ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem) { - private readonly IFileSystem _fileSystem; - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - private readonly CollectionType[] _ignoredCollections = [CollectionType.livetv, CollectionType.boxsets, CollectionType.playlists]; + _logger = logger; + _libraryManager = libraryManager; + _fileSystem = fileSystem; + } - public PlaylistItemsProvider(ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem) + /// + public string Name => "Playlist Item Provider"; + + /// + public int Order => 100; + + /// + public Task> GetMetadata( + ItemInfo info, + IDirectoryService directoryService, + CancellationToken cancellationToken) + { + var result = new MetadataResult() { - _logger = logger; - _libraryManager = libraryManager; - _fileSystem = fileSystem; + Item = new Playlist + { + Path = info.Path + } + }; + Fetch(result); + + return Task.FromResult(result); + } + + private void Fetch(MetadataResult result) + { + var item = result.Item; + var path = item.Path; + if (!Playlist.IsPlaylistFile(path)) + { + return; } - public string Name => "Playlist Reader"; - - // Run last - public int Order => 100; - - public Task FetchAsync(Playlist item, MetadataRefreshOptions options, CancellationToken cancellationToken) + var extension = Path.GetExtension(path); + if (!Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparison.OrdinalIgnoreCase)) { - var path = item.Path; - if (!Playlist.IsPlaylistFile(path)) - { - return Task.FromResult(ItemUpdateType.None); - } - - var extension = Path.GetExtension(path); - if (!Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparison.OrdinalIgnoreCase)) - { - return Task.FromResult(ItemUpdateType.None); - } - - var items = GetItems(path, extension).ToArray(); + return; + } + var items = GetItems(path, extension).ToArray(); + if (items.Length > 0) + { + result.HasMetadata = true; item.LinkedChildren = items; - - return Task.FromResult(ItemUpdateType.MetadataImport); } - private IEnumerable GetItems(string path, string extension) + return; + } + + private IEnumerable GetItems(string path, string extension) + { + var libraryRoots = _libraryManager.GetUserRootFolder().Children + .OfType() + .Where(f => f.CollectionType.HasValue && !_ignoredCollections.Contains(f.CollectionType.Value)) + .SelectMany(f => f.PhysicalLocations) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + using (var stream = File.OpenRead(path)) { - var libraryRoots = _libraryManager.GetUserRootFolder().Children - .OfType() - .Where(f => f.CollectionType.HasValue && !_ignoredCollections.Contains(f.CollectionType.Value)) - .SelectMany(f => f.PhysicalLocations) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - using (var stream = File.OpenRead(path)) + if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) { - if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetWplItems(stream, path, libraryRoots); - } - - if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetZplItems(stream, path, libraryRoots); - } - - if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetM3uItems(stream, path, libraryRoots); - } - - if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetM3uItems(stream, path, libraryRoots); - } - - if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) - { - return GetPlsItems(stream, path, libraryRoots); - } + return GetWplItems(stream, path, libraryRoots); } - return Enumerable.Empty(); - } - - private IEnumerable GetPlsItems(Stream stream, string playlistPath, List libraryRoots) - { - var content = new PlsContent(); - var playlist = content.GetFromStream(stream); - - return playlist.PlaylistEntries - .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) - .Where(i => i is not null); - } - - private IEnumerable GetM3uItems(Stream stream, string playlistPath, List libraryRoots) - { - var content = new M3uContent(); - var playlist = content.GetFromStream(stream); - - return playlist.PlaylistEntries - .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) - .Where(i => i is not null); - } - - private IEnumerable GetZplItems(Stream stream, string playlistPath, List libraryRoots) - { - var content = new ZplContent(); - var playlist = content.GetFromStream(stream); - - return playlist.PlaylistEntries - .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) - .Where(i => i is not null); - } - - private IEnumerable GetWplItems(Stream stream, string playlistPath, List libraryRoots) - { - var content = new WplContent(); - var playlist = content.GetFromStream(stream); - - return playlist.PlaylistEntries - .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) - .Where(i => i is not null); - } - - private LinkedChild GetLinkedChild(string itemPath, string playlistPath, List libraryRoots) - { - if (TryGetPlaylistItemPath(itemPath, playlistPath, libraryRoots, out var parsedPath)) + if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { - return new LinkedChild - { - Path = parsedPath, - Type = LinkedChildType.Manual - }; + return GetZplItems(stream, path, libraryRoots); } - return null; + if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetM3uItems(stream, path, libraryRoots); + } + + if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetM3uItems(stream, path, libraryRoots); + } + + if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) + { + return GetPlsItems(stream, path, libraryRoots); + } } - private bool TryGetPlaylistItemPath(string itemPath, string playlistPath, List libraryPaths, out string path) + return Enumerable.Empty(); + } + + private IEnumerable GetPlsItems(Stream stream, string playlistPath, List libraryRoots) + { + var content = new PlsContent(); + var playlist = content.GetFromStream(stream); + + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); + } + + private IEnumerable GetM3uItems(Stream stream, string playlistPath, List libraryRoots) + { + var content = new M3uContent(); + var playlist = content.GetFromStream(stream); + + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); + } + + private IEnumerable GetZplItems(Stream stream, string playlistPath, List libraryRoots) + { + var content = new ZplContent(); + var playlist = content.GetFromStream(stream); + + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); + } + + private IEnumerable GetWplItems(Stream stream, string playlistPath, List libraryRoots) + { + var content = new WplContent(); + var playlist = content.GetFromStream(stream); + + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); + } + + private LinkedChild GetLinkedChild(string itemPath, string playlistPath, List libraryRoots) + { + if (TryGetPlaylistItemPath(itemPath, playlistPath, libraryRoots, out var parsedPath)) { - path = null; - string pathToCheck = _fileSystem.MakeAbsolutePath(Path.GetDirectoryName(playlistPath), itemPath); - if (!File.Exists(pathToCheck)) + return new LinkedChild { - return false; - } + Path = parsedPath, + Type = LinkedChildType.Manual + }; + } - foreach (var libraryPath in libraryPaths) - { - if (pathToCheck.StartsWith(libraryPath, StringComparison.OrdinalIgnoreCase)) - { - path = pathToCheck; - return true; - } - } + return null; + } + private bool TryGetPlaylistItemPath(string itemPath, string playlistPath, List libraryPaths, out string path) + { + path = null; + string pathToCheck = _fileSystem.MakeAbsolutePath(Path.GetDirectoryName(playlistPath), itemPath); + if (!File.Exists(pathToCheck)) + { return false; } - public bool HasChanged(BaseItem item, IDirectoryService directoryService) + foreach (var libraryPath in libraryPaths) { - var path = item.Path; - - if (!string.IsNullOrWhiteSpace(path) && item.IsFileProtocol) + if (pathToCheck.StartsWith(libraryPath, StringComparison.OrdinalIgnoreCase)) { - var file = directoryService.GetFile(path); - if (file is not null && file.LastWriteTimeUtc != item.DateModified) - { - _logger.LogDebug("Refreshing {Path} due to date modified timestamp change.", path); - return true; - } + path = pathToCheck; + return true; } - - return false; } + + return false; + } + + /// + public bool HasChanged(BaseItem item, IDirectoryService directoryService) + { + var path = item.Path; + if (!string.IsNullOrWhiteSpace(path) && item.IsFileProtocol) + { + var file = directoryService.GetFile(path); + if (file is not null && file.LastWriteTimeUtc != item.DateModified) + { + _logger.LogDebug("Refreshing {Path} due to date modified timestamp change.", path); + return true; + } + } + + return false; } }