diff --git a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs index bff8fdac5c..4eb75b82ff 100644 --- a/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs +++ b/MediaBrowser.Providers/Playlists/PlaylistItemsProvider.cs @@ -8,11 +8,13 @@ using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; using PlaylistsNET.Content; @@ -24,11 +26,16 @@ namespace MediaBrowser.Providers.Playlists IPreRefreshProvider, IHasItemChangeMonitor { + private readonly IFileSystem _fileSystem; + private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; + private readonly CollectionType[] _ignoredCollections = [CollectionType.livetv, CollectionType.boxsets, CollectionType.playlists]; - public PlaylistItemsProvider(ILogger logger) + public PlaylistItemsProvider(ILogger logger, ILibraryManager libraryManager, IFileSystem fileSystem) { _logger = logger; + _libraryManager = libraryManager; + _fileSystem = fileSystem; } public string Name => "Playlist Reader"; @@ -59,109 +66,117 @@ namespace MediaBrowser.Providers.Playlists 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)) { if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) { - return GetWplItems(stream, path); + return GetWplItems(stream, path, libraryRoots); } if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { - return GetZplItems(stream, path); + return GetZplItems(stream, path, libraryRoots); } if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) { - return GetM3uItems(stream, path); + return GetM3uItems(stream, path, libraryRoots); } if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) { - return GetM3u8Items(stream, path); + return GetM3uItems(stream, path, libraryRoots); } if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) { - return GetPlsItems(stream, path); + return GetPlsItems(stream, path, libraryRoots); } } return Enumerable.Empty(); } - private IEnumerable GetPlsItems(Stream stream, string path) + private IEnumerable GetPlsItems(Stream stream, string playlistPath, List libraryRoots) { var content = new PlsContent(); var playlist = content.GetFromStream(stream); - return playlist.PlaylistEntries.Select(i => new LinkedChild - { - Path = GetPlaylistItemPath(i.Path, path), - Type = LinkedChildType.Manual - }); + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); } - private IEnumerable GetM3u8Items(Stream stream, string path) + private IEnumerable GetM3uItems(Stream stream, string playlistPath, List libraryRoots) { var content = new M3uContent(); var playlist = content.GetFromStream(stream); - return playlist.PlaylistEntries.Select(i => new LinkedChild - { - Path = GetPlaylistItemPath(i.Path, path), - Type = LinkedChildType.Manual - }); + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); } - private IEnumerable GetM3uItems(Stream stream, string path) + private IEnumerable GetZplItems(Stream stream, string playlistPath, List libraryRoots) { - var content = new M3uContent(); + var content = new ZplContent(); var playlist = content.GetFromStream(stream); - return playlist.PlaylistEntries.Select(i => new LinkedChild - { - Path = GetPlaylistItemPath(i.Path, path), - Type = LinkedChildType.Manual - }); + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); } - private IEnumerable GetZplItems(Stream stream, string path) + private IEnumerable GetWplItems(Stream stream, string playlistPath, List libraryRoots) { - var content = new ZplContent(); + var content = new WplContent(); var playlist = content.GetFromStream(stream); - return playlist.PlaylistEntries.Select(i => new LinkedChild - { - Path = GetPlaylistItemPath(i.Path, path), - Type = LinkedChildType.Manual - }); + return playlist.PlaylistEntries + .Select(i => GetLinkedChild(i.Path, playlistPath, libraryRoots)) + .Where(i => i is not null); } - private IEnumerable GetWplItems(Stream stream, string path) + private LinkedChild GetLinkedChild(string itemPath, string playlistPath, List libraryRoots) { - var content = new WplContent(); - var playlist = content.GetFromStream(stream); - - return playlist.PlaylistEntries.Select(i => new LinkedChild + if (TryGetPlaylistItemPath(itemPath, playlistPath, libraryRoots, out var parsedPath)) { - Path = GetPlaylistItemPath(i.Path, path), - Type = LinkedChildType.Manual - }); + return new LinkedChild + { + Path = parsedPath, + Type = LinkedChildType.Manual + }; + } + + return null; } - private string GetPlaylistItemPath(string itemPath, string containingPlaylistFolder) + private bool TryGetPlaylistItemPath(string itemPath, string playlistPath, List libraryPaths, out string path) { - if (!File.Exists(itemPath)) + path = null; + string pathToCheck = _fileSystem.MakeAbsolutePath(Path.GetDirectoryName(playlistPath), itemPath); + if (!File.Exists(pathToCheck)) { - var path = Path.Combine(Path.GetDirectoryName(containingPlaylistFolder), itemPath); - if (File.Exists(path)) + return false; + } + + foreach (var libraryPath in libraryPaths) + { + if (pathToCheck.StartsWith(libraryPath, StringComparison.OrdinalIgnoreCase)) { - return path; + path = pathToCheck; + return true; } } - return itemPath; + return false; } public bool HasChanged(BaseItem item, IDirectoryService directoryService)