480 lines
22 KiB
Markdown
480 lines
22 KiB
Markdown
|
|
# 01 — Artwork & Images on Jellyfin
|
|||
|
|
|
|||
|
|
How artwork actually flows through Jellyfin 10.10.x on this server, what went
|
|||
|
|
wrong with the Futurama library on first scan, and the exact API calls used to
|
|||
|
|
fix it. Written for an operator who's never used Jellyfin before but is
|
|||
|
|
comfortable with curl and Docker.
|
|||
|
|
|
|||
|
|
Server: `https://tv.s8n.ru` (Jellyfin `10.10.3`, container `jellyfin` on
|
|||
|
|
nullstone). Auth header below uses the long-lived API token — replace with your
|
|||
|
|
own `X-Emby-Token` if needed.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
TOKEN="*redacted*"
|
|||
|
|
H="-H \"Authorization: MediaBrowser Token=${TOKEN}\""
|
|||
|
|
BASE="https://tv.s8n.ru"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. How Jellyfin's image system works
|
|||
|
|
|
|||
|
|
Every "item" in Jellyfin (Movie, Series, Season, Episode, Person, BoxSet,
|
|||
|
|
MusicAlbum, etc.) can hold one or more images, keyed by **ImageType**.
|
|||
|
|
|
|||
|
|
Per-item-type, the relevant types are:
|
|||
|
|
|
|||
|
|
| ImageType | Movie | Series | Season | Episode | Notes |
|
|||
|
|
|-------------|:----:|:------:|:------:|:-------:|-------|
|
|||
|
|
| Primary | yes | yes | yes | yes | "Poster". The thumbnail you see in the grid. |
|
|||
|
|
| Backdrop | yes | yes | yes | no | Fanart / hero background. Multiple allowed (`Backdrop/0`, `Backdrop/1`, ...). |
|
|||
|
|
| Logo | yes | yes | no | no | Transparent text-logo, used in the detail-page header. |
|
|||
|
|
| Banner | no | yes | yes | no | Wide 758×140-ish strip. Mostly TheTVDB heritage. |
|
|||
|
|
| Thumb | yes | yes | yes | yes | 16:9 still. Episodes use this as their poster. |
|
|||
|
|
| Disc | yes | no | no | no | DVD/Blu-ray hub icon. Rare. |
|
|||
|
|
| Art | yes | yes | no | no | Clearart — transparent character cutout. |
|
|||
|
|
| BoxSet/Menu | (CC) | (CC) | - | - | ClearArt-style, used by some skins. |
|
|||
|
|
|
|||
|
|
For an **Episode**, the Primary IS the still — there is no separate "Thumb"
|
|||
|
|
in practice; clients fall back to whichever is present.
|
|||
|
|
|
|||
|
|
### Where images live on disk
|
|||
|
|
|
|||
|
|
Inside the container:
|
|||
|
|
```
|
|||
|
|
/config/metadata/library/<hash-prefix>/<item-id>/poster.jpg
|
|||
|
|
/config/metadata/library/<hash-prefix>/<item-id>/backdrop.jpg
|
|||
|
|
/config/metadata/library/<hash-prefix>/<item-id>/backdrop1.jpg
|
|||
|
|
...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
On the host that's `/home/docker/jellyfin/config/metadata/library/...`. They are
|
|||
|
|
stamped from URLs returned by the configured **Image Fetchers** — which are
|
|||
|
|
plugins, not built into core.
|
|||
|
|
|
|||
|
|
### What the API returns
|
|||
|
|
|
|||
|
|
`GET /Items?...&Fields=ImageTags,BackdropImageTags` returns:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"ImageTags": { "Primary": "abc...", "Logo": "def...", "Thumb": "..." },
|
|||
|
|
"BackdropImageTags": ["hash1", "hash2"]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
An empty `ImageTags: {}` and `BackdropImageTags: []` means **no images
|
|||
|
|
attached at all**. That was the Futurama symptom.
|
|||
|
|
|
|||
|
|
`GET /Items/{id}/Images` returns a per-image listing with size and path —
|
|||
|
|
returns `[]` (empty array) when nothing is attached.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. Which scrapers fetch which images
|
|||
|
|
|
|||
|
|
Jellyfin core ships with these image-related providers:
|
|||
|
|
|
|||
|
|
| Plugin | Movies | Series/Episode | Music | Images? | API key? | Notes |
|
|||
|
|
|-----------------------|:------:|:--------------:|:-----:|:-------:|:--------:|-------|
|
|||
|
|
| **TMDb** (built-in) | yes | yes | - | yes | bundled | The default. Provides Primary/Backdrop/Logo/Still. |
|
|||
|
|
| **TheTVDB** (plugin) | - | yes | - | yes | needs v4 key | Better for Banners and obscure shows. Requires installing the plugin and adding a TVDB v4 API key. |
|
|||
|
|
| **Fanart.tv** (plugin)| yes | yes | yes | yes | community key | Best clearart/clearlogo/disc art. Requires plugin install. |
|
|||
|
|
| **OMDb** (built-in) | yes | yes | - | no | optional | Metadata only. No images. |
|
|||
|
|
| **Studio Images** (built-in) | -| - | - | yes | none | Studio logos, scraped from a hard-coded GitHub list. Frequently 404s — harmless. |
|
|||
|
|
| **AudioDB / MusicBrainz** | - | - | yes | yes | none | Music only. |
|
|||
|
|
|
|||
|
|
### Provider order matters
|
|||
|
|
|
|||
|
|
In **Library options → TV Shows → Series → Image Fetchers** you order them.
|
|||
|
|
Jellyfin walks the list, takes the **first** result for each ImageType. So if
|
|||
|
|
TheTVDB is first and returns a Primary, TMDb is not consulted for that Primary —
|
|||
|
|
even if its image is better. Reorder, then refresh with `replaceAllImages=true`
|
|||
|
|
to force re-evaluation.
|
|||
|
|
|
|||
|
|
### What happens if a fetcher is listed but the plugin is missing
|
|||
|
|
|
|||
|
|
The library config carries the *names* "The Movie Database" and "TheTVDB" as
|
|||
|
|
strings. If the TheTVDB plugin isn't installed, that entry is silently ignored
|
|||
|
|
on each refresh — no error. Symptom: refresh "succeeds" but TVDB images never
|
|||
|
|
appear. Verify with `GET /Plugins`.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Common failure modes (and fixes)
|
|||
|
|
|
|||
|
|
### A. `EnableInternetProviders: false` on the library ⟵ THIS WAS US (1/2)
|
|||
|
|
|
|||
|
|
This is the first big gotcha. The setting is per-library, off-by-default
|
|||
|
|
when a library is created via the API or via certain "I'll configure it later"
|
|||
|
|
paths in the wizard. With it off, Jellyfin builds items from filenames only —
|
|||
|
|
no metadata, no images, no provider IDs.
|
|||
|
|
|
|||
|
|
Diagnostic:
|
|||
|
|
```bash
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Library/VirtualFolders" | jq '.[] | {Name, EnableIP: .LibraryOptions.EnableInternetProviders}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Fix: POST a full LibraryOptions payload back with `EnableInternetProviders:
|
|||
|
|
true`. **Note**: saving library options causes Jellyfin 10.10.3 to reload
|
|||
|
|
itself (~10–15s of HTTP 503). If you're scripting against the API, sleep before
|
|||
|
|
the next call.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Pull current options, mutate, push back
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Library/VirtualFolders" \
|
|||
|
|
| jq '.[] | select(.Name=="TV Shows") | {Id: .ItemId, LibraryOptions: (.LibraryOptions | .EnableInternetProviders=true)}' \
|
|||
|
|
> /tmp/tv-options.json
|
|||
|
|
|
|||
|
|
curl -s -X POST \
|
|||
|
|
-H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
--data-binary @/tmp/tv-options.json \
|
|||
|
|
"$BASE/Library/VirtualFolders/LibraryOptions"
|
|||
|
|
# Expect: HTTP 204
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### A2. Wrong fetcher names in TypeOptions ⟵ THIS WAS US (2/2, the real killer)
|
|||
|
|
|
|||
|
|
In **Jellyfin 10.10.x** the TMDb plugin advertises itself with the name
|
|||
|
|
**`TheMovieDb`** (no spaces). Older Jellyfin versions called it
|
|||
|
|
`The Movie Database`. If your library was upgraded from an old config OR if
|
|||
|
|
you copy-pasted from a 2022 forum post, your `TypeOptions[].MetadataFetchers`
|
|||
|
|
and `ImageFetchers` may say `"The Movie Database"` — and the matcher is
|
|||
|
|
**case+space-strict**. There is no fallback, no warning logged, no error.
|
|||
|
|
The fetcher list silently resolves to *zero matching providers* and refresh
|
|||
|
|
runs to completion in milliseconds without ever calling TMDB.
|
|||
|
|
|
|||
|
|
Symptoms:
|
|||
|
|
- Refresh returns 204, then nothing happens.
|
|||
|
|
- No `tmdb`/`fetch`/`provider` lines in the log at all.
|
|||
|
|
- `ProviderIds` may show `Tmdb: 615` if you manually identified the show via
|
|||
|
|
the UI — that goes through `ItemLookupController`, a different code path
|
|||
|
|
that *does* match by name. But subsequent automatic refresh still does
|
|||
|
|
nothing because the *library* fetcher list doesn't match.
|
|||
|
|
|
|||
|
|
Diagnostic — list what the server actually advertises:
|
|||
|
|
```bash
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Libraries/AvailableOptions?LibraryContentType=tvshows" \
|
|||
|
|
| jq '.TypeOptions[] | {Type, MetadataFetchers: [.MetadataFetchers[].Name], ImageFetchers: [.ImageFetchers[].Name]}'
|
|||
|
|
```
|
|||
|
|
Cross-check those exact strings against your library's TypeOptions.
|
|||
|
|
|
|||
|
|
Fix: rewrite the library's TypeOptions to use the names from
|
|||
|
|
`AvailableOptions` verbatim. Same payload as in fix A, but with
|
|||
|
|
`"TheMovieDb"` everywhere. Then trigger a FullRefresh. The first refresh
|
|||
|
|
fixed the missing series-level data (Overview, Genres, Primary, Logo, Thumb,
|
|||
|
|
Backdrop) and the second one — running without you doing anything because
|
|||
|
|
Jellyfin queues a children-refresh after a parent-refresh — populated all
|
|||
|
|
seasons and all 44 episodes with their stills and ProviderIds.
|
|||
|
|
|
|||
|
|
### B. Outbound DNS / network blocked from container
|
|||
|
|
|
|||
|
|
Symptom: TMDB plugin loaded, IDs not getting set, no obvious log error.
|
|||
|
|
Diagnostic:
|
|||
|
|
```bash
|
|||
|
|
ssh user@192.168.0.100 \
|
|||
|
|
'docker exec jellyfin curl -sI https://api.themoviedb.org/3/configuration --max-time 5'
|
|||
|
|
```
|
|||
|
|
A bare `HTTP/2 401` from `api.themoviedb.org` is **fine** — that's TMDB
|
|||
|
|
rejecting an unauthenticated probe. What matters is that the TLS handshake and
|
|||
|
|
HTTP response happened at all. If you see `Could not resolve host`, fix DNS
|
|||
|
|
(check `/etc/resolv.conf` inside the container, the docker network's DNS, or
|
|||
|
|
Pi-hole upstream).
|
|||
|
|
|
|||
|
|
### C. TMDB rate limit (40 req / 10 s per IP)
|
|||
|
|
|
|||
|
|
Symptom: refresh stalls partway, episode stills missing for some episodes,
|
|||
|
|
others fine. Look for `429` in the logs:
|
|||
|
|
```bash
|
|||
|
|
ssh user@192.168.0.100 'docker logs jellyfin --since 24h 2>&1 | grep -E "429|TooMany"'
|
|||
|
|
```
|
|||
|
|
Fix: nothing — just re-run the refresh. The bundled TMDB key is shared across
|
|||
|
|
all Jellyfin installs but rate-limited per source IP. Big libraries can take
|
|||
|
|
minutes to fully populate on the first scan.
|
|||
|
|
|
|||
|
|
### D. Language fallback with `PreferredMetadataLanguage`
|
|||
|
|
|
|||
|
|
We run `pl` (Polish) with `MetadataCountryCode=PL`. TMDB has very sparse Polish
|
|||
|
|
posters/backdrops for older Western shows. If `pl` returns nothing for a given
|
|||
|
|
ImageType, Jellyfin core asks for language `null` (international, no text) and
|
|||
|
|
then `en` as a final fallback. This works **as long as** TMDB plugin's
|
|||
|
|
"Include image fetcher language" setting includes English — set in
|
|||
|
|
*Dashboard → Plugins → TMDb → Image language*. Usually default-includes `en`.
|
|||
|
|
|
|||
|
|
If you see the metadata in Polish but only English-language posters, that's
|
|||
|
|
working as designed.
|
|||
|
|
|
|||
|
|
### E. NSFW / "Adult" filter blanking images
|
|||
|
|
|
|||
|
|
TMDB has an `include_adult` flag. Jellyfin defaults to *off*. For SFW content
|
|||
|
|
this never matters; for kids-anime imports that TMDB has flagged adult, posters
|
|||
|
|
go missing. Fix: `Dashboard → Plugins → TMDb → Include adult content = on`.
|
|||
|
|
Not relevant to Futurama.
|
|||
|
|
|
|||
|
|
### F. TheTVDB plugin without v4 API key
|
|||
|
|
|
|||
|
|
Old configs from Jellyfin 10.7 listed "TheTVDB" as the default series scraper.
|
|||
|
|
Since 10.9 the bundled key is gone — TVDB went paid. Symptoms: "TheTVDB" in the
|
|||
|
|
Image Fetcher list but no images sourced from there. Either install the
|
|||
|
|
**TheTVDB** plugin from `repo.jellyfin.org` and paste a v4 subscriber API key,
|
|||
|
|
or remove it from the fetcher order and let TMDb cover everything. We did the
|
|||
|
|
latter.
|
|||
|
|
|
|||
|
|
### G. Studios image errors in the log (red herring)
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
StudiosImageProvider failed in GetImageInfos for type Studio at /config/metadata/Studio/Adult Swim
|
|||
|
|
```
|
|||
|
|
The bundled Studio Images plugin scrapes a hard-coded GitHub repo
|
|||
|
|
(`MediaBrowser/jellyfin-plugin-studioimages-data`) for studio logos. That repo
|
|||
|
|
is occasionally unreachable or doesn't have the studio you need. **It does not
|
|||
|
|
affect series/episode/movie artwork at all.** Ignore unless you specifically
|
|||
|
|
want studio logos in the home-screen "Studios" row.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Triggering a metadata + image refresh
|
|||
|
|
|
|||
|
|
Per-item refresh — full replace:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
ITEM_ID="156e57437f795e5c8cd80fc98bafaee0" # Futurama series
|
|||
|
|
|
|||
|
|
curl -s -X POST \
|
|||
|
|
-H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items/$ITEM_ID/Refresh?metadataRefreshMode=FullRefresh\
|
|||
|
|
&imageRefreshMode=FullRefresh\
|
|||
|
|
&replaceAllMetadata=true\
|
|||
|
|
&replaceAllImages=true\
|
|||
|
|
®enerateTrickplay=false"
|
|||
|
|
# Expect: HTTP 204
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Modes:
|
|||
|
|
- `metadataRefreshMode` ∈ `None | ValidationOnly | Default | FullRefresh`
|
|||
|
|
- `imageRefreshMode` same set
|
|||
|
|
- `replaceAllMetadata=true` wipes Overview/Genres/etc and re-pulls.
|
|||
|
|
- `replaceAllImages=true` wipes attached images and re-pulls. Use this every
|
|||
|
|
time you've changed fetcher order or installed a new image plugin.
|
|||
|
|
- `regenerateTrickplay=true` forces re-extraction of trickplay sprites — heavy,
|
|||
|
|
leave off for metadata-only refreshes.
|
|||
|
|
|
|||
|
|
Refresh recurses into children: Series → Seasons → Episodes. For a single
|
|||
|
|
episode refresh, pass that episode's item ID instead.
|
|||
|
|
|
|||
|
|
Library-wide refresh (rare — usually you want per-item):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
curl -s -X POST -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Library/Refresh"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Watching progress
|
|||
|
|
|
|||
|
|
The Refresh task is asynchronous — `204` just means "queued". Monitor via:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Container log (best signal)
|
|||
|
|
ssh user@192.168.0.100 'docker logs jellyfin --tail 200 -f' \
|
|||
|
|
| grep -iE "futurama|tmdb|provider|fetch"
|
|||
|
|
|
|||
|
|
# API: poll the item itself
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items?Recursive=true&IncludeItemTypes=Series&userId=$USER_ID&\
|
|||
|
|
Fields=ProviderIds,ImageTags,BackdropImageTags" \
|
|||
|
|
| jq '.Items[] | {Name, ProviderIds, ImgKeys: (.ImageTags|keys), Backdrops: (.BackdropImageTags|length)}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`ProviderIds` populates first (within seconds), `ImageTags.Primary` and
|
|||
|
|
backdrops follow after the image fetcher has iterated through TMDB's image
|
|||
|
|
list and cached them locally.
|
|||
|
|
|
|||
|
|
### Inspecting a single item's images
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items/$ITEM_ID/Images" | jq
|
|||
|
|
```
|
|||
|
|
Returns an array of `{ImageType, ImageIndex, Path, BlurHash, Width, Height,
|
|||
|
|
Size}`. Empty array = nothing attached.
|
|||
|
|
|
|||
|
|
### Manually identifying a series (when auto-match misses)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Search TMDB for a candidate
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" -X POST \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
--data '{"SearchInfo":{"Name":"Futurama","Year":1999},"IncludeDisabledProviders":false}' \
|
|||
|
|
"$BASE/Items/RemoteSearch/Series" | jq '.[0]'
|
|||
|
|
|
|||
|
|
# Apply the picked TMDB ID
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" -X POST \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
--data '{"ProviderIds":{"Tmdb":"615"}, "Name":"Futurama"}' \
|
|||
|
|
"$BASE/Items/RemoteSearch/Apply/$ITEM_ID?replaceAllImages=true"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Installing the Fanart.tv plugin (optional)
|
|||
|
|
|
|||
|
|
Adds clearart / clearlogo / disc-art and richer backdrops. Not needed for the
|
|||
|
|
Futurama fix, but worth knowing for music libraries especially.
|
|||
|
|
|
|||
|
|
The current `https://repo.jellyfin.org/files/plugin/manifest.json` ships
|
|||
|
|
**Fanart 14.0.0.0** with `targetAbi 10.11.5.0` — that requires Jellyfin 10.11+.
|
|||
|
|
This server is 10.10.3, so the latest Fanart build is **not compatible**.
|
|||
|
|
Older builds in the manifest target `10.9.0.0` ABI which is too old for 10.10.
|
|||
|
|
|
|||
|
|
Options:
|
|||
|
|
1. Wait until we upgrade Jellyfin to 10.11+ and then install.
|
|||
|
|
2. Run an old-ABI build by manually dropping a `10.9.0.0`-targeted Fanart DLL
|
|||
|
|
into `/config/plugins/Fanart_<version>/` — works in practice, but requires
|
|||
|
|
a server restart and the user has asked us not to restart.
|
|||
|
|
|
|||
|
|
If/when you do install:
|
|||
|
|
```bash
|
|||
|
|
# Find the plugin GUID
|
|||
|
|
GUID="170a157f-ac6c-437a-abdd-ca9c25cebd39" # Fanart
|
|||
|
|
VERSION="14.0.0.0"
|
|||
|
|
|
|||
|
|
curl -s -X POST -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Packages/Installed/Fanart?AssemblyGuid=$GUID&Version=$VERSION"
|
|||
|
|
# Then a SERVER RESTART is required. The plugin won't appear in /Plugins
|
|||
|
|
# until restart.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
After install, edit each library's image fetcher list to include `"Fanart"`,
|
|||
|
|
then trigger `replaceAllImages=true` refresh.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. Futurama — what we found and what we did
|
|||
|
|
|
|||
|
|
### Findings
|
|||
|
|
|
|||
|
|
| What | Value |
|
|||
|
|
|-------------------------------------------------------|--------------------------------------|
|
|||
|
|
| Series item ID | `156e57437f795e5c8cd80fc98bafaee0` |
|
|||
|
|
| Path | `/media/tv/Futurama` |
|
|||
|
|
| Seasons / episodes on disk | 3 / 44 |
|
|||
|
|
| `LibraryOptions.EnableInternetProviders` (TV) | **`false`** ← root cause #1 |
|
|||
|
|
| `LibraryOptions.EnableInternetProviders` (Movies) | **`false`** (same bug) |
|
|||
|
|
| Fetcher names in TypeOptions | `"The Movie Database"` ← root cause #2; should be `"TheMovieDb"` in 10.10.x |
|
|||
|
|
| `"TheTVDB"` listed as fetcher | yes — but plugin not installed → silent no-op |
|
|||
|
|
| `ProviderIds` before fix | `{}` — nothing |
|
|||
|
|
| `ImageTags` / `BackdropImageTags` before fix | `{}` / `[]` |
|
|||
|
|
| Plugins installed | TMDb, OMDb, MusicBrainz, AudioDB, Studio Images, Open Subtitles |
|
|||
|
|
| TheTVDB plugin | **NOT installed** |
|
|||
|
|
| Fanart plugin | **NOT installed** (manifest only ships ABI 10.11/10.9 — not compatible with 10.10.3) |
|
|||
|
|
| Container outbound to `api.themoviedb.org` | OK — TLS + HTTP working, returned full image set for tv/615 |
|
|||
|
|
| Logs before fix | Only `StudiosImageProvider` errors (harmless GitHub 404s) — no TMDB activity at all |
|
|||
|
|
|
|||
|
|
### Changes applied
|
|||
|
|
|
|||
|
|
1. **TV Shows library** — flipped `EnableInternetProviders` to `true`,
|
|||
|
|
replaced `"The Movie Database"` and `"TheTVDB"` with `"TheMovieDb"` in
|
|||
|
|
`MetadataFetchers`, `MetadataFetcherOrder`, `ImageFetchers`,
|
|||
|
|
`ImageFetcherOrder` for Series/Season/Episode TypeOptions. Added a
|
|||
|
|
`Season` TypeOptions block (was missing — would have inherited "no
|
|||
|
|
fetchers" silently for season images).
|
|||
|
|
2. **Movies library** — same: `EnableInternetProviders=true`, fetcher
|
|||
|
|
string `"TheMovieDb"`.
|
|||
|
|
3. **PreferredMetadataLanguage** kept as `pl`, `MetadataCountryCode=PL`.
|
|||
|
|
Polish overview and genres landed; English fallback worked for poster art.
|
|||
|
|
4. **Server reloads** — three of them, each triggered automatically by
|
|||
|
|
`POST /Library/VirtualFolders/LibraryOptions`. No Docker restart, no
|
|||
|
|
compose change. (10–15s of HTTP 503 each. The reload IS the reason the
|
|||
|
|
first attempts to flip `EnableInternetProviders` appeared to "stick" then
|
|||
|
|
"revert" — what was actually happening: the API saw the new in-memory
|
|||
|
|
value, but the BACKGROUND save to disk omitted any property whose value
|
|||
|
|
matched the .NET serializer default; on reload the in-memory state came
|
|||
|
|
back out of sync with what we'd posted. Solution was to push the **full**
|
|||
|
|
options blob with EVERY explicit value set, including the corrected
|
|||
|
|
fetcher names — once both fixes were in the same payload, the in-memory
|
|||
|
|
state was usable for the next refresh and all metadata flowed.)
|
|||
|
|
5. **Triggered refresh** on series ID `156e57437f795e5c8cd80fc98bafaee0`
|
|||
|
|
with `metadataRefreshMode=FullRefresh&imageRefreshMode=FullRefresh&replaceAllMetadata=true&replaceAllImages=true`.
|
|||
|
|
First refresh populated Series-level data; the recursive children refresh
|
|||
|
|
that fires automatically afterwards filled all Seasons and Episodes.
|
|||
|
|
|
|||
|
|
### Final state (verified 2026-05-08 ~01:11Z)
|
|||
|
|
|
|||
|
|
Series **Futurama** (`156e57437f795e5c8cd80fc98bafaee0`):
|
|||
|
|
- `ProviderIds`: `Tmdb=615`, `Imdb=tt0149460`, `Tvdb=73871`, `TvRage=3628`
|
|||
|
|
- `Genres`: Animacja, Komedia, Sci-Fi & Fantasy
|
|||
|
|
- `Overview`: 182 chars (Polish)
|
|||
|
|
- `PremiereDate`: 1999-03-28, `EndDate`: 2025-09-15, `Status`: Continuing
|
|||
|
|
- `OfficialRating`: PL-12, `CommunityRating`: 8.37
|
|||
|
|
- `ImageTags`: Primary, Logo, Thumb attached
|
|||
|
|
- `BackdropImageTags`: 1 backdrop attached
|
|||
|
|
- On-disk files: `poster.jpg`, `backdrop.jpg`, `landscape.jpg`, `logo.png`
|
|||
|
|
in `/home/docker/jellyfin/config/metadata/library/15/156e57437f795e5c8cd80fc98bafaee0/`
|
|||
|
|
|
|||
|
|
Series-level images detail:
|
|||
|
|
|
|||
|
|
| ImageType | Resolution | Size (bytes) |
|
|||
|
|
|-----------|-------------|--------------|
|
|||
|
|
| Primary | 2000×3000 | 347,957 |
|
|||
|
|
| Logo | 1999×625 | 246,060 |
|
|||
|
|
| Thumb | 3840×2160 | 572,338 |
|
|||
|
|
| Backdrop | 3840×2160 | 995,768 |
|
|||
|
|
|
|||
|
|
Seasons (3/3 with Primary image):
|
|||
|
|
- Season 1 (Tvdb=6588) — Primary attached
|
|||
|
|
- Season 2 (Tvdb=6589) — Primary attached
|
|||
|
|
- Season 3 (Tvdb=6590) — Primary attached
|
|||
|
|
|
|||
|
|
Episodes:
|
|||
|
|
- 44 / 44 with `ProviderIds` (Tvdb + Imdb + TvRage on every one)
|
|||
|
|
- 44 / 44 with `ImageTags.Primary` (per-episode still)
|
|||
|
|
- All episode names in Polish (e.g. "Rok 3000", "Lądowanie", "Współlokator")
|
|||
|
|
|
|||
|
|
### Verification commands (run them yourself)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Series
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items?Ids=156e57437f795e5c8cd80fc98bafaee0&Fields=ProviderIds,ImageTags,BackdropImageTags&userId=2be0f0d3fe3a45dc9298138a15a01925" \
|
|||
|
|
| jq '.Items[0] | {Name, ProviderIds, ImageTags, Backdrops: (.BackdropImageTags|length)}'
|
|||
|
|
|
|||
|
|
# Seasons
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items?ParentId=156e57437f795e5c8cd80fc98bafaee0&IncludeItemTypes=Season&userId=2be0f0d3fe3a45dc9298138a15a01925&Fields=ImageTags,ProviderIds" \
|
|||
|
|
| jq '.Items[] | {Name, ProviderIds, ImageTags}'
|
|||
|
|
|
|||
|
|
# Episodes — count those with a Primary
|
|||
|
|
curl -s -H "Authorization: MediaBrowser Token=$TOKEN" \
|
|||
|
|
"$BASE/Items?Recursive=true&ParentId=156e57437f795e5c8cd80fc98bafaee0&IncludeItemTypes=Episode&userId=2be0f0d3fe3a45dc9298138a15a01925&Fields=ImageTags" \
|
|||
|
|
| jq '[.Items[] | select(.ImageTags.Primary)] | length'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Useful endpoints reference (Jellyfin 10.10 API)
|
|||
|
|
|
|||
|
|
| Endpoint | Purpose |
|
|||
|
|
|---------------------------------------------------|-------------------------------|
|
|||
|
|
| `GET /Library/VirtualFolders` | List libraries + options. |
|
|||
|
|
| `POST /Library/VirtualFolders/LibraryOptions` | Update one library's options. |
|
|||
|
|
| `POST /Library/Refresh` | Refresh whole library set. |
|
|||
|
|
| `POST /Items/{id}/Refresh` | Refresh one item + children. |
|
|||
|
|
| `GET /Items?Recursive=true&IncludeItemTypes=...` | Query items. |
|
|||
|
|
| `GET /Items/{id}/Images` | List attached images. |
|
|||
|
|
| `POST /Items/{id}/Images/{type}` (multipart) | Upload image manually. |
|
|||
|
|
| `DELETE /Items/{id}/Images/{type}/{index}` | Delete one image. |
|
|||
|
|
| `POST /Items/RemoteSearch/Series` (or `/Movie`) | Manual provider search. |
|
|||
|
|
| `POST /Items/RemoteSearch/Apply/{id}` | Apply chosen ProviderId set. |
|
|||
|
|
| `GET /Plugins` | List installed plugins. |
|
|||
|
|
| `GET /Repositories` | List plugin repositories. |
|
|||
|
|
| `POST /Packages/Installed/{name}?AssemblyGuid=&Version=` | Install plugin (needs restart). |
|
|||
|
|
| `GET /System/ActivityLog/Entries?Limit=N` | Recent server events. |
|
|||
|
|
| `GET /ScheduledTasks` | Task states + progress. |
|
|||
|
|
|
|||
|
|
Auth: header `Authorization: MediaBrowser Token=<token>` works for everything
|
|||
|
|
above. The `?api_key=<token>` query parameter form also works for GETs.
|