diff --git a/Directory.Build.props b/Directory.Build.props index 641cdf1..c4d6a62 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ - 1.4.4.0 - 1.4.4.0 - 1.4.4.0 + 1.4.5.0 + 1.4.5.0 + 1.4.5.0 diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs index fa00c01..3165727 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeImageProvider.cs @@ -47,7 +47,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public string Name => "TubeArchivist"; /// - public bool Supports(BaseItem item) => item is Episode; + public bool Supports(BaseItem item) => item is Episode && Utils.IsTubeArchivistItem(item); /// public IEnumerable GetSupportedImages(BaseItem item) @@ -65,7 +65,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers _logger.LogDebug("{Message}", string.Format(CultureInfo.CurrentCulture, "Getting images for video: {0} ({1})", video?.Title, videoTAId)); _logger.LogDebug("{Message}", "Thumb URI: " + video?.VidThumbUrl); - if (video != null) + if (video != null && Utils.HasImageUrl(video.VidThumbUrl)) { list.Add(new RemoteImageInfo { @@ -87,6 +87,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers } else { + if (!Utils.HasImageUrl(url)) + { + throw new HttpRequestException("TubeArchivist returned an empty image URL."); + } + return await Plugin.Instance.HttpClient.GetAsync(new Uri(Utils.SanitizeUrl(Plugin.Instance.Configuration.TubeArchivistUrl + url).TrimEnd('/')), cancellationToken).ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs index d62e530..fa21e87 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/EpisodeMetadataProvider.cs @@ -50,6 +50,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public async Task> GetMetadata(EpisodeInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); + if (string.IsNullOrWhiteSpace(info.Path)) + { + return result; + } + var taApi = TubeArchivistApi.GetInstance(); var videoTAId = Utils.GetVideoNameFromPath(info.Path); var video = await taApi.GetVideo(videoTAId).ConfigureAwait(true); @@ -79,6 +84,10 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public async Task> GetSearchResults(EpisodeInfo searchInfo, CancellationToken cancellationToken) { var results = new List(); + if (string.IsNullOrWhiteSpace(searchInfo.Path)) + { + return results; + } var taApi = TubeArchivistApi.GetInstance(); var videoTAId = Utils.GetVideoNameFromPath(searchInfo.Path); diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesImageProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesImageProvider.cs index 6fef96a..641ddb6 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesImageProvider.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesImageProvider.cs @@ -45,12 +45,12 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public string Name => "TubeArchivist"; /// - public bool Supports(BaseItem item) => item is Series; + public bool Supports(BaseItem item) => item is Series && Utils.IsTubeArchivistItem(item); /// public IEnumerable GetSupportedImages(BaseItem item) { - return new[] { ImageType.Primary }; + return new[] { ImageType.Primary, ImageType.Art, ImageType.Banner, ImageType.Backdrop }; } /// @@ -62,10 +62,8 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers var channel = await taApi.GetChannel(channelTAId).ConfigureAwait(true); _logger.LogDebug("{Message}", string.Format(CultureInfo.CurrentCulture, "Getting images for channel: {0} ({1})", channel?.Name, channelTAId)); _logger.LogDebug("{Message}", "Thumb URI: " + channel?.ThumbUrl); - _logger.LogDebug("{Message}", "TVArt URI: " + channel?.TvartUrl); - _logger.LogDebug("{Message}", "Banner URI: " + channel?.BannerUrl); - if (channel != null) + if (channel != null && Utils.HasImageUrl(channel.ThumbUrl)) { list.Add(new RemoteImageInfo { @@ -73,18 +71,17 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers Type = ImageType.Primary, Url = channel.ThumbUrl }); + } + + if (channel != null && Utils.HasImageUrl(channel.TvartUrl)) + { list.Add(new RemoteImageInfo { ProviderName = Name, Type = ImageType.Art, Url = channel.TvartUrl }); - list.Add(new RemoteImageInfo - { - ProviderName = Name, - Type = ImageType.Banner, - Url = channel.BannerUrl - }); + list.Add(new RemoteImageInfo { ProviderName = Name, @@ -93,6 +90,16 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers }); } + if (channel != null && Utils.HasImageUrl(channel.BannerUrl)) + { + list.Add(new RemoteImageInfo + { + ProviderName = Name, + Type = ImageType.Banner, + Url = channel.BannerUrl + }); + } + return list; } @@ -105,6 +112,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers } else { + if (!Utils.HasImageUrl(url)) + { + throw new HttpRequestException("TubeArchivist returned an empty image URL."); + } + return await Plugin.Instance.HttpClient.GetAsync(new Uri(Utils.SanitizeUrl(Plugin.Instance.Configuration.TubeArchivistUrl + url).TrimEnd('/')), cancellationToken).ConfigureAwait(false); } } diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesMetadataProvider.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesMetadataProvider.cs index d44a847..9d94cd5 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesMetadataProvider.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Providers/SeriesMetadataProvider.cs @@ -49,6 +49,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public async Task> GetMetadata(SeriesInfo info, CancellationToken cancellationToken) { var result = new MetadataResult(); + if (string.IsNullOrWhiteSpace(info.Path)) + { + return result; + } + var taApi = TubeArchivistApi.GetInstance(); var channelTAId = Utils.GetChannelNameFromPath(info.Path); var channel = await taApi.GetChannel(channelTAId).ConfigureAwait(true); @@ -77,6 +82,10 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers public async Task> GetSearchResults(SeriesInfo searchInfo, CancellationToken cancellationToken) { var results = new List(); + if (string.IsNullOrWhiteSpace(searchInfo.Path)) + { + return results; + } var taApi = TubeArchivistApi.GetInstance(); var channelTAId = Utils.GetChannelNameFromPath(searchInfo.Path); diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/JFToTubeArchivistPlaylistsSyncTask.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/JFToTubeArchivistPlaylistsSyncTask.cs index 16b05a0..2cdd384 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/JFToTubeArchivistPlaylistsSyncTask.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/JFToTubeArchivistPlaylistsSyncTask.cs @@ -379,7 +379,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks new TaskTriggerInfo { Type = TaskTriggerInfoType.IntervalTrigger, - IntervalTicks = TimeSpan.FromSeconds(Plugin.Instance!.Configuration.TAJFProgressTaskInterval).Ticks + IntervalTicks = TimeSpan.FromSeconds(Plugin.Instance!.Configuration.JFTAPlaylistsSyncTaskInterval).Ticks }, ]; } diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/TAToJellyfinPlaylistsSyncTask.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/TAToJellyfinPlaylistsSyncTask.cs index 19c66ae..6cf2bdb 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/TAToJellyfinPlaylistsSyncTask.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Tasks/TAToJellyfinPlaylistsSyncTask.cs @@ -201,7 +201,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks new TaskTriggerInfo { Type = TaskTriggerInfoType.IntervalTrigger, - IntervalTicks = TimeSpan.FromSeconds(Plugin.Instance!.Configuration.TAJFProgressTaskInterval).Ticks + IntervalTicks = TimeSpan.FromSeconds(Plugin.Instance!.Configuration.TAJFPlaylistsSyncTaskInterval).Ticks }, ]; } diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel/Channel.cs b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel/Channel.cs index 75696c7..6cd2028 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel/Channel.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Channel/Channel.cs @@ -96,7 +96,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist { Name = Name, SearchProviderName = Constants.ProviderName, - ImageUrl = ThumbUrl, + ImageUrl = Utils.HasImageUrl(ThumbUrl) ? ThumbUrl : null, ProviderIds = new Dictionary() { { Constants.ProviderName, Id } } }; } @@ -118,14 +118,16 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist Constants.ProviderName, Id } }, - ImageInfos = new[] - { + ImageInfos = Utils.HasImageUrl(ThumbUrl) ? + [ new ItemImageInfo { Path = ThumbUrl, Type = ImageType.Primary } - }, + + ] : + [], Tags = this.Tags != null ? this.Tags.ToArray() : [] diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Video/Video.cs b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Video/Video.cs index 22b3f44..9410295 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Video/Video.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/TubeArchivist/Video/Video.cs @@ -109,7 +109,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist Name = Title, SearchProviderName = Constants.ProviderName, ProductionYear = Published.Year, - ImageUrl = VidThumbUrl, + ImageUrl = Utils.HasImageUrl(VidThumbUrl) ? VidThumbUrl : null, PremiereDate = Published, ProviderIds = new Dictionary() { { Constants.ProviderName, YoutubeId } } }; @@ -142,14 +142,16 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist Constants.ProviderName, YoutubeId } }, - ImageInfos = new[] - { + ImageInfos = Utils.HasImageUrl(VidThumbUrl) ? + [ new ItemImageInfo { Path = VidThumbUrl, Type = ImageType.Primary } - }, + + ] : + [], Tags = this.Tags.ToArray() }; } diff --git a/Jellyfin.Plugin.TubeArchivistMetadata/Utils/Utils.cs b/Jellyfin.Plugin.TubeArchivistMetadata/Utils/Utils.cs index f526db0..d329c15 100644 --- a/Jellyfin.Plugin.TubeArchivistMetadata/Utils/Utils.cs +++ b/Jellyfin.Plugin.TubeArchivistMetadata/Utils/Utils.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Text.RegularExpressions; +using MediaBrowser.Controller.Entities; namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities { @@ -125,6 +126,32 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities return path.Split(DetectDirectorySeparator(path)).Last(); } + /// + /// Checks whether the Jellyfin item belongs to the configured TubeArchivist collection. + /// + /// Jellyfin item. + /// True when the item belongs to the configured TubeArchivist collection. + public static bool IsTubeArchivistItem(BaseItem item) + { + if (Plugin.Instance == null) + { + return false; + } + + var topParent = item.GetTopParent(); + return string.Equals(topParent?.Name, Plugin.Instance.Configuration.CollectionTitle, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Checks whether a TubeArchivist image URL can be fetched safely. + /// + /// Image URL returned by TubeArchivist. + /// True when the image URL is non-empty. + public static bool HasImageUrl(string? url) + { + return !string.IsNullOrWhiteSpace(url); + } + private static char DetectDirectorySeparator(string path) { int backslashCount = path.Count(c => c == '\\'); diff --git a/build.yaml b/build.yaml index 42c71fc..61f8b54 100644 --- a/build.yaml +++ b/build.yaml @@ -2,7 +2,7 @@ name: "TubeArchivistMetadata" guid: "dc97d0c6-28b0-4242-afb4-5833ae1b3715" imageUrl: https://raw.githubusercontent.com/tubearchivist/tubearchivist-jf-plugin/master/images/logo.png -version: "1.4.4.0" +version: "1.4.5.0" targetAbi: "10.11.0.0" framework: "net9.0" overview: "Metadata for your TubeArchivist library on Jellyfin" @@ -14,4 +14,4 @@ owner: "DarkFighterLuke" artifacts: - "Jellyfin.Plugin.TubeArchivistMetadata.dll" changelog: > - Handle TubeArchivist playlists pagination + Limit providers to TubeArchivist paths, skip empty image URLs, and fix playlist sync intervals