ankenyr / jellyfin-youtube-metadata-plugin

Youtube Metadata Plugin for Jellyfin
GNU Affero General Public License v3.0
481 stars 31 forks source link

Fix mv thumbnail "returned NotFound, ignoring" #63

Open choyuansu opened 2 years ago

choyuansu commented 2 years ago

Couldn't get correct thumbnails for videos in Library of "Music Videos" type. Found out YoutubeMetadata is not available as an option for image fetcher. After adding support for Music Videos, got blank thumbnails. Using "thumbnail" instead of "thumbnails[^1]" from ytvideo.info.json gives better results. Please let me know if anything was wrong. First time using .NET and C#.

ankenyr commented 1 year ago

Adding support for MusicVideos on line 110 seems fine but I don't understand why the other lines need to be changed. All other libraries work and should be broken if this was an issue.

ankenyr commented 1 year ago

pinging this again, let me know what the other changes are for.

choyuansu commented 1 year ago

I'm experiencing an issue where thumbnails are not downloaded for some videos in Music Video folders. It seems that the last item in the thumbnails list in info.json does not always have a valid image (e.g. yt-dlp --write-info-json --skip-download "https://www.youtube.com/watch?v=OB7HVOCo6oQ"), which causes an error shown in the logs below. So I changed to use the value of "thumbnail" in the info.json instead of "thumbnails", which seems to guarantee a valid image.

Though I'm not sure if this is something only I am experiencing. Feel free to let me know if you weren't able to reproduce this issue.

[2022-08-11 17:39:56.724 -04:00] [DBG] [30] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: "ITZY “SNEAKERS” M/V @ITZY"
[2022-08-11 17:39:56.724 -04:00] [DBG] [3] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: "ITZY #Twenty Video | The 1st Fan Meeting"
[2022-08-11 17:39:56.853 -04:00] [DBG] [3] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: Creating RemoteImageInfo for "OB7HVOCo6oQ"
[2022-08-11 17:39:56.876 -04:00] [DBG] [3] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: GetImageResponse 
[2022-08-11 17:39:56.887 -04:00] [DBG] [30] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: Creating RemoteImageInfo for "Hbb5GPxXF1w"
[2022-08-11 17:39:56.887 -04:00] [DBG] [30] Jellyfin.Plugin.YoutubeMetadata.Providers.YoutubeDL.YTDLImageProvider: YTDLImage GetImages: GetImageResponse 
[2022-08-11 17:39:56.976 -04:00] [DBG] [30] MediaBrowser.Providers.Music.MusicVideoMetadataService: "https://i.ytimg.com/vi_webp/OB7HVOCo6oQ/maxresdefault.webp" returned NotFound, ignoring
[2022-08-11 17:39:57.041 -04:00] [DBG] [34] MediaBrowser.Providers.Manager.ProviderManager: Saving image to "/config/metadata/library/d2/d244f4c9626f395618a9e690022fdeb6/poster.webp"
[2022-08-11 17:39:57.523 -04:00] [DBG] [10] Emby.Drawing.ImageProcessor: Getting image size for item "MusicVideo" "/config/metadata/library/d2/d244f4c9626f395618a9e690022fdeb6/poster.webp"
[2022-08-11 17:39:57.794 -04:00] [DBG] [3] Emby.Server.Implementations.HttpServer.WebSocketConnection: WS "192.168.0.151" received message: WebSocketMessage`1 { MessageType: ScheduledTasksInfoStop, MessageId: 00000000-0000-0000-0000-000000000000, ServerId: null, Data: null }
[2022-08-11 17:39:57.794 -04:00] [DBG] [3] Jellyfin.Api.WebSocketListeners.ScheduledTasksWebSocketListener: WS "192.168.0.151" stop transmitting to "ScheduledTasksWebSocketListener"
[2022-08-11 17:39:57.866 -04:00] [DBG] [31] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: "CustomAuthentication" was successfully authenticated.
[2022-08-11 17:39:57.867 -04:00] [DBG] [31] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: "CustomAuthentication" was successfully authenticated.
[2022-08-11 17:39:57.974 -04:00] [DBG] [31] Emby.Server.Implementations.Data.SqliteItemRepository: "GetItemList" query time (slow): 107.1213ms. Query: "select type,data,StartDate,EndDate,ChannelId,IsMovie,IsSeries,EpisodeTitle,IsRepeat,CommunityRating,CustomRating,IndexNumber,IsLocked,PreferredMetadataLanguage,PreferredMetadataCountryCode,Width,Height,DateLastRefreshed,Name,Path,PremiereDate,Overview,ParentIndexNumber,ProductionYear,OfficialRating,ForcedSortName,RunTimeTicks,Size,DateCreated,DateModified,guid,Genres,ParentId,Audio,ExternalServiceId,IsInMixedFolder,DateLastSaved,LockedFields,Studios,Tags,TrailerTypes,OriginalTitle,PrimaryVersionId,DateLastMediaAdded,Album,CriticRating,IsVirtualItem,SeriesName,SeasonName,SeasonId,SeriesId,PresentationUniqueKey,InheritedParentalRatingValue,ExternalSeriesId,Tagline,ProviderIds,Images,ProductionLocations,ExtraIds,TotalBitrate,ExtraType,Artists,AlbumArtists,ExternalId,SeriesPresentationUniqueKey,ShowId,OwnerId from TypedBaseItems A where ParentId=@ParentId"
[2022-08-11 17:39:58.030 -04:00] [DBG] [33] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: "CustomAuthentication" was successfully authenticated.
[2022-08-11 17:39:58.031 -04:00] [DBG] [33] Jellyfin.Api.Auth.CustomAuthenticationHandler: AuthenticationScheme: "CustomAuthentication" was successfully authenticated.
[2022-08-11 17:39:58.034 -04:00] [DBG] [10] MediaBrowser.Providers.Manager.ProviderManager: OnRefreshComplete "cbbc5a5a9f6120e102ef77f998e2ee73"
[2022-08-11 17:39:58.044 -04:00] [ERR] [10] MediaBrowser.Providers.Manager.ProviderManager: Error refreshing item
Constraint: SQLitePCL.pretty.SQLiteException: NOT NULL constraint failed: ItemValues.Type
   at SQLitePCL.pretty.SQLiteException.Throw(Int32 rc, Int32 extended, String msg)
   at SQLitePCL.pretty.SQLiteException.CheckOk(sqlite3 db, Int32 rc)
   at SQLitePCL.pretty.StatementImpl.MoveNext()
   at Emby.Server.Implementations.Data.SqliteItemRepository.InsertItemValues(Byte[] idBlob, List`1 values, IDatabaseConnection db)
   at Emby.Server.Implementations.Data.SqliteItemRepository.UpdateItemValues(Guid itemId, List`1 values, IDatabaseConnection db)
   at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItemsInTransaction(IDatabaseConnection db, IEnumerable`1 tuples)
   at Emby.Server.Implementations.Data.SqliteItemRepository.<>c__DisplayClass34_0.b__0(IDatabaseConnection db)
   at SQLitePCL.pretty.DatabaseConnection.<>c__DisplayClass20_0.b__0(IDatabaseConnection db)
   at SQLitePCL.pretty.DatabaseConnection.RunInTransaction[T](IDatabaseConnection This, Func`2 f, TransactionMode mode)
   at SQLitePCL.pretty.DatabaseConnection.RunInTransaction(IDatabaseConnection This, Action`1 action, TransactionMode mode)
   at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(IEnumerable`1 items, CancellationToken cancellationToken)
   at Emby.Server.Implementations.Library.LibraryManager.UpdateItemsAsync(IReadOnlyList`1 items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Video.UpdateToRepositoryAsync(ItemUpdateType updateReason, CancellationToken cancellationToken)
   at MediaBrowser.Providers.Manager.MetadataService`2.SaveItemAsync(MetadataResult`1 result, ItemUpdateType reason, CancellationToken cancellationToken)
   at MediaBrowser.Providers.Manager.MetadataService`2.RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.BaseItem.RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Folder.<>c__DisplayClass68_0.<b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at MediaBrowser.Providers.Manager.ProviderManager.RunMetadataRefresh(Func`1 action, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Folder.RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, Boolean recursive, IProgress`1 progress, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Folder.<>c__DisplayClass70_0`1.<b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at MediaBrowser.Controller.Entities.Folder.RunTasks[T](Func`3 task, IList`1 children, IProgress`1 progress, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Folder.ValidateChildrenInternal2(IProgress`1 progress, Boolean recursive, Boolean refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
   at MediaBrowser.Controller.Entities.Folder.ValidateChildrenInternal(IProgress`1 progress, Boolean recursive, Boolean refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService, CancellationToken cancellationToken)
   at MediaBrowser.Providers.Manager.ProviderManager.RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder, CancellationToken cancellationToken)
   at MediaBrowser.Providers.Manager.ProviderManager.RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
   at MediaBrowser.Providers.Manager.ProviderManager.StartProcessingRefreshQueue()
ankenyr commented 1 year ago

This is likely a processing issue in Youtube. Just because a single video isn't valid doesn't mean that we want to use a different field. If you inspect the traffic when requesting it looks like a 404 is returned. In this case what should happen is if a 404 is returned the next image in order of preference is tried until the array is exhausted.

Relying on thumbnail by itself will not always lead to the best image. In this case thumbnail refers to the 7th item in the priority. Number 4 though is valid and of better quality.

https://i.ytimg.com/vi_webp/OB7HVOCo6oQ/sddefault.webp vs https://i.ytimg.com/vi/OB7HVOCo6oQ/hqdefault.jpg