- Adding optional studio badges and a red `NEW EPISODES` series tag
The codebase is intentionally small and centralized:
- Backend and image pipeline: `app.py`
- Frontend UI, CSS, and browser logic: `templates/index.html`
- Static studio logos: `static/studios/`
- Generated cache files: `cache/`
## Runtime Model
The app is mostly a single-server process with one HTML page.
- FastAPI serves the UI and JSON/image endpoints
-`httpx.AsyncClient` is reused for Emby API calls
- Pillow is used for all image composition
- The browser page is a single template with inline CSS and JS
There is no frontend build system and no database.
## Configuration
Environment variables:
-`EMBY_URL`
-`EMBY_API_KEY`
Defaults are currently hard-coded in `app.py`. That is convenient for local usage but should be treated carefully if this app is ever shared more broadly.
## Key Files
### `app.py`
This file contains:
- App startup/shutdown
- Emby API helpers
- Image loading and upload helpers
- Font selection helpers
- The entire artwork render pipeline
- Search/image/apply API routes
This is the core of the system. Most behavior changes happen here.
### `templates/index.html`
This file contains:
- Full UI markup
- Full CSS
- Full browser-side state management
- Search/pagination logic
- Asset picker logic for Emby-known logos and backdrops
- Generate/apply button behavior
There is no JS framework. Everything is plain DOM code.
## How The App Works
### 1. Search flow
Browser:
- User types into the search box
- JS debounces and cancels stale requests
-`GET /api/search` is called with `q`, `start`, and `limit`
- Results are rendered in the left sidebar with lightweight poster images
Server:
-`/api/search` queries Emby `/Items`
- Returns paginated search results with metadata needed by the UI
- Search result posters are served via `/api/poster/{item_id}` using reduced dimensions for speed
### 2. Item image discovery flow
When an item is selected:
- The browser immediately starts a preview generate call
- In parallel, it calls `GET /api/images/{item_id}`
That endpoint returns the Emby-known images already attached to the item:
-`logos`
-`backdrops`
-`primaries`
The UI uses that to populate:
- Logo asset picker
- Backdrop asset picker
- Accurate backdrop counts
Important:
- This is Phase 1 of image browsing only
- It only exposes images Emby already knows for the item
- It does not yet perform remote/provider image lookup
### 3. Generate flow
Browser:
-`POST /api/generate`
- Sends the selected options:
- background mode
- selected backdrop index
- selected logo index
- logo position
- logo size
- darkness
- studio badge
- series tag
- whether to also generate a matching primary poster
Server:
- Pulls `Primary`, selected `Logo`, and selected `Backdrop` from Emby
- Builds the wide thumb with `generate_thumbnail(...)`
- Writes the thumb to cache
- Optionally builds and caches a tall primary via `generate_primary_cover(...)`
- Returns the thumb image stream to the browser
### 4. Apply flow
Browser:
-`POST /api/apply`
- Sends the same effective rendering settings as generate
Server:
- Rebuilds the same cache key
- Reads the cached thumb if present
- If missing, regenerates on demand to avoid cache-miss 400 failures
- Uploads the thumb to Emby as `Thumb`
- If `generate_primary` is enabled, uploads the cached or regenerated tall poster as `Primary`
Important:
-`Apply` must remain tolerant of cache misses
- Do not reintroduce a hard dependency on a pre-existing cache file only
- Better user-visible error reporting for partial apply failures
- Cache cleanup strategy
## Rules For Future Agents
- Do not split backend logic into multiple files unless there is a strong reason. This app is currently maintainable specifically because it is centralized.
- Do not introduce a frontend framework casually. The current plain JS approach is appropriate for the app’s size.
- Do not remove the cache-miss regeneration fallback from `apply`.
- Do not assume Emby optional image endpoints always return valid images.
- Do not change wide-thumb behavior without checking tall-primary behavior too.
- If adding a new render option, update both generate and apply paths and the cache key in the same change.