Artwork cannot be picked by hand: the RemoteImages routes are two stubs and a 404 #200
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The dashboard's artwork picker — Change image, which lists what TMDb has for
an item and lets an operator pick one — cannot work. Two of its three routes
answer empty and the third is unwritten:
POST /Items/{itemId}/RemoteImages/Downloadis not routed at all. Automaticartwork does work — a scan fetches and files the pictures a film won — so
this is only the hand-picking half.
The comment above the stubs is out of date: M10 landed the providers, and
nothing here needs to reach anything new.
Both halves already exist in the tree
Listing. The providers answer in exactly the shape the route wants —
Vec<RemoteImage>, andRemoteImage(
crates/ephyra-core/src/item/described.rs:15) carrieskind,url,width,height,language, which isRemoteImageInfomember for member:metadata/tmdb/mod.rs:131—images(a film)metadata/tmdb/tv.rs:159,180,212—series_images,season_images,episode_imagesmetadata/artwork.rs:70—thumb(a studio's, from the image repository)Downloading.
crates/ephyra-app/src/scan/run/remote.rs:816—downloadfetches a url and writes the picture where upstream keeps it, picking the
extension off the url and returning the path and the store's modified time.
That is what
SaveImagedoes upstream.So the work is the route layer: resolve the item, pick the right provider call
for its kind, page the result, and for the download, call the existing writer
and update the row.
What upstream answers
upstream/Jellyfin.Api/Controllers/RemoteImageController.cs:GetRemoteImages(line 62) — takestype,startIndex,limit,providerName,includeAllLanguages; answers aRemoteImageResultwithImages,TotalRecordCountandProviders. The DTO is already generated inephyra-dto— the stub returnsRemoteImageResult::default()today.GetRemoteImageProviders(line 127) — the provider names for the item, nonetwork.
DownloadRemoteImage(line 151) — requires elevation, takestypeandimageUrlon the query string, saves, marks the itemImageUpdate, answers204;404for an unknown item.Verifying it
D27: the network is recorded once and replayed to both servers. The recording
is
crates/ephyra-app/corpus/fetched.jsonbeside the answer keyenriched.json, cut together bycargo xtask reference gen-enriched-corpus;--extendkeeps what is recorded and asks only for what is new, which is themode to use here. A replay that misses hard-fails, so an unrecorded request
cannot silently reach the network in a test.
The picture-choosing rule M10 settled is the thing to not re-litigate: the
size asked for is
original, and a row records what the database reported —picking differently is a different width and a different diff.
Open
Providersfirst. It reaches nothing and makes the picker's providerfilter real; worth landing on its own.
mergetake theset of locked fields. An operator picking a poster by hand is explicit and
should probably override, which is what upstream does — but it is a decision,
not a given.
Done in
5e6bb607, with the review's findings in0087bbea.The picker is
crates/ephyra-http/src/routes/library/remote_images.rs; thefan-out a refresh already ran is now one function both callers reach, behind
RemoteArtwork— the composition root handing a route the same databases andthe same keys a scan gets.
Measured against a pinned upstream on the enriched fixture, both live. The
listings agree exactly:
and
/RemoteImages/Providersagrees for all 156 items the fixture holds —every kind, including the ones no scenario reaches.
Three things upstream disagreed with the first attempt about, each found by
that diff rather than by reading the C#:
OrderByLanguageDescendingis not alanguage sort — it is language, then rating to a tenth, then votes, which is
what a scan already ranked by. An
Orderenum threaded through six providermethods came back out.
the list into two passes reordered every picture that tied with another.
original, and nothing configures it to be.
What the review found
fetch_picturesanswers for, so an album carrying a release-group id wasasked twice per scan and filed two posters under a forced image refresh. The
first test written for it could not fail — the fake host answered every
request with the same bytes — so the fixture now answers the music database
with an album, and the test fails without the guard.
when the write was extracted.
The two routes read the item's kind through different functions and had come
apart.
Kind::Studiowas also missing from the list of kinds a stored typedecodes to.
is, so a
pngbehind a query was filed as ajpgand an error page wouldhave been filed as a poster.
Driven through the web client
Opening Edit images → search on a film lists the posters with their database,
language and rating; the Source filter narrows to one database; picking one
files it and the dialog closes on the item's new poster.
One trap worth knowing, and it is upstream's: the pinned bundle calls
loading.show()and then.then(...)with no.catch, so a download thatfails for any reason leaves a spinner that never stops.