#nullable disable #pragma warning disable CS1591 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using Jellyfin.Extensions; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; using Microsoft.Extensions.Logging; using PlaylistsNET.Content; namespace MediaBrowser.Providers.Playlists { public class PlaylistItemsProvider : ICustomMetadataProvider, IHasOrder, IForcedProvider, IPreRefreshProvider, IHasItemChangeMonitor { private readonly ILogger _logger; public PlaylistItemsProvider(ILogger logger) { _logger = logger; } public string Name => "Playlist Reader"; // Run last public int Order => 100; public Task FetchAsync(Playlist item, MetadataRefreshOptions options, CancellationToken cancellationToken) { 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); } using (var stream = File.OpenRead(path)) { var items = GetItems(stream, extension).ToArray(); item.LinkedChildren = items; } return Task.FromResult(ItemUpdateType.None); } private IEnumerable GetItems(Stream stream, string extension) { if (string.Equals(".wpl", extension, StringComparison.OrdinalIgnoreCase)) { return GetWplItems(stream); } if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { return GetZplItems(stream); } if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) { return GetM3uItems(stream); } if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) { return GetM3u8Items(stream); } if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) { return GetPlsItems(stream); } return new List(); } private IEnumerable GetPlsItems(Stream stream) { var content = new PlsContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { Path = i.Path, Type = LinkedChildType.Manual }); } private IEnumerable GetM3u8Items(Stream stream) { var content = new M3uContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { Path = i.Path, Type = LinkedChildType.Manual }); } private IEnumerable GetM3uItems(Stream stream) { var content = new M3uContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { Path = i.Path, Type = LinkedChildType.Manual }); } private IEnumerable GetZplItems(Stream stream) { var content = new ZplContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { Path = i.Path, Type = LinkedChildType.Manual }); } private IEnumerable GetWplItems(Stream stream) { var content = new WplContent(); var playlist = content.GetFromStream(stream); return playlist.PlaylistEntries.Select(i => new LinkedChild { Path = i.Path, Type = LinkedChildType.Manual }); } public bool HasChanged(BaseItem item, IDirectoryService directoryService) { var path = item.Path; if (!string.IsNullOrWhiteSpace(path) && item.IsFileProtocol) { var file = directoryService.GetFile(path); if (file != null && file.LastWriteTimeUtc != item.DateModified) { _logger.LogDebug("Refreshing {0} due to date modified timestamp change.", path); return true; } } return false; } } }