Jump to content

[YouTube Plugin] Beta Test Thread


Go to solution Solved by eli761,

Recommended Posts

eli761
Posted

Hi everyone,

I would like to share a beta version of my YouTube plugin for Emby.

This plugin is focused on clean integration using the official YouTube Data API v3 and embedded YouTube playback.

Main plugin overview inside Emby:

image.thumb.jpeg.925da3af26d5c731161bedc7a52b5bf7.jpeg

image.thumb.jpeg.b86035348d349c73c8e0be3b496eb877.jpeg

image.thumb.jpeg.b47d6bbf50b105e5e00b0d225d0d0884.jpeg

What the plugin can do:

  • Browse YouTube channels, playlists, and search results directly in Emby
  • Support @handles, UC channel IDs, PL playlist IDs, and free-text search
  • Channel subfolders for Videos, Shorts, and Live/Upcoming
  • Trending view with region/category options
  • Recently Added view across configured channels
  • Optional Watch Later polling
  • Optional Hide Shorts toggle to fully remove Shorts from browsing views
  • Quota tracking shown in the plugin settings

 

Plugin settings:

image.jpeg.726f1a2eca9d78e604fd53738f4f2033.jpeg

 

 

image.jpeg.05dbeb00583674abaef82780668c2373.jpeg

image.jpeg.8911bd7c7941bf2ffe5ed41bec59a9a8.jpeg

Requirements:

  • Emby Server 4.9 or newer
  • YouTube Data API v3 key

Known limitations:

  • Playback uses the YouTube watch page in the embedded web player
  • Resume position cannot be reliably forced by the plugin in this playback mode
  • Audio track/language behavior is controlled by YouTube account/browser settings, not by plugin-side URL forcing

Download:

 

Thank you for testing and helping improve the plugin.

 

 

  • Like 7
graytinc
Posted (edited)

for some reason, I am getting error , even after pasting the API Key

RROR: Please configure a YouTube API Key in the plugin settings.

 

 

 

 

Edited by graytinc
eli761
Posted

Hey graytinc,

looks like a few things could be causing this, so let's work through them one by one:

First, make sure you've actually enabled the YouTube Data API v3 — just creating a key isn't enough. Head to Google Cloud Console → APIs & Services → Library, search for "YouTube Data API v3" and hit Enable. You can also use this direct link: https://console.cloud.google.com/apis/api/youtube.googleapis.com

Next, check your API key restrictions. Go to Credentials → click your key → under "API restrictions" set it to Don't restrict key for now. Also temporarily remove any HTTP referrer or IP restrictions you might have set.

Another thing worth trying: re-enter the key manually. Copy-pasting can sometimes sneak in invisible characters that silently break authentication.

And finally, don't forget to do a full Emby restart after any of these changes — it won't pick them up otherwise.

If none of that helps, drop your logs here and I'll take a closer look at what's actually going wrong.

LoveYou2
Posted (edited)

I try all impossible to make it work :(

image.thumb.png.50be731cf5637b8a713d82d23e619d80.png

image.thumb.png.d87ec0802ab3ef6307bdee0c4a10797a.png

Edited by LoveYou2
eli761
Posted

Hey,

Can you share the Emby logs? Without them it's just guessing.

eli761
Posted

One thing that's worth checking before we dig into the logs: after pasting the API key and saving, did you get a chance to run the "Refresh Internet Channels" task manually?

You can find it under Dashboard → Scheduled Tasks → Refresh Internet Channels — just hit the little play button next to it. Emby otherwise only refreshes channels on its own schedule (roughly every 24h), so the old "Please configure…" message can stick around for a while even though the key is already saved correctly.

  • Like 1
LoveYou2
Posted (edited)
22 minutes ago, eli761 said:

One thing that's worth checking before we dig into the logs: after pasting the API key and saving, did you get a chance to run the "Refresh Internet Channels" task manually?

You can find it under Dashboard → Scheduled Tasks → Refresh Internet Channels — just hit the little play button next to it. Emby otherwise only refreshes channels on its own schedule (roughly every 24h), so the old "Please configure…" message can stick around for a while even though the key is already saved correctly.

After Refresh Internet Channels is working :) thanks.

image.thumb.png.cbaf2112792b8785e4aaa2b65878ef3d.png

Edited by LoveYou2
LoveYou2
Posted

Excellent work. This is exactly what Emby was missing.

I have a problem, but I could be wrong, and it might not be a problem. I SET Trending region to GR but the results don't look right to me. I look forward to your response, and if there's any update, I'd like to know about it.

image.thumb.png.28360f979e316ced85415ca4e1ce4894.png

image.thumb.png.cbca47368135efef0663c9f03aae394d.png

eli761
Posted (edited)

When you say the results "don't look right," I'm curious what you were expecting to see — could you elaborate a bit?

If you mean it doesn't match your personal YouTube homepage, that's actually by design. The plugin pulls the regional Trending feed for your selected country (Greece in your case), which shows what's currently most popular and heavily watched across all viewers in that region — not personalized to your individual tastes.

Your YouTube homepage is curated based on your subscriptions and watch history, but Trending is a snapshot of what's objectively popular in the entire country right now. That's why you're seeing Greek gaming creators (Siaman, SenseiKoala, LegitGamingGR), and international viral content all mixed together.

To confirm this is working correctly, I actually ran the exact same API call the plugin makes:

https://www.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=50&regionCode=GR&key=YOUR_API_KEY

The response matched your screenshot perfectly — the videos you're seeing in Emby (Siaman's Minecraft video, SenseiKoala's Brainrot content, LegitGamingGR's Football Manager video, etc.) all appear in the official YouTube Trending list for Greece right now.

So the plugin is doing exactly what it's supposed to — faithfully showing what YouTube itself reports as trending in GR. If you'd prefer a more curated feed that matches your personal interests, I'd recommend using My YouTube Content instead and adding specific channels you follow. That way you get only the creators you actually want, with no algorithmic noise.

Edited by eli761
  • Thanks 1
graytinc
Posted

How are you getting images in Trending?

eli761
Posted

Hey, yeah that's a known issue — the images tend to break after about a day. I've been working on it and I'm currently testing whether my fix actually solves the bug. Will let you know once I've got some results!

Phyrate
Posted

Hello, great plugin, thank you for your work.

After I disabled the trending and categories section, the folders still appear, is that the normal functionality? The reason I disabled the trending section is that I set it to country code KR, and it said "nothing found" after refreshing. Thank you.

 

Untitled.jpg

Untitled2.jpg

LoveYou2
Posted
4 minutes ago, Phyrate said:

Hello, great plugin, thank you for your work.

After I disabled the trending and categories section, the folders still appear, is that the normal functionality? The reason I disabled the trending section is that I set it to country code KR, and it said "nothing found" after refreshing. Thank you.

 

Untitled.jpg

Untitled2.jpg

Try to "Refresh Internet Channels" task manually, you can find it under Dashboard → Scheduled Tasks → Refresh Internet Channels

  • Agree 1
GrimEvil
Posted

Works great, only issue is the thumb nails do not currently work for me so all the media is blank 

image.thumb.png.abc2bc2983d8598b84e5c0a6936e67dd.png

eli761
Posted

Hey,

same bug as the one I mentioned before. If you want, I can send you the test build I'm currently running to see if my fix holds up on your end too.

 

LoveYou2
Posted
2 hours ago, GrimEvil said:

Works great, only issue is the thumb nails do not currently work for me so all the media is blank 

image.thumb.png.abc2bc2983d8598b84e5c0a6936e67dd.png

You refresh metadata before this problem start Or have you had it from the start?

 image.png.9aa7df5bd177a2c8999c9125a102efea.png

LoveYou2
Posted

Hello eli761, playlist, @handle limit to 15-16 rows?

 

eli761
Posted

No, there's no 15-16 row limit in the plugin — you can add as many entries as you want (comma-separated). The code just splits by commas and loads them all.

The only real limit is YouTube's daily API quota (10,000 units/day). Cost per entry:

  • UCxxxx channel IDs → 1 unit 
  • @Handles → 1 unit  (plugin uses channels?forHandle=, not search)
  • PLxxxx playlists → 1 unit 
  • Free text search terms → 100 units  expensive

One important thing to keep in mind: on a cold load (first time opening the library, after a plugin restart, or when the metadata cache is empty), the plugin has to fetch full details for every single video — view counts, durations, descriptions, thumbnails, live status, etc. That uses the videos.list endpoint (1 unit per batch of 50 videos), so quota usage during the initial load is significantly higher than during normal use.

Once videos are in the metadata cache ), subsequent loads are much cheaper since most of the data is served from cache.

So if you're seeing entries cut off, it's most likely hitting a quota exhaustion or API timeout during the cold load, not a hard plugin limit.

GrimEvil
Posted (edited)
3 hours ago, LoveYou2 said:

You refresh metadata before this problem start Or have you had it from the start?

 image.png.9aa7df5bd177a2c8999c9125a102efea.png

I have not seen any thumb nails since the start and I have also refreshed metadata, but still only see the above. 

I have also done this for several of the videos with no change. 

Edited by GrimEvil
eli761
Posted (edited)

YouTube Plugin v1.17.1

Hey everyone 

New release is up — mostly Trending/Categories fixes, faster refresh for big channels, and a few quality-of-life tweaks.

Fixes:
- Empty Categories are now correctly hidden.

New:
- Auto-refresh after setup — no need to manually trigger a refresh anymore. Once you've entered your API key and saved your channels, the plugin kicks off the first refresh on its own. Just wait a few seconds and reload the page.
- Persistent MetaCache — descriptions, durations, premiere dates and thumbs now survive a restart. No more re-enrichment cost after a reboot.
- Configurable rate limit — new *"API Rate Limit (requests/min)"* setting (60–1200, default 240) for anyone with raised API quota.
- Channel folder shortcut — with *Hide Shorts* on and *Live Folders* off, clicking a channel jumps straight into Videos instead of a one-item submenu.

Quota:
- More efficient overall, lower daily usage


About the thumbnail bug:

Not 100 % sure yet if the bug where thumbnails disappear is really gone. With the persistent MetaCache it should be fixed, but I haven't been able to test it over several days.

If you try this version, please report back  whether your thumbnails stay permanently or break again after some time. Would really help me figure out if I still need to dig into this.

 

Download:

 

Have fun, and let me know how it runs for you 

Edited by eli761
  • Like 1
all4dom
Posted

Just copy & paste into plugin folder & restart emby?

Thanks

Dom

 

eli761
Posted

Yes, Just drop the .dll file into your programdata/plugins folder and give your Emby server a restart.

  • Thanks 1
all4dom
Posted

Ok thank you.

GrimEvil
Posted (edited)

still have blank images so not sure what is going on with my copy, I can see the below if it helps?

2026-04-23 15:26:03.431 Error ProviderManager: Error refreshing item World Tour Vlog 4 | Klangkuenstler x Unreal - Istanbul, Paris, Montréal 12860685 https://www.youtube.com/watch?v=xWYX3Xdk600
    *** Error Report ***
    Version: 4.10.0.10
    Command line: /system/EmbyServer.dll -programdata /config -ffdetect /bin/ffdetect -ffmpeg /bin/ffmpeg -ffprobe /bin/ffprobe -restartexitcode 3
    Operating system: Linux version 4.4.302+ (root@build7) (gcc version 12.2.0 (GCC) ) #86009 SMP Wed Nov 26 18:45:32 CST 2025
    OS/Process: x64/x64
    Framework: .NET 8.0.25
    Runtime: system/System.Private.CoreLib.dll
    Processor count: 4
    Data path: /config
    Application path: /system
    SQLitePCL.pretty.SQLiteException: Busy: database is locked
    SQLitePCL.pretty.SQLiteException: Exception of type 'SQLitePCL.pretty.SQLiteException' was thrown.
       at SQLitePCL.pretty.SQLiteException.CheckOk(sqlite3 db, Int32 rc)
       at SQLitePCL.pretty.DatabaseConnection.Execute(IDatabaseConnection This, ReadOnlySpan`1 sqlUtf8)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, Action`1 afterSave, Boolean disableForeignKeys, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, Boolean setDateLastSaved, Boolean saveMetadata, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, BaseItem parent, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at Emby.Providers.Manager.MetadataService`2.SaveItem(MetadataResult`1 result, Boolean isFirstRefresh, BaseItem[] collectionFolders, LibraryOptions libraryOptions, ItemUpdateType reason, IDirectoryService directoryService, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.MetadataService`2.RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at MediaBrowser.Controller.Entities.BaseItem.RefreshMetadata(MetadataRefreshOptions options, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.StartProcessingRefreshQueueInternal()
    Source: SQLitePCL.pretty
    TargetSite: Void CheckOk(SQLitePCLEx.sqlite3, Int32)
    
2026-04-23 15:26:03.499 Error ProviderManager: Error refreshing item Klangkuenstler @ Outworld Secret Rave, Berlin (live set) 12860686 https://www.youtube.com/watch?v=z16Yq4X87Hs
    *** Error Report ***
    Version: 4.10.0.10
    Command line: /system/EmbyServer.dll -programdata /config -ffdetect /bin/ffdetect -ffmpeg /bin/ffmpeg -ffprobe /bin/ffprobe -restartexitcode 3
    Operating system: Linux version 4.4.302+ (root@build7) (gcc version 12.2.0 (GCC) ) #86009 SMP Wed Nov 26 18:45:32 CST 2025
    OS/Process: x64/x64
    Framework: .NET 8.0.25
    Runtime: system/System.Private.CoreLib.dll
    Processor count: 4
    Data path: /config
    Application path: /system
    SQLitePCL.pretty.SQLiteException: Busy: database is locked
    SQLitePCL.pretty.SQLiteException: Exception of type 'SQLitePCL.pretty.SQLiteException' was thrown.
       at SQLitePCL.pretty.SQLiteException.CheckOk(sqlite3 db, Int32 rc)
       at SQLitePCL.pretty.DatabaseConnection.Execute(IDatabaseConnection This, ReadOnlySpan`1 sqlUtf8)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, Action`1 afterSave, Boolean disableForeignKeys, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, Boolean setDateLastSaved, Boolean saveMetadata, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, BaseItem parent, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at Emby.Providers.Manager.MetadataService`2.SaveItem(MetadataResult`1 result, Boolean isFirstRefresh, BaseItem[] collectionFolders, LibraryOptions libraryOptions, ItemUpdateType reason, IDirectoryService directoryService, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.MetadataService`2.RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at MediaBrowser.Controller.Entities.BaseItem.RefreshMetadata(MetadataRefreshOptions options, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.StartProcessingRefreshQueueInternal()
    Source: SQLitePCL.pretty
    TargetSite: Void CheckOk(SQLitePCLEx.sqlite3, Int32)
    
2026-04-23 15:26:03.560 Error ProviderManager: Error refreshing item Klangkuenstler Vlog | All Night Long @ Outworld, IFEMA Madrid 12860687 https://www.youtube.com/watch?v=0VCFpHPHlB0
    *** Error Report ***
    Version: 4.10.0.10
    Command line: /system/EmbyServer.dll -programdata /config -ffdetect /bin/ffdetect -ffmpeg /bin/ffmpeg -ffprobe /bin/ffprobe -restartexitcode 3
    Operating system: Linux version 4.4.302+ (root@build7) (gcc version 12.2.0 (GCC) ) #86009 SMP Wed Nov 26 18:45:32 CST 2025
    OS/Process: x64/x64
    Framework: .NET 8.0.25
    Runtime: system/System.Private.CoreLib.dll
    Processor count: 4
    Data path: /config
    Application path: /system
    SQLitePCL.pretty.SQLiteException: Busy: database is locked
    SQLitePCL.pretty.SQLiteException: Exception of type 'SQLitePCL.pretty.SQLiteException' was thrown.
       at SQLitePCL.pretty.SQLiteException.CheckOk(sqlite3 db, Int32 rc)
       at SQLitePCL.pretty.DatabaseConnection.Execute(IDatabaseConnection This, ReadOnlySpan`1 sqlUtf8)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, Action`1 afterSave, Boolean disableForeignKeys, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Data.SqliteItemRepository.SaveItems(List`1 items, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, Boolean setDateLastSaved, Boolean saveMetadata, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItems(List`1 items, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Server.Implementations.Library.LibraryManager.UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, BaseItem parent, MetadataRefreshOptions metadataRefreshOptions)
       at MediaBrowser.Controller.Entities.BaseItem.UpdateToRepository(ItemUpdateType updateReason, MetadataRefreshOptions metadataRefreshOptions)
       at Emby.Providers.Manager.MetadataService`2.SaveItem(MetadataResult`1 result, Boolean isFirstRefresh, BaseItem[] collectionFolders, LibraryOptions libraryOptions, ItemUpdateType reason, IDirectoryService directoryService, MetadataRefreshOptions metadataRefreshOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.MetadataService`2.RefreshMetadata(BaseItem item, MetadataRefreshOptions refreshOptions, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at MediaBrowser.Controller.Entities.BaseItem.RefreshMetadata(MetadataRefreshOptions options, BaseItem[] collectionFolders, LibraryOptions libraryOptions, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.RefreshItem(BaseItem item, MetadataRefreshOptions options, CancellationToken cancellationToken)
       at Emby.Providers.Manager.ProviderManager.StartProcessingRefreshQueueInternal()
    Source: SQLitePCL.pretty
    TargetSite: Void CheckOk(SQLitePCLEx.sqlite3, Int32)
    
2026-04-23 15:26:03.629 Error ProviderManager: Error refreshing item World Tour Vlog 2 | Klangkuenstler x Unreal  - Lisbon, Portugal 12860688 https://www.youtube.com/watch?v=SbtN9CGTVLI
    *** Error Report ***

 

maybe not able to write to the databsase for some reason?

 

Edited by GrimEvil
eli761
Posted

That error isn't actually about thumbnails — it's a generic Emby/SQLite issue.

The stack trace shows:
→ SQLiteException: Busy: database is locked


So what's happening: the plugin's image provider downloads the thumbnail fine (that part is just HTTP, never touches the DB). But when Emby then tries to save the refreshed item back to library.db, the database is locked by another writer, the whole refresh aborts, and the just-fetched image never gets written into the ItemImages table. 

Easiest thing to try first — but before you touch anything, make a full copy of your Emby programdata folder as a backup (just copy/paste the whole folder somewhere safe while Emby is stopped).

  1. Stop Emby.
  2. Go to your Emby programdata folder (the one containing library.db). If the files library.db-wal and library.db-shm exist, delete them. If they don't exist, just skip this step — nothing to do. (Never delete library.db itself!)
  3. Start Emby again.
  4. In Emby go to Dashboard → Scheduled Tasks and make sure no other library scan/refresh is running in parallel. Pause them if needed.
  5. Trigger a metadata refresh on the YouTube library only and check if the "database is locked" errors are gone.

Also, could you tell me:

How are you running Emby? (Docker, native install on Linux/Windows, Synology/QNAP NAS package, unRAID, TrueNAS, etc.)
Where does the programdata folder live? (local SSD/HDD, network share like NFS/SMB, external USB drive, NAS volume…?)

  • Like 1

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...