Skip to content

feat: add Emby/Jellyfin support via adapter pattern + per-item apply/restore#3

Open
JPT62089 wants to merge 21 commits into
Bothari:mainfrom
JPT62089:main
Open

feat: add Emby/Jellyfin support via adapter pattern + per-item apply/restore#3
JPT62089 wants to merge 21 commits into
Bothari:mainfrom
JPT62089:main

Conversation

@JPT62089
Copy link
Copy Markdown

@JPT62089 JPT62089 commented Apr 1, 2026

Summary

  • Multi-backend support: Adds an adapter pattern (MediaServer protocol) so googlarr works with Plex, Emby, and Jellyfin. One backend per instance, configured via config.yml.
  • EmbyAdapter: Full Emby/Jellyfin implementation using raw requests — library listing, item enumeration, season detection, poster download/upload (base64-encoded as Emby requires).
  • Per-item Apply/Restore: Hover buttons on each poster card let you push a single prank poster to the server or restore the original immediately, without waiting for the scheduled cron window.

What changed

Area Details
googlarr/server/ New package: base.py (Protocol), plex.py (PlexAdapter), emby.py (EmbyAdapter), __init__.py (factory)
googlarr/config.py Validates server.type/url/token/libraries instead of plex.*
googlarr/db.py sync_library_items() uses adapter instead of plexapi directly
googlarr/prank.py apply_pranks/restore_originals take server param, call server.upload_poster()
googlarr/main.py Uses create_server(config) factory
googlarr/web.py Two new endpoints: POST /api/items/<id>/apply and /restore
googlarr/web_ui.html Hover action buttons (Apply/Restore) on poster cards with inline status update
Legacy scripts apply.py, restore.py, regenerate.py updated to use adapter
Config server.type field (plex, emby, jellyfin) replaces plex.* block

Config change

# Before
plex:
  url: "http://localhost:32400"
  token: "your-token"

# After
server:
  type: "emby"        # plex | emby | jellyfin
  url: "https://your-server"
  token: "your-token"
  libraries:
    - "Movies"
    - "TV shows"

Test plan

  • Emby: library scan, poster download, prank generation, apply, restore
  • Per-item apply/restore via web UI hover buttons
  • Docker build and run
  • Plex: existing functionality preserved (PlexAdapter wraps plexapi unchanged)
  • Jellyfin: should work identically to Emby (same REST API)

🤖 Generated with Claude Code

claude and others added 21 commits March 31, 2026 20:39
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace direct PlexServer instantiation and deleted download_poster() usage
in apply.py, restore.py, and regenerate.py with the create_server() factory
and server.download_poster() adapter method.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Emby's POST /Items/{id}/Images/Primary expects base64-encoded image data,
not raw bytes. Raw bytes cause a 500 error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Bothari
Copy link
Copy Markdown
Owner

Bothari commented Apr 2, 2026

This is a massive and awesome PR; gonna review it over the next couple of days and set up small Jellyfin and Emby servers to confirm it works properly.

@JPT62089
Copy link
Copy Markdown
Author

JPT62089 commented Apr 3, 2026

Oh boy, I loved this idea so much I have more ideas that I wanna do... Not limited to just googly for April 1st 🤣

As I am sure it's fully obvious, my PR was 100% vibe coded... But I did do a bunch of testing with my Emby server. I did not spin up a jellyfin server to test there, though. Nor did I validate it did not break plex.

Hope it all works well for you!

@Project516
Copy link
Copy Markdown

As I am sure it's fully obvious, my PR was 100% vibe coded... But I did do a bunch of testing with my Emby server. I did not spin up a jellyfin server to test there, though. Nor did I validate it did not break plex.

I can test this on a jellyfin server if I have time.

For clarification this PR should add the googly eye feature to jellyfin?

@JPT62089
Copy link
Copy Markdown
Author

JPT62089 commented Apr 3, 2026

As I am sure it's fully obvious, my PR was 100% vibe coded... But I did do a bunch of testing with my Emby server. I did not spin up a jellyfin server to test there, though. Nor did I validate it did not break plex.

I can test this on a jellyfin server if I have time.

For clarification this PR should add the googly eye feature to jellyfin?

Should™

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants