Changelog
Highlights of recent releases. Every release carries its full notes on the GitHub Releases page.
v1.8.3.36 - A busy AI service no longer fails a library job; unusable Intel GPU is explained
2026-10-04 · target-server acceptance not run; GPU, live-player and HDR target-hardware behavior remain unverified
- Library jobs failed the whole video on the first frame the AI service rejected, and an HTTP 429 (all slots busy, for example while someone plays video through the same container) or a 503 during the circuit breaker's 10 second cooldown counted as final. These are now waited out, up to 6 times per frame, following the service's
Retry-After. Real client errors and cancellation behave as before (discussion #80). - Issue #90 (Intel Arc, "Device GPU is not available"): onnxruntime silently rebuilt the session on the CPU and the service never said why. The service now detects this, reports the reason, runs OpenVINO on its CPU device instead, and no longer reports that as a GPU. Usual cause:
group_add: rendernames a group that has a different ID inside the container than the host's render group. The startup log,/doctor(gpu_device_access),/gpu-verifyand/statusnow name the exact numeric group ID to use. - Docs: the install pages, README and compose file now say to pass the host's numeric GPU group IDs (AMD, Intel and Vulkan images). The AMD image build now fails when the ROCm provider is missing, instead of publishing a CPU-only image under the amd tag.
- The Intel fix was checked against a simulated onnxruntime and in a real container with a device only one group may open; it was not run on a real Arc GPU, so a driver problem on such a machine is not ruled out.
v1.8.3.35 - Player button without write access; engines behind a base URL
2026-09-26 · target-server acceptance not run; GPU, live-player and HDR target-hardware behavior remain unverified
- Issue #75: the player button appeared only when Jellyfin could write its web client's
index.html. A default Windows install (NetworkService under Program Files), the Debian package, snaps and read-only containers never got it, except in a tab that had opened the plugin's settings. - The plugin now adds its script to the page as Jellyfin serves it and leaves the file alone. The page is sent uncompressed and in full, so a cached copy cannot keep an older release's script.
- Checked on Jellyfin 12.1.0 with a read-only web folder: v1.8.3.34 served the page without the script, v1.8.3.35 served it with the script, and the web client loaded it with no errors.
- Behind a Jellyfin base URL (for example
/jellyfin) the Lanczos, Anime4K and WebGPU real-time engines never loaded: they were requested without the base URL, and Jellyfin redirected the request to its start page. They now load relative to the web client; checked on Jellyfin 12.1.0 behind/jellyfin. - The AI service is unchanged; all seven Docker variants are republished at v1.8.3.35 to keep versions in step.
- Local regression run: 466 C#, 212 Python and 77 Node behavior tests passed. Not a GPU or live-player certification.
v1.8.3.34 - Real-time upscaling starts again
2026-09-26 · target-server acceptance not run; GPU, live-player and HDR target-hardware behavior remain unverified
- Issues #86 and #87: since v1.8.3.31 real-time upscaling refused every video in the web client with "Video color metadata unavailable; realtime processing cannot be validated", and the menu stayed on Standby. The player looked for the playing item in the page address, where Jellyfin 10.9 and later no longer put it.
- It now reads the item from the video's stream address (direct play), or from the web client's playback request when Jellyfin transcodes to HLS. For an item with several versions it checks the colour format of the version that plays.
- v1.8.3.31, the version for Jellyfin 10.11, has the same defect.
- Issue #75: on a default Windows install Jellyfin runs as NetworkService, cannot write its web client's
index.html, and the player button never became permanent. The README and the support assistant now give the Windows fix; they no longer advise a reload that removes the button again. - The AI service is unchanged; all seven Docker variants are republished at v1.8.3.34 to keep versions in step.
- Local regression run: 454 C#, 212 Python and 74 Node behavior tests passed, plus a headless Chromium check with the stream and PlaybackInfo addresses Jellyfin 12.1 uses. Not a GPU or live-player certification.
v1.8.3.33 - Redesigned menus; SDR videos no longer refused as HDR
2026-09-24 · target-server acceptance not run; GPU, live-player and HDR target-hardware behavior remain unverified
- New in-player menu: a live frame-rate readout with a 20-second trend against the video's own rate, filter tiles that preview the playing frame, a bottom sheet on phones, a larger panel on TVs, and keyboard and remote support.
- The settings page in the same style; its tabs are real buttons that keyboards and TV remotes reach. Fixes an error on every Models-tab visit.
- HDR needs real evidence now: DVD/SD rips (smpte170m, bt470bg) and untagged 10-bit files are SDR again, in real time and in library jobs.
- HDR batch output keeps the model's detail (1.8.3.31/32 kept only its colour), and the model gets a fuller-range frame.
- Server AI: a stale frame no longer freezes over the video during an outage, and a server that cannot keep up hands over to Lanczos after 5 s.
- Local regression run: 454 C#, 212 Python and 57 Node behavior tests passed. Not a GPU or live-player certification.
v1.8.3.32 - Native Jellyfin 12
Native .NET 10 / Jellyfin 12.0 build, aligned test dependencies and CI, ABI-aware release validation, and updated Docker server examples. Requires Jellyfin 12.0 or newer. Regular ZIP and all seven Docker variants are published with matching version pins and rolling tags. Target-hardware acceptance remains unverified.
v1.8.3.31 — Playback recovery and model guards
2026-09-17 · target-server acceptance explicitly waived by the owner; GPU, live-player and HDR target-hardware behavior remain unverified
- Issue #79: playback frames and video chunks no longer consume the ten-image-actions-per-minute limit. The player handles 429/503, Retry-After, cancellation and fresh-frame retries with one request at a time.
- Driver upscaling prevents double processing. Object masking keeps its capture loop. Auto selects Server AI only when its measured frame rate reaches 80% of the video frame rate.
- Batch jobs stop on AI errors or invalid frames. FFmpeg decoding and encoding still run on the Jellyfin host; Docker handles the AI inference.
- Interpolation, face restoration and detectors stay out of normal upscaler selection. Import limits and conversion-output checks are enforced.
- PQ/BT.2020 RGB16 transport only; HLG, dynamic HDR and realtime/multi-frame HDR are rejected. HDR image quality still requires target-clip and display acceptance.
- All seven Docker variants receive v1.8.3.31 version pins and regular docker7 tags. CUDA remains the default; TensorRT requires compatible libraries and explicit opt-in.
- Local regression run: 443 C#, 209 Python and 36 Node behavior tests passed, including mutation checks. These results are not a GPU or live-player certification.
Release gates · Issue and discussion audit
v1.8.3.30 - Notifications stack instead of piling up
2026-08-16
- Issue #77: "if you hit a toggle in quick succession, the notifications will simply pile on top of each other." They did — literally. Every notification was its own
position: fixedelement anchored to the same corner, so two of them resolved to the identical coordinates and the second covered the first. Measured in a browser against the real CSS: three toasts all reportedtop 1185 / bottom 1226. - They are flow children of one fixed host now, and the host stacks them. Same measurement after the fix: 1185, 1136, 1087, no overlap.
- Repeating a message no longer clones it. Pressing a toggle repeatedly produces the same text over and over, and a tidy stack of five identical lines is still noise. An identical message still on screen has its timer restarted instead. Verified: firing "Settings saved!" five times leaves one.
- The stack is capped at four, so holding a control down cannot fill the viewport.
- The plugin had three copies of this code — config page, player overlay, quick menu — each with the same defect. All three are fixed, because fixing one is how a bug gets reported twice. The sidebar was already correct: it defers to Jellyfin's own toast, and there is now a test keeping it that way.
- Eleven regression tests; each of five reintroduced defects is caught. 375 C# + 166 Python tests green.
v1.8.3.29 - The error message now says what went wrong
2026-08-06
- Testing v1.8.3.28 on a live server showed the last piece of the same problem: a failed Load Detection Model always printed one generic sentence, no matter what happened. The handler read
err.responseText— an XHR field — while Jellyfin 10.11's client is fetch-based and rejects with aResponse. Confirmed against the running server: the rejection is[object Response],err.textis a function,err.responseTextdoes not exist, so the parse threw every single time. - Meanwhile the service was returning exactly what the user needed:
"definitelynotamodel is not on disk. Import or upload a detection model first". That reaches the status line now. - The old fallback also told you to save your settings — advice that stopped being true in v1.8.3.28, when the button started saving them itself.
- 364 C# + 166 Python tests green.
v1.8.3.28 - The object-masking card, as reported by someone using it
2026-08-06
- It works. Discussion #11 reports Ultralytics YOLO exports loading (YOLO26n fastest in their testing), boxes landing where they should, and 5–10 fps at low quality on a Ryzen 5 7600 through
docker7-cpu. Two UI bugs came with that, and both were real. - "The status would stick on a previous model name." Because it was telling the truth. The button POSTed nothing and the endpoint read only the saved config, so a newly typed id loaded the previous model and the status reported that one. The endpoint takes a
modelNamenow and the button sends what is on screen. The saved value stays as the fallback for scripts. - "It seemed to ignore the confidence values I put in." It did.
step="0.05"makes atype=numberinput reportvalue === ''for entries the browser rejects — and floating point puts values like0.6off that grid, since(0.6-0.05)/0.05is 10.999999999999998. The save path skipped empty strings, so the number vanished without a word.step="any", parse, clamp, and write the stored value back into the field. - Values reverted after navigating away. Nothing on this card was persisted until the global Save Settings, while an action button sat right next to the fields implying otherwise. Load Detection Model saves the card first, then loads.
- Four regression tests, each verified to fail when its fix is removed. 364 C# + 166 Python tests green.
v1.8.3.27 - What a live server showed that no test could
2026-08-05
- Every translated string had been falling back to its key, on every install.
strings.en.jsonwas declared as an embedded resource and was never in the DLL: MSBuild reads the.en.in the file name as a culture tag, so it was compiled into a satellite assembly (en/…resources.dll) that the release ZIP does not ship. Jellyfin logged "Failed to get resource" on every config-page load. The test guarding this asserted that the.csprojmentioned the file — which it always did. It now asks the built assembly. /hardware-inforeported three things it had never checked.GpuAvailablereturned the HardwareAcceleration config toggle (default on), so a CPU-only server was told it had a GPU while/gpu-verifyon the same box reported no devices at all.FFmpegAvailableandOnnxRuntimewere the literalstrueand"Available". All three are observations now, and what the user asked for is a separate field.- The frame proxies threw away the diagnosis. On a freshly restarted container the service answers
{"detail": "No model loaded"}— one line naming the fix — and the plugin replaced it with "Frame upscaling failed". The service's own message is passed through now. - Two documentation errors found the same way:
/Upscaler/healthis listed on the API page and does not exist (onlyhealth/detailed), andbenchmark-frameis a GET, not a POST. - 360 C# + 166 Python tests green.
v1.8.3.26 - The plugin downloads the detector itself
2026-08-05
- No more "bring your own model".
tiny-yolov3is in the catalog, so the Models tab downloads and verifies it like any other model. That was only possible once the pin could be verified rather than asserted: the file was downloaded, its sha384 checked against the OpenVINO model zoo's ownmodel.yml, and the sha256 in the catalog computed from those exact bytes. - A real model found a real bug. Loading the actual
tiny-yolov3on a live server reportedinput_size: 640. The export declares its spatial dims as('N', 3, None, None)— nothing in the file says 416, so the loader fell back to the generic default while the anchors are trained for 416. Every synthetic test model declares a fixed size, so no test could ever reach that path. The catalog now carries the size and the loader prefers it. - The catalog sync script had been broken since v1.8.3.23 and nobody noticed, because it is only run by hand. It executed
main.pyto read the model list, which needs fastapi, OpenCV and ONNX Runtime installed — and sincefrom . import object_maskwas added it failed outright with "attempted relative import". It parses the file withastnow: a literal dict needs no imports at all. - … and it would have mangled the file it writes. PowerShell captures command output as an array of lines and
Out-File -NoNewlineconcatenates array elements with no separator, so a run collapsed the whole pretty-printed catalog onto a single line — a 1000-line diff with no semantic change. Both bugs found by running it. - 356 C# + 166 Python tests green.
v1.8.3.25 - Detection models can actually be imported
2026-08-05
- Reported in discussion #11, and it was mine. The import gate hard-required a 4D output, so every detection model was rejected with
Expected 4D output (N, C, H, W), got shape [1, None, 4]— that is the boxes tensor of exactly theyolo-v3-tinyexport the feature was built for. v1.8.3.24 could load a detector and mask with it, and there was no way to get one in. I had verified the code I wrote, not the path a user walks. - The fix is a shared gate, not an override switch. The importer now classifies the model, and for detectors it calls the same
plan_forthat decides how to drive it at load time. Sharing it is the point: a model that imports is a model that loads. A separate, laxer import check would only move the rejection to a later step — worse, because by then the user believes it is installed. - An imported detector is registered as
object-detectionwith no scale factor, so it stays out of the upscaler dropdowns and auto-mode cannot pick it for a video. The category survives a container restart; before this it would have come back as a super-resolution model. - A model that is neither is now refused with both reasons stated. "Expected 4D output" alone sent the reporter looking for a mistake in his own import when the model was fine and the gate was wrong.
- Six tests covering import → load → mask as one path. Against the old gate five of them fail with the reporter's exact message.
- 354 C# + 166 Python tests green.
v1.8.3.24 - Object masking during playback
2026-08-05
- The part of discussion #11 that v1.8.3.23 did not deliver. The requester asked for a real-time filter; what shipped was a service endpoint nothing called. The player's capture loop already ran for server-side upscaling — it just had nowhere to send frames. With masking enabled it now posts to
Upscaler/detect-maskand draws the covered frame back onto the overlay. Switch it in Settings, or in the player menu under Auto → Cover objects. - It replaces upscaling on that stream, on purpose. Upscaling and detecting is two full inference passes per frame, which no realistic server sustains at playback rate. One endpoint per frame. Batch upscaling is untouched.
- Settings for classes, mode (box or blur), padding and confidence, plus an admin-only button that loads the detector. Padding defaults to 12 px because a detector's box hugs the animal and the ears sticking out set a dog off just as well.
- Tests that can actually fail. Mutation testing on the previous release found two guards asserting text rather than behaviour: the neighbouring-directory bypass could be put back with the suite green, and the critical path check could be made unreachable while a source-count guard still passed. Both are now exercised — the containment rule is a tested function, and
ProcessVideois called with a mocked library manager. The same pass found a state field written but never read, now deleted. - The AI service's object-masking endpoints are driven end to end by real synthesised ONNX models, one per detector family. Nothing had ever called them.
- A
CODE_OF_CONDUCT.md, which the contributing page had been promising while the file did not exist. - 354 C# + 160 Python tests green.
v1.8.3.23 - Object masking
2026-08-05
- Cover things you do not want on screen. Answers discussion #11: a user's dog reacts to dogs and cats on TV.
POST /models/load-detectorloads a detector alongside the upscaler, andPOST /detect-maskreturns the frame with detections covered by a filled box or a blur — by COCO class or theanimalsgroup, with padding, because a detector's box hugs the animal and the ears sticking out set a dog off just as well. - Why not ffmpeg, which is what was asked for. jellyfin-ffmpeg's build carries 46
--enable-*flags and no DNN backend at all — nolibopenvino, nolibtensorflow, nolibtorch; the stringdnndoes not appear in it.dnn_detectcannot run on the ffmpeg Jellyfin ships whatever the plugin passes it. And accepting arbitrary-vfwould be a hole rather than a feature: ffmpeg filter syntax includesmovie=andsubtitles=, which read files, handing every authenticated user the same primitive v1.8.3.22 had just closed. - Both detector families, decided by reading the model. Single-head exports (YOLOv5/v7/v8/v9) return raw anchors and need NMS from the caller; the ONNX YOLOv3 exports — including the
yolo-v3-tiny-onnxthe request named — take a second input, run NMS inside the graph and return boxes as(y,x,y,x)already in source coordinates. The service reads the loaded model's own inputs and outputs to tell them apart, and rejects anything it does not recognise at load time: a misread tensor does not raise, it paints boxes over the wrong part of the picture. - No detection model ships with it. Every catalog entry carries a verified sha256 pin, and inventing one for an unhashed model would break exactly the guarantee the importer provides. Bring your own through the existing import path.
- A static check that every global name the AI service references exists. Written because the detector loader called a helper this service has never had — Python resolves those at call time, so the module imported cleanly, the route appeared in the schema, and the endpoint would have raised
NameErrorthe first time anyone used it. It reports exactly that one name against the pre-fix file across 5 800 lines, and nothing else. - Also: the face-restore preview proxy read request bodies into the Jellyfin heap unbounded — now capped at 32 MB. And the object-masking tests were not running in CI at all (
cv2missing there), which is why the test dependency is now declared. - 321 C# + 150 Python tests green.
v1.8.3.22 - Code-review fixes: one critical, nine confirmed highs
2026-08-03
- Security.
POST /processaccepted any path on the server. The controller carries only[Authorize], and unlike its two sibling endpoints it had no media-library allowlist — with ffmpeg's-ythat was an arbitrary-overwrite primitive, and its "input file not found" reply doubled as a file-existence oracle. There is now one shared, separator-safe allowlist helper, and neither job entry point will overwrite an existing file. - Auto mode was never running in batch.
Modeldefaulted torealesrgan-x4, but the nightly scan gates on "auto enabled and model empty" — so with shipped defaults that gate was always false. Every batch run used a 4× model and skipped the hardware cap and 8K guard built in v1.8.3.14–.17, while the dashboard displayed "Auto". Same bug class asPreferredAnimeModelin v1.8.3.15: an override field's default must be empty. The dropdown has an Auto entry now, which it never did. - Every frame-by-frame job failed on comma-decimal locales.
fps=and both-ssvalues used the current culture, so 23.976 becamefps=23,976— and a comma is the ffmpeg filter separator. de-DE/fr-FR servers got "No such filter: '976'". - 100% CPU after any job cancel. Two permit leaks (Cancel kept one, Resume minted one) plus an empty-queue branch that handed the surplus straight back: wait succeeds, queue empty, release, repeat.
- Three silent misreports: a Lanczos fallback stored as an AI result (poisoning the library for all future runs), an HDR URL that 404'd on a trailing slash while reporting success, and expired cache entries orphaning multi-GB files on disk.
- The Docker cleanup script would have deleted every current tag. It pinned
v1.7.8while the repo shipped v1.8.3.21 — an-Executerun would have removed all 71 current tags and re-pointed:latestback to a v1.7.8 image. The version is derived frommeta.jsonnow and it refuses to run if its target tag is missing. - 14 regression guards. 315 C# + 123 Python tests green.
v1.8.3.21 - Maintainability groundwork
2026-08-01
- model_import.py - the OpenModelDB import and pth→ONNX conversion block moved out of main.py (6808 → 6627 lines) as a verbatim extraction. Every function body is byte-identical and no route moved; the endpoints keep their decorators. Three test monkeypatch targets moved with it - and one of them turned out to have been passing for the wrong reason.
- i18n groundwork. English is now the source language, read from a catalogue rather than hardcoded:
strings.en.jsonplus a smallt()helper. Adding a locale is copying the file, translating values, and one line of code. Nothing was translated - this phase proves the structure. - A full extraction would be ~485 strings; 58 are migrated - the activity strip and auto-mode texts, all of them new or rewritten in v1.8.3.20. Migrating text nobody is editing risks a regression for no benefit. docs/I18N.md records the numbers and how to continue per tab.
- A missing key renders as the key name, never as an empty string - a blank label is invisible in a screenshot. 7 tests guard the catalogue, including that both assets are embedded and registered, since getting that wrong 404s silently and turns every label into its key.
v1.8.3.20 - Honesty, visibility, reproducibility
2026-08-01
- The filter promise is settled. The UI said "AI picks model + filter per video" and the code half-kept it: it stopped overwriting a preset you had chosen, but still wrote its own whenever the field was empty - so the first playback quietly decided your look. Auto now suggests a look with an Apply button, in the player's Auto tab and the sidebar, and only when its opinion differs from yours. It writes nothing on its own.
- The activity strip says what a job is doing: phase, frame x of y, model with the auto reason, fps and ETA on one line. Those numbers were computed on every frame and thrown away after the websocket send; they are cached now, so a polled dashboard can show them. Idle says when the last job finished - the old "N jobs completed" counted a list that never contains completed jobs, so it could never appear.
- docs/ENDPOINT-AUDIT.md reports all 66 routes against their real callers. 20 have no reference in the repo, grouped by what they are - including a real gap: the settings page offers three Processing Queue controls over a queue whose six endpoints no UI ever calls. Nothing was deleted.
/Upscaler/hardware-benchmarkreplaces the misleadingly named/Upscaler/recommendations, which returns a hardware benchmark rather than a model recommendation. The old route stays as a deprecated alias with an identical payload.- Reproducible builds now actually are. Lock files existed since v1.8.3.13 and no image installed one. Five variants now install a hash-pinned lock with
--require-hashes;intelandnvidiaproduced their first lock ever (a non-root base that could not write the file, and a base with no Python at all). Two variants stay unhashed for documented reasons - see DOCKER-IMAGES.md. - The Python suite had been red since v1.8.3.14 - a mock kept an old signature after
download_modelgained a progress callback - and shipped over six releases because pytest was not a release gate. It is now. The download path is also covered for real against a loopback fixture server, including the SSRF gate, which had no tests at all. 293 C# + 123 Python tests green.
v1.8.3.19 - The Auto tab no longer states a default as a fact
2026-07-25
- Browser-testing the new tab against a live server caught it reporting "RUNNING NOW / nomosuni-compact-x2 / HD content in real time" on a page where no video was playing. With no video element the resolver is handed 0×0 and falls through to its HD branch — and the pane presented that fallback as a decision about the file in front of you, while printing the literal string "unknown output size" as though it were data.
- Three headings now, matched to what is actually known: Running now, Auto would pick (auto off), and Default pick — start playback for this file. In the last state the output size and the resolution-derived reason are omitted rather than printed, because both would be fabricated. The model, its scale and the signals stay: "Resolution: unknown" is true and useful.
v1.8.3.18 - Auto mode gets its own tab in the player
2026-07-25
- Auto tab in the in-player panel, and it leads. Auto mode has been the default since v1.8.3.12, but the panel only ever asked the Custom-mode questions ("pick a model", "pick a filter"). It now answers the one that matters while a video is running: what auto decided for this file, at what scale, to what output size, and why - with the "what it looked at" signals and any substitution warning.
- Everything switchable without leaving the player - auto mode itself, video filters, face restoration and real-time upscaling, each writing straight to the config and taking effect immediately. Turning real-time upscaling on or off restarts the loop, because that is when it reads its settings.
- Re-apply to this video re-runs the decision and hands it to the running upscaler. No page reload, no full configuration page.
- The filter row says what is true: auto suggests a look and never overwrites a preset you chose (v1.8.3.14 stopped it doing that silently).
v1.8.3.14 - v1.8.3.17 - Auto mode respects your hardware
2026-07-25
- The two recommenders finally talk. Content selection ("what suits this material?") and the AI service's hardware advisor ("what can this box run?") were separate systems that never exchanged a word, so a CPU-only NAS could be handed a full restoration net. An over-budget pick now falls back with a stated reason: "realesrgan-x4 suits the material but is too heavy for this weak CPU (no GPU) - clearreality-x4 was used instead so the job actually finishes." An unknown hardware class caps nothing, and a model you picked yourself is never overridden.
- The scale you were shown was not the scale you got. The AI service ignores the requested factor and uses the model's native one, so the library scan logged
scale=2xwhile auto ran a 4x model - a 1080p batch job silently produced 8K frames. The real factor is now read from the model, reported by the API and used by the job. A 4K source is cleaned up, not enlarged. - Every downloadable model has a Get button (27 had none), with real byte progress instead of a hardcoded "~300 MB". "Not DL" split into Not downloaded and Self-host only - no public ONNX build, nothing to wait for.
- Pause / Resume / Cancel on the dashboard, not just the Jobs tab.
- Three of these four releases exist because deploying to a real CPU-only server found what the unit tests had passed over: a shipped default that the resolver could not tell from a deliberate user choice, a substitution that overshot the target size, and a scale parser that knew only half the catalog's naming conventions. 273 tests now pin all of it.
v1.8.3.13 - Auto mode explains itself + reproducible builds
2026-07-25
- Auto transparency - the automatic model choice wrote its reasoning to a debug log that is off by default and returned a bare model name, so users saw a model they never picked. The dashboard now shows
Auto → modelwith the reason, an expandable "what it looked at" list, and an amber warning when a model was substituted (the preferred multi-frame model has no public ONNX build). The in-player notification and the sidebar carry the reason too. - Activity strip - one line on the dashboard: running file, phase, progress, model and fps; idle reads "Ready · Auto mode active" instead of a bare "Idle". No new data sources, just assembled.
- Reproducible builds - no Dockerfile carries an
APP_VERSIONdefault any more (six said 1.8.2 while one said 1.8.3.8, so/status,/healthand the dashboard reported a wrong version); CI injects it from the release tag and the release guard fails if a default reappears. A new weekly workflow resolves each Python layer inside its real base image, and CI now builds five image variants on every push instead of one - a dependency conflict can no longer surface after the release tag. - New docs/DOCKER-IMAGES.md: real image sizes (0.27 GB CPU to 20 GB AMD), converter RAM guidance, and the AMD stack CVE assessment with an exit trigger. Tests: xUnit 199, pytest 112.
v1.8.3.12 - Polish: Auto/Custom mode + face-model fix
2026-07-17
- Mode switch on the dashboard - Auto (default) picks model and filters per video from your benchmarks; flip the switch for Custom full manual control.
- Numeric sliders reverted to plain number inputs (the on/off toggle switches stay); the Live Model Benchmark card moved below AI Face Restoration; benchmark boxes keep a stable size.
- Face-model fix - gpen-512 and restoreformer++ were un-downloadable: upstream re-uploaded both files, so the sha256 pins no longer matched (the supply-chain gate refused correctly). Re-pinned after verification - all four face models download and load now.
- Console: 5000-line log buffer + Download button; FBGEMM/AVX2 error hint for transformer conversion on old CPUs.
v1.8.3.11 - Settings redesign + async everything + player favorites
2026-07-16
- New "Models" tab - Model Catalog, ★ Favorites, the importer (incl. file-install), AI Face Restoration, Live Benchmark and Comparison View live in ONE place now; the Settings tab shrank to five labeled groups (Connection / Upscaling / Playback / Library Scan / Advanced) with a live settings search box.
- Toggles & sliders instead of checkboxes - all 19 checkboxes render as switches and 8 numeric fields became sliders with live value badges. Same element ids underneath: saved configs and the save/load logic are untouched.
- Async import/convert with honest phases - imports run as background jobs (downloading → extracting/converting → validating) polled by the UI; big CPU conversions can no longer hit the proxy timeout. Face-restore models (~300 MB) download in the background with live status before loading. Older services fall back to the synchronous path transparently.
- Player favorites - the in-player quick menu shows a ★ Favorites category first (your pinned models incl. imports); imported models can be deleted from the Favorites card.
- New service endpoints
POST /models/import-async+GET /models/import-status/{id}; new plugin proxies incl. background downloads andDELETE models/import/{name}. Tests: pytest 103, xUnit 190, UI-consistency 123 refs.
v1.8.3.10 - Import-UX hotfix: warnings are not errors
2026-07-16
- The NC license notice is a warning again, not a fake error - it was rendered in the same permanent red as real failures, so imports looked broken. Now amber, with "import still possible" wording; red is reserved for real failures.
- Actionable error lines - every import/install failure now says what to do next (service unreachable → check URL + Test Connection; timeout → retry or file-install; 401/403 → token mismatch; 501 → converter image needed).
- Favorites card no longer briefly shows "not on the service" for a just-imported model (render order fixed); the "Model Catalog" card title shows the real model count instead of a stale "(35 Models)".
v1.8.3.9 - Hotfix: zip-pin semantics + converter exporter
2026-07-16
- ZIP imports work now - OpenModelDB pins the inner
.onnx, not the zip container (one AnimeJaNai release zip ships five variants); the extractor now selects the member whose sha256 matches the catalog pin. - pth conversion works now - torch ≥2.9 switched
torch.onnx.exportto the dynamo exporter (needs onnxscript); the export pins the legacy exporter (dynamo=False) and the converter image ships onnx+onnxscript. - Both bugs surfaced in the first live run on a real server - and the sha256/verification gates refused cleanly instead of installing wrong bytes, exactly as designed.
v1.8.3.8 - Install ANY OpenModelDB model
2026-07-13
- Importer everywhere - the AI service owns the import pipeline now: the
:5000dashboard got an "Import from OpenModelDB" section (search, license badges, one-click import), and the plugin config page shows the whole direct catalog - ready-to-use, convertible, and manual-install entries greyed out with the reason. ZIP-packed releases (the AnimeJaNai series) import one-click now (pinned zip verified, single .onnx extracted with a decompression cap). - New opt-in converter image
docker7-converter(CPU + torch/spandrel, ~2 GB): converts.pth/.safetensorscommunity models to ONNX and verifies the export against the torch output before registering - unlocks ~500 of the 609 pth-only models (240 fully automatic via sha256-pinned downloads). Standard images answer 501 with a clear pointer. - File install on the config page:
.onnxinstalls directly,.pthconverts - closes the gap for Google-Drive/Mega-hosted models (download in the browser, hand the file over). Installed files are auto-pinned to favorites. - ★ Favorites card: every pinned model with status (loaded/ready), Use and Unpin actions.
- Plugin import endpoints delegate to the service when available (downloads run in the container, not the Jellyfin process) with a transparent fallback for older images. The catalog generator records sha256 pins for convertible models too.
- Tests: pytest 99 (16 new gate/zip/converter invariants), xUnit 190, UI-consistency 120 refs. All 7 docker images released in lockstep as v1.8.3.8.
v1.8.3.7 - Model favorites + restart-proof imports
2026-07-13
- ★ Favorites - new group at the top of the model dropdown; pin/unpin the selected model with the star button next to it. Every one-click import is pinned automatically: pick a community model, hit Import, and it sits at the top of the list ready to select.
- Import search - a search box filters the ~40 importable OpenModelDB models live (name, architecture, license, scale).
- Fix: imported models survive container restarts - the AI service used to register uploads only in memory; a restart silently dropped them from the catalog while the file stayed in the volume. Uploads now write a
<name>.custom.jsonsidecar and are re-registered at startup; deleting a model removes both. Imported models are labelled Imported / Custom in the dropdown. - Tests: pytest 83 (5 new persistence invariants), xUnit 190, UI-consistency 114 refs. docker7 images released in lockstep as v1.8.3.7.
v1.8.3.6 - One-click model importer
2026-07-13
- Import community models from the config page - new "Import Community Model" card: pick any directly importable OpenModelDB model; the plugin downloads it (allowlisted hosts only, plain
.onnx, 500 MB cap), verifies the pinned sha256 and registers it with the AI service asomdb-<id>. No curl, no console. NC-licensed models show a non-commercial warning before import. - Docker service releases in lockstep - the docker7 images ship as v1.8.3.6 too, so the service dashboard shows the same version as the plugin (it had stayed at 1.8.3.4 because images only rebuild on docker tags; no functional service change).
- New admin endpoints
GET /Upscaler/models/importable+POST /Upscaler/models/import; the external download client carries no service token, so the secret never reaches third-party hosts. - Catalog check against the 2026-07-13 OpenModelDB refresh: no new freely-licensed direct-ONNX candidates (all 2025/2026 additions are CC-BY-NC) - exactly the gap the importer covers for private use.
- Tests: xUnit 186 (22 new importer-gate invariants), pytest 78.
v1.8.3.5 - Hardening + importable models
2026-07. Guard-rails release + 660+ importable community models.
- Importable models page. New Importable models page: 60 ready-to-use ONNX + 609 convertible community models from OpenModelDB, with license badges (non-commercial flagged), sizes, sha256 pins and direct downloads. The data refreshes weekly via CI; the page renders the JSON client-side, so nothing is hand-maintained. The site's AI assistant answers questions about any of these models.
- Triple-feed release guard.
verify-release.ps1now asserts all three plugin feeds (manifest.json,repository-jellyfin.json,repository-simple.json) carry the release with one consistent checksum — live and in the checkout. Kills the issue-#74 drift class for good. - UI field-consistency check in CI. Every element id referenced from JS must exist in the HTML (the v1.8.3.3 save-crash class). It immediately caught a real one: the test-upscale button read a non-existent
#PreferredModeland silently always tested realesrgan-x4 — it now tests the selected model. - Small fixes.
UserManagerAdaptercaches its reflection lookup (was per user × item on library scans); 5 new pytest invariants for the face-restore helpers; the three recommendation endpoints got disambiguating docs (they are different functions, not aliases — the planned consolidation was intentionally dropped).
v1.8.3.4 - Jellyfin 12.0 readiness + catalog integrity
2026-07. Compatibility + curation release.
- Jellyfin 12.0 ready (RC-tested statically). Building against
Jellyfin.Controller 12.0.0-rc2surfaced exactly one API break (IUserManager.Usersremoved); the user lookup now adapts at runtime, so one DLL serves 10.11.x and 12.x. The web code already uses the modernAuthorization: MediaBrowserscheme, so 12.0's legacy-auth rejection does not affect the plugin. Full break list + RC test plan:docs/JELLYFIN-12-READINESS.md. - Catalog integrity sweep. All 73 model URLs HEAD-checked: 16 were dead (8 HuggingFace repos deleted upstream). 9 repointed to verified mirrors, 7 marked [self-host required] because no public ONNX exists.
- 3 new license-checked models (sha256-pinned, CPU-benchmarked):
purephoto-realplksr-x4,nomos8kdat-x4(JPEG restoration),fallin-soft-x2(real-time anime).clearreality-x4repinned to the author's Apache-2.0 build — measured 32× faster than realesrgan-x4 on CPU.ultrasharp-v2-x4now carries its CC-BY-NC-SA flag. - Downloads are hash-verified. New
license/attribution/sha256catalog fields; the service verifies the sha256 before a downloaded model is activated. - Docker supply-chain. Explicit
starlette>=1.0.1floor (BadHost auth-bypass fix) + Pillow/python-multipart/opencv floors raised in all 7 requirement sets; base images re-pinned (python-slim digest, CUDA 12.8.1);:latestnow updates with every publish (was stuck on a v1.7.8-era image).
v1.8.3.3 - Fix config-page Save
2026-06. Plugin-only hotfix.
- Save works again. The v1.8.3.2 SSH cleanup left one stale, unguarded line in the settings Save handler that referenced a removed input and threw a
TypeError, so saving plugin settings failed. Removed that line; no other change.
v1.8.3.2 - Remove dead SSH remote transcoding
2026-06. Plugin-only release (closes #73).
- Removed the stale SSH remote-transcoding path. The docker7 image dropped sshd long ago (non-root appuser hardening), but the plugin still shipped SSH config + UI, a
/Upscaler/ssh/testendpoint that ranssh, and an FFmpeg-wrapper installer. All of it is gone, including the now-orphaned PlatformDetectionService. - Offload over HTTP instead. Point AI Service URL at
http://<host>:5000- no SSH, no wrapper script. Removes an admin endpoint that executedssh. Existing docker7 images unaffected.
v1.8.3.1 - Cancel-fix
2026-06. Plugin-only release.
- Cancel actually stops a job now. The job-cancel endpoint reported success but never halted the running job: the per-job cancellation token was created and cancelled correctly, but the bare caller token (not the linked per-job token) was passed into the extraction/upscaling pipeline, so the signal never arrived. The semaphore wait, model load and the method executor now all receive the linked per-job token. Pre-existing across all processing methods.
v1.8.3 - Opt-in pipeline parallelism
2026-06. Plugin-only release (works with the existing docker7 images, no rebuild needed).
- Pipeline parallelism (experimental, default OFF). A new setting overlaps frame extraction with upscaling instead of running them strictly back-to-back: while ffmpeg is still extracting later frames, already-extracted frames are upscaled concurrently. Built on a thread-safe
FrameStreamCoordinatorthat hands a frame to the upscaler only once a successor frame proves it was fully written, and drops the unproven highest frame if extraction fails, so the output frame-count and ordering match the sequential path exactly. Default behaviour is unchanged; the overlap runs only when you tick the box. - Tests.
FrameStreamCoordinatorstate-machine coverage (COMPLETE-vs-FAILED asymmetry, terminal-first-wins); xUnit 164, dotnet build clean.
v1.8.2 - Quality + hardening pass
2026-06. Plugin + service update.
- Denoise-before-encode prefilter. A dedicated source-clean pass (
hqdn3d/nlmeans) that runs before upscaling/encoding - independent of the camera-style filters. Cleaner input means better SR and a smaller re-encode. - VMAF quality scoring. New admin-only
POST /Upscaler/vmafobjectively scores an upscaled file against a reference via ffmpeg+libvmaf (0-100). - Second interpolation architecture. The frame-interpolation engine is now input-signature-adaptive (RIFE / IFRNet / CAIN); IFRNet + CAIN added to the catalog as experimental self-host.
- MultiFrame extraction progress. The multi-frame path now reports live extraction progress like the other pipelines.
- Decoupled model download.
POST /models/download-async+GET /models/download-status/{id}run big downloads in the background so they no longer trip client timeouts. - Supply-chain hardening. All six Docker base images pinned by
@sha256digest + a pip-audit CVE sweep (0 known vulnerabilities). - Docs + tests. New "client-VSR vs server-side" hardware chapter, a verified frame-stream coordinator, and new tests across detection, denoise, VMAF, interpolation, async download and multi-frame VSR.
v1.8.1 - Live filter fix + hardware-aware recommendation
2026-06. Plugin + service update.
- Live video filters fixed. In-player presets/sliders had no visible effect while realtime client-side upscaling was active - the upscaler renders to a canvas overlay that covered the filtered
<video>. The CSS filter is now applied to the visible canvas too, so filters take effect again. - Hardware-aware model recommendation. New
/recommend(service) and/Upscaler/recommend(plugin) pick a model + scale your detected hardware can actually run - a weak CPU gets fsrcnn-x2 @2x, a dedicated GPU gets Real-ESRGAN x4 - instead of letting you pick a heavy model that hits the seconds-per-frame wall.
v1.7.13 - Settings-page redesign + API-token guide
2026-06. Plugin release (no Docker functional change).
- Redesigned settings page. The plugin config page now uses the same clean "Operator Console" look as the Docker service UI - consistent dark theme, cards, KPI tiles, chips, blue accent, Inter typography. CSS-only re-theme: every setting and behaviour is unchanged.
- API-token setup, finally clear. New step-by-step guide for securing the AI service:
API_TOKENis a container environment variable - set it in compose/run and paste the same value into the plugin's "AI Service API Token" field; or useAPI_TOKEN=disableon a trusted LAN. The plugin field's hint now spells out there's no "generate" button (you set the value in both places).
v1.7.12 - First-load timeout fix + real error messages
2026-06. Plugin release (no Docker functional change).
- First-time downloads no longer fail with "Load failed". Loading a model that has to download (face-restore GFPGAN/CodeFormer/GPEN ~280-377MB, or large ONNX) hit a 120s proxy timeout mid-download. A dedicated 570s download client fixes it (just under the 600s UI wait so an over-long download surfaces a real error, not a blank browser timeout); the /models/load UI timeout was raised to match, benchmarks went 120s to 300s.
- Real error messages. The UI error parsers now read detail || error || message, so the actual cause is shown instead of a generic "Load failed". A DI test guards the named-client timeouts so a typo can't silently fall back to the 100s default.
v1.7.11 - Honest extraction progress + version-display guard
2026-06. Plugin release (no Docker functional change).
- "Stuck at 95%" - now fixed for the extraction phase too. Batch progress shows real frame-extraction + upscale progress (frames done/total) instead of a time estimate that pinned at 95% during the long ffmpeg extraction on slow CPUs (#72); the dashboard shows the live phase (Extracting / Upscaling / Encoding) instead of "Idle". The pipe-encode path that could also pin at 95% is fixed (unknown-total sentinel).
- Honest version display, guarded. configurationpage.html now shows the real plugin version (v1.7.10 shipped still rendering v1.7.9), and the release script asserts every user-visible version string matches the tag so it can't drift again.
v1.7.10 - "Stuck at 95%" fix + sharper GPU diagnostics
2026-06. Docker + plugin release, both at v1.7.10.
- "Stuck at 95%" fixed at the root. Job progress now reflects real frames processed (frames done/total + fps + ETA) instead of a time estimate that capped at 95% on slow hardware. A job with no AI model loaded now fails fast with a clear "load a model first" message instead of grinding to 95% and hanging. (#70 / #72)
- Smarter Setup Doctor.
/doctordetects "GPU + CUDA/ROCm available but inference on CPU" (a host driver/toolkit mismatch) and gives the right fix -- update the host driver / check logs -- instead of mislabeling it a CPU image. (#71) - Honest version display. The in-player menu + System-Diagnostics panel now show the real plugin version.
v1.7.9 - Setup Doctor + Embedded Anime4K + GPU-State Fix
2026-06. Docker + plugin release, both at v1.7.9. Pull the refreshed docker7 / docker7-<backend> images and update the plugin.
- Setup Doctor. New
GET /doctorone-shot self-diagnostic - backend, GPU provider active, device passthrough, the right onnxruntime build (catches vendor-shadowing), API token, and a model smoke test, each row with a copy-paste fix - plus a "Setup Check" panel on the Docker dashboard's Hardware tab. Condenses the #66/#69/#70 setup-friction saga into onecurl. - GPU-state fix.
run_benchmark(),/models/loadand/benchmark-framestill reported the requested GPU intent instead of the active provider truth; all three now usegpu_is_active(). - Anime4K actually runs now. The "Anime4K (anime shader)" real-time tier previously loaded a dead CDN URL and silently fell back to Lanczos. It now ships a vendored, tree-shaken Anime4K.js (npm 1.1.2, Anime4K 4.0.1, WebGL, MIT, ~225 KB) embedded in the plugin DLL - offline, no CDN - with a WebGL2 float-texture support-gate and automatic Lanczos fallback. Honest label: an anime shader, not a neural net. Third-party licenses recorded in
THIRD-PARTY-NOTICES.md. - Docs honesty. Honest real-time tier ladder across README + site; the website support bot gained a Setup Doctor topic.
v1.7.8 - Model Catalog +12 & GPU / Benchmark / AMD Fixes
2026-06. Plugin bumped to v1.7.8 (embedded offline model-fallback refreshed 59 → 71); all functional fixes ship in the Docker images. Pull the refreshed docker7 / docker7-<backend> images (or pin :v1.7.8-<backend>). All changes are in docker-ai-service/.
- Model catalog 59 → 71 (+12). New ONNX models from the curated
notaneimu/onnx-image-modelssource, focused on compressed/streaming sources:realesr-general-x4v3/-wdn(tiny modern general default),realwebphoto-v4-dat2-x4+nomoswebphoto-realplksr-x4(trained on degraded web images),dejpg-realplksr-1x+denoise-realplksr-1x(1x artifact-cleanup pre-passes),foolhardy-remacri-x4,nmkd-siax-x4,nomos8k-hat-l-x4(full HAT-L),textures-rgt-s-x4(RGT-S, new architecture),lsdir-compact-v2-x4,spanx2-ch48. - 256px-model benchmark crash (#70):
run_benchmark()now reads the loaded ONNX session's real input shape, so fixed-shape models (realesrgan-x4-256) benchmark at 256×256 instead of a 64px tile that raised a Reshape error during warmup - the "Reshape" failure Gemini misattributed to the GPU. - GPU-active reporting (#69/#70): new
gpu_is_active()derives "is the GPU really in use?" from the live execution-provider list (now counts OpenVINO/CoreML, not only CUDA/ROCm)./health,/status,/hardware,/gpu-verifyreport the honest value - the dashboard and System tab no longer disagree, and/gpu-verifyno longer showsusing_gpu:falsewhile OpenVINO is active. - AMD image ran on CPU: the build log proved the
onnxruntime-rocmwheel installed fine, but plainonnxruntime(pulled byrequirements-amd.txt) shadowed it - both ship the sameonnxruntimemodule and the plain build won. Removed it from the AMD requirements and force-installonnxruntime-rocmas the sole provider inDockerfile.amd. - Stale service version: the startup banner /
/statusreported a hardcoded1.6.1.21;VERSIONnow reads theAPP_VERSIONbuild arg.
v1.7.7 - Docker Self-Verification Hardening
Released May 2026. Structural completion of the Intel-Arc saga (#45/#66/#67/#69). A dedicated docker-ai-service deep-analysis found no acute bugs left - but a missing verification layer. C# Plugin DLL bit-identical to v1.7.6 - all changes are in docker-ai-service/. Tests 123/123.
- Build-time provider asserts (the core fix): No Dockerfile checked at build time whether its expected ONNX provider was actually installed. That gap is exactly what let the v1.7.5 Intel bug slip through (plain
onnxruntimebuilt fine but had no OpenVINO EP → CPU-only image despite a GPU dashboard). New:Dockerfile(NVIDIA) assertsCUDAExecutionProvider,Dockerfile.intelassertsOpenVINOExecutionProvider- both hard-fail (exit 1) if the provider is missing. The build goes red instead of publishing a working-looking CPU-only image. - AMD provider visibility:
Dockerfile.amdhad a silent|| pip install onnxruntimeCPU fallback. New: a warn-only assert (exit 0, because CPU is a valid fallback for AMD when ROCm wheels are yanked) - the CPU mode is now visible in the build log instead of slipping through unnoticed. - entrypoint.sh WSL2 awareness:
detect_backend()only checked/dev/dri/renderD128and falsely printed "Backend: cpu" (plus a false GPU-missing warning) on WSL2 setups, even thoughmain.pycorrectly detects the GPU via/dev/dxgsince v1.7.4. New: a/dev/dxgbranch → banner is consistent with the real detection. - Verification:
dotnet build- 0/0. Build asserts run on every Docker rebuild. Quad-MD5 verified post-release.
v1.7.6 - Intel OpenVINO Provider Hotfix (Issue #69 Point 1)
Released May 2026. Hotfix release closing the last open point of issue #69 (Intel Arc GPU detected but inference ran on CPU). C# Plugin DLL bit-identical to v1.7.5 - fix is docker-ai-service only.
- Root cause - empirically verified via Laurent's
/gpu-verify: His setup was correct (group_add: render, WSL2 mount, latest image), butonnx_providerscontained only[AzureExecutionProvider, CPUExecutionProvider]. NoOpenVINOExecutionProviderin the list - the plugin could not do GPU inference on Intel hardware at all, regardless of model. Gemini's diagnosis (Reshape node in realesrgan-x4) was symptom-treatment. - Plugin bug in
requirements-intel.txt: The comment there wrongly claimed "onnxruntime-openvino is deprecated, use onnxruntime + system OpenVINO". Wrong: plainonnxruntimefrom PyPI does NOT bundle theOpenVINOExecutionProvider, not even with system OpenVINO in the base image. The provider is only available in the dedicatedonnxruntime-openvinoPyPI variant. - Fix (1 line):
onnxruntime>=1.20.0,<2.0.0→onnxruntime-openvino>=1.20.0,<2.0.0inrequirements-intel.txt. Plus the wrong comment removed + an honest note about the empirical verification. After a Docker Hub image pull + container restart,/gpu-verifyshowsOpenVINOExecutionProvideras an active provider. - AMD build retry: the v1.7.5 docker-publish had a Trivy timeout on the AMD ROCm scan (Triton kernel-dumps too large). v1.7.6 re-triggers all 6 backends - AMD should pass this time (transient infra issue).
- Verification:
dotnet build- 0/0.dotnet publishmit identischen DLL-Bytes wie v1.7.5 (nur Versions-Strings ändern). Quad-MD5 post-release verifiziert.
v1.7.5 - Non-Admin User Support + 4:3 Aspect-Ratio Fix
Released May 2026. Issue #69-driven release closing two bugs that blocked majority-of-users access to the plugin. C# Plugin DLL has minimal surgical changes (31 authorization-policy line removals, no logic change). Tests 123/123 unchanged. Build 0/0.
- Fix #69 (Auth) - Non-admin users blocked from the plugin. Audit found 47 of 52 endpoints in
UpscalerController.cswere guarded with[Authorize(Policy = "RequiresElevation")]- Jellyfin's admin-only policy. Including all playback/upscale/queue endpoints. Normal Jellyfin users could see the model list but not load any model or trigger any upscale. v1.7.5 reclassifies 31 endpoints to[Authorize](authenticated-user OK) while keeping 16 admin-only by design: server-config (service-config,settings/import,settings/export,filter-config), destructive (models/cleanup,cache/clear), security (ssh/test), global queue control (queue/pause,queue/resume), detailed observability (metrics,cache/stats,health/detailed,models/disk-usage,fallback), and load-tests (test,benchmark). Class-level[Authorize]onUpscalerController(L33) ensures all 52 endpoints still require an authenticated session - only the elevation requirement was removed. Security note: GPU-intensive ops are now reachable by all authenticated users; existingMaxConcurrentStreams+MaxQueueSizeclamps (v1.7.2) provide global DoS-cap. Per-user quota deferred to v1.7.6. - Fix #69 (Aspect-Ratio) - 4:3 movies no longer stretched. Both real-time renderers (
Configuration/webgl-upscaler.js+Configuration/webgpu-ai-realtime.js) set canvas-overlay CSS towidth:100%; height:100%withoutobject-fit, blindly stretching 4:3 source to 16:9 player container. Addedobject-fit: containto both - canvas drawbuffer already carries the correctvideoWidth × videoHeightaspect, socontainlets the browser letterbox correctly without extra geometry code. Zero risk to 16:9 content. - Issue #45 closed as obsolete - same reporter (FrRene06) as #66, original Feb-2026 thread predating v1.7.4 WSL2 fixes.
- Verification:
dotnet build- 0/0.RequiresElevationcount went from 47 → 16 (verified via grep - exactly the 31 expected downgrades). Quad-MD5 verified post-release.
v1.7.4 - Docker-Side Fixes: FP16 Type Detection + WSL2 GPU
Released May 2026. Two real-world bug reports closed in a single release. C# Plugin DLL is bit-identical to v1.7.3.1 - this release ships docker-ai-service Python fixes + updated docker-compose recipe.
- Fix #67 - ONNX FP16/FP32 type mismatch (reported by @eparrish64 on 2026-05-19, same day). NVIDIA users hit
ONNXRuntimeError INVALID_ARGUMENT: Unexpected input data type. Actual: (tensor(float16)), expected: (tensor(float))at every model warmup. Root cause:_resolve_fp16_setting()auto-enables FP16 on any NVIDIA with Compute Capability >=7.0 (Volta+), but most catalog ONNX models (Real-ESRGAN, SwinIR, HAT, …) are FP32-exported. New helper_session_input_is_fp16(session)checks the loaded model's input dtype before the cast in_onnx_infer_tile()and_onnx_infer_multiframe_tile()- FP16 only kicks in when both global flag AND model agree. - Fix #66 - Docker / WSL2 / Intel Arc on Windows 11 (reported by @FrRene06 on 2026-05-17). Dashboard stuck on "No GPU detected (CPU-only mode)" no matter which image tag was tried. Root cause: Intel-detection only searched
/dev/dri/renderD*; WSL2 uses/dev/dxg(DirectX bridge). New WSL2 detection branch viaclinfo --list+ new_parse_clinfo_intel_name()helper; new commentedai-upscaler-wsl2section indocker-compose.ymlwith the verified Intel Arc A380 mount/devices recipe;/gpu-verifyendpoint exposes awsl2diagnostics block. - Stale issues closed: #49 (Vulkan - already supported as
docker7-vulkanimage), #64 (Select Library - implemented v1.6.1.14), #62 + #63 (v1.5.x install bugs - obsolete after repo-feed sync). Repo now has 0 open issues. - Verification:
dotnet build- 0/0.dotnet test- 123/123 unchanged from v1.7.3.1. Python syntax check onmain.pypassed. Quad-MD5 verified post-release.
v1.7.3.1 - Hotfix + Interface-Extraction + Adapter Test Coverage
Released May 2026. Audit-caught release-vs-code inconsistency: v1.7.3 release notes announced deletion of GET /Upscaler/js/{name}, but a batch-edit interrupt during release left it intact at UpscalerController.cs:261. v1.7.3.1 actually deletes it (0 callers, user-impact: zero).
- Phase D - Interface Extraction. New
IUpscalerCore(2 methods:UpscaleImageAsync+DetectHardwareAsync) as minimal-surface seam forVideoFrameProcessor. NewIUserManagerAdapter(1 method:IsAnyUserPlayed) wrapsIUserManager+IUserDataManagerwith fail-open semantics (DB exception → returns false → treat as unwatched). DI uses factory patternsp.GetRequiredService<UpscalerCore>()- single shared instance, production code unchanged. - Phase E (partial) - Test Coverage. New
UserManagerAdapterTestsregression-guard the fail-open contract:IsAnyUserPlayed_ReturnsFalse_WhenItemIsNull+IsAnyUserPlayed_ReturnsFalse_WhenUsersEnumerableThrows. If a future refactor flips the contract to fail-closed, the second test fails loudly. PlayCount/Played-flag scenarios deferred to v1.7.4 (needs Jellyfin.Data package-ref). - Polish:
docs/MODEL-HOSTING.mdannotation updated v1.6.1.18, registry size 48 → v1.7.3.1, registry size 59. - Verification:
dotnet build- 0 warnings, 0 errors.dotnet test- 123/123 passing (was 121, +2 new). Saved v1.7.x configs are bit-for-bit compatible.
v1.7.3 - meta.json-in-ZIP Verify + Dead-Code Purge + Site Sync
Released May 2026. External audit caught the v1.7.0 ZIP-version-mismatch class - meta.json said 1.6.1.23 while manifest said 1.7.0 because a Fact-Forcing-Gate interrupted the version-bump batch. Audit roadmap A+B+C closed in one mega-patch.
- NEW CI gate:
zip-version-check- unzips the build artifact, parsesmeta.jsoninside, asserts.versionmatches manifest. Adding a 5th workflow job alongsideverify-fallback-sync,audit-tryapply-lambdas,verify-site-sync. - Dead endpoint deletion:
POST /Upscaler/cache/configremoved - 0 callers (dead since v22's UI-cleanup pruned CacheManager toggles).GET /Upscaler/js/{name}was also announced as deleted but missed due to batch-edit interrupt - closed in v1.7.3.1 hotfix. - Dead class purge:
UpscalerSettingsclass removed;CPUInfo+MemoryInfokept (transitively reachable viaBenchmarkResultsproperties - audit was wrong on those two, dotnet build catches it). - Site sync:
site/models.htmlextended with 11 missing entries (Next-Gen, Film Restoration, Face Restoration sections) to match Python catalog (48 → 59). NewScripts/sync-site-topbar-versions.ps1mirrorsmeta.jsonversion into<span class="brand-version">across all 14 site HTML files. - Verification:
dotnet build- 0/0.dotnet test- 121/121.
v1.7.2 - Math.Clamp DoS-Hardening + 6 New Models + ProcessingStatus Cleanup
Released May 2026. Hardening release closing the int.MaxValue payload class.
- 18 numeric Property setters in
PluginConfigurationupgraded fromMath.Max(value, lower)toMath.Clamp(value, lower, upper)- Settings-Import or REST PUT withint.MaxValuepayload can no longer corrupt saved configs. 3 lower-bound drift fixes en passant:RealtimeCaptureWidth(240→320 min sane),HealthCheckIntervalSeconds(10s→30s min),CircuitBreakerResetSeconds(30s→60s min). - Catalog 53 → 59: +MAN-x2/x4, +CRAFT-x2/x4, +GPEN-512, +NAFNet-denoise.
Resources/models-fallback.jsonregenerated viaScripts/sync-fallback-models.ps1;verify-fallback-syncCI-job validates. - Dead-enum purge:
ProcessingStatus.Analyzingremoved - never emitted anywhere, holdover from v1.5 design. - +4 tests: new
ProcessingQueueTests(reflection-injected_persistPath) covers the debounced-Timer + SemaphoreSlim non-overlapping persist pattern from v1.7.0. Tests 117 → 121. - Verification:
dotnet build- 0/0.dotnet test- 121/121.
v1.7.1 - RealtimeModeRegistry + WebGPU AI Mode + Drift-Lock Tests
Released May 2026. Drift-prevention closure - fifth and final registry pattern, generic [Theory]-based drift-lock test covers all 5 dropdowns at once.
- NEW
RealtimeModeRegistrywith three sets:UiModes(5: auto / bilinear / lanczos / anime4k / webgpuai),BackwardsCompatAliases({webgl}),AcceptedAtImport= union of both. Old saved configs withwebglstill load and silently migrate tolanczos- no breakage. - NEW
Configuration/webgpu-ai-realtime.js(~258 LoC). Loads onnxruntime-web@1.20.1 + Real-ESRGAN compact ONNX via 4-stage defensive CDN fallback (jsdelivr primary, unpkg secondary, then Lanczos fallback). 5th option "AI WebGPU" added to RealtimeMode dropdown. Browser-side AI realtime - no Docker round-trip. - NEW
RegistryDriftLockTests- single generic[Theory]over 5 dropdowns (Codec / Quality / ButtonPosition / RealtimeMode / FilterPreset). Parses embeddedconfigurationpage.html, asserts set-equality against the matching registry HashSet. Adding a UI option without registry-update fails the build. Tests 102 → 117. - Verification:
dotnet build- 0/0.dotnet test- 117/117.
v1.7.0 - Anime4K Realtime + Frame-Loop CT Propagation + Debounced Persist
Released May 2026. Substantial release: NEW Anime4K realtime tier (MIT-licensed Anime4K.js, jsdelivr CDN with Lanczos fallback). The old "WebGL" mode is honestly rebranded to "Lanczos + Sharpen" (it was always classical, never AI).
- Frame-Loop CancellationToken propagation - closes the v20/v21 outer-loop adoption hole at
VideoFrameProcessor.cs:252. Scheduler-cancel now flows down toUpscaleImageAsync(..., cancellationToken). - Process.WaitForExitAsync + linked CTS -
ProcessingMethodExecutorL619-621 replacesTask.Run(() => proc.WaitForExit(60000), ct)with proper async pattern combining timeout + caller CT. - Debounced async PersistQueue - Timer-based
RequestPersist()+SemaphoreSlimnon-overlapping writer, 500ms quiet window. 5 sync callers migrated. No more disk-I/O waits on hot path. - Settings-Import +18 missing TryApply lambdas - filter properties (brightness/contrast/saturation/gamma/sharpness/temperature/vignette/grain/denoise/lutPath), face-restore (model/weight), library-IDs, AI-service token. Previously these silently fell back to defaults on Import.
- NEW
QualityLevelRegistry+ButtonPositionRegistry- same drift-lock pattern as v23'sCodecRegistry.UpscalerControllerTryApply lambdas reference the registries. - Verification:
dotnet build- 0/0.dotnet test- 115/115. RealtimeMode dropdown: Auto / Lanczos+Sharpen / Anime4K / Server-AI (WebGPU+ONNX path added in v1.7.1). Saved v1.6.x configs are bit-for-bit compatible.
v1.6.1.23 - OutputCodec Save-Validation Fix
Released May 2026. Hotfix for a P0 user-impact bug surfaced in the v22 deep-audit: the #OutputCodec dropdown offered 12 codec choices but the save endpoint accepted only 3 - picking AV1/NVENC/QSV silently fell back to libx264.
- Bug class: four codec allowlists drifting across
UpscalerController.cs:1437(3 entries),VideoFrameProcessor.cs:400(7),ProcessingMethodExecutor.cs:477realtime (6, no copy),ProcessingMethodExecutor.cs:803batch (12). User-impact worst case: NVIDIA RTX 40 user picksav1_nvenc, gets libx264 silently - 5-20× slower encoding. - Fix: new
Services/CodecRegistry.cswith two HashSets -OutputCodecs(all 12, used by save + reconstruct + batch) andRealtimeOutputCodecs(HW-encoders + libx264/265, used by the realtime pipe path). All 4 sites now reference one of these sets. - Drift-lock: new
CodecRegistryTests.csparses the embeddedconfigurationpage.htmlat test time, extracts every<option value="X">inside#OutputCodec, and asserts set-equality againstCodecRegistry.OutputCodecs. Adding a UI codec without bumping the registry (or vice versa) fails the build. - +17 new tests - 12 codec InlineData + 5 facts (HaveCount, case-insensitive, subset, exclusions, HTML-parse). Tests grew 85 → 102.
- Verification:
dotnet build- 0 warnings, 0 errors.dotnet test- 102/102 passing. Zero deletions: existing inline lists replaced withCodecRegistry.*references. - Methodical lesson: the v22 deep-audit identified the bug class - TryApply lambdas with non-trivial bodies can contain validation that silently discards user choices. Future audits should grep for multi-line
TryApplyblocks specifically and review their decision logic against the corresponding UI surface.
v1.6.1.22 - UI Honesty Cleanup (No-Op Toggles Removed)
Released May 2026. Follow-through on the v1.6.1.21 honest-disclosure principle: 30 dead-backend config controls removed from the settings page after a triple-pass over all 88 properties (v21's audit only enumerated 54 - the regex missed property-bodies).
- 5 entirely-dead
<details>sections removed - Quality Metrics, Face Enhancement, Film Grain Management, Health & Circuit Breaker, Model Management. - 18 individual fields removed from mixed-live sections -
PlayerButton,Notifications,AutoRetryButton,EnableProcessingQueue,EnableProgressNotifications,EnableModelPreloading,EnableModelAutoCleanup,EnableHealthMonitoring,EnableGpuFallbackToCpu,EnableComparisonView,EnableCustomModelUpload,EnableApiDocs,EnablePreProcessingCache,MaxVRAMUsage,CpuThreads,MaxUpscaledFileSizeMB,RealtimeTargetFps+ 2 dead Face-Restore sliders. - JS load/save arrays pruned in lockstep -
fields,nums,floats,checks,sliderMap,longs. 3 orphan slider event listeners removed. - Properties + Controller
TryApplykept - saved user configs continue to load without crash. Removed inputs simply don't get edited via the page anymore. Backwards-compatible. - Deliberately preserved -
ButtonPosition,EnableRealtimeUpscaling,RealtimeMode,RealtimeCaptureWidth(player-integration.js consumers - false-positive in algo's first pass),EnableFaceRestore+FaceRestoreModel(UI-direct-to-/face-restore/loadREST consumers). - Discovery methodology - pass 1: multi-line aware regex; pass 2: per-property consumer count across
Services/,ScheduledTasks/,Controllers/,Plugin.cs,Configuration/*.{js,html},docker-ai-service/app/main.py; pass 3: line-level inspection of every DEAD-CTRL-ONLY with js>=1 to distinguish real consumers from save/load array entries. - Verification:
dotnet build- 0 warnings, 0 errors.dotnet test- 85/85 passing (unchanged).configurationpage.html2807 → 2680 lines. Zero behavior change, zero new code paths.
v1.6.1.21 - Adoption v2 + Compute-Waste Fixes + Honest Dead-Config
Released May 2026. Follow-up patch closing 8 findings of the v1.6.1.20 external audit.
RestrictToUnwatchedContent+SkipUpscaledOnRescanfinally wired - both toggles existed since v1.6.1.14 with 0 consumers.LibraryUpscaleScanTasknow consults a newIsAnyUserPlayed(BaseItem)helper (DI extended withIUserManager+IUserDataManager). User compute-waste-protection finally honored.- 6 remaining HttpClient calls now use
HttpContext.RequestAborted- 16/16 coverage including hot-path/upscale-frameand/upscale-video-chunk. No more 120s server hangs when client disconnects mid-playback. - ProcessingStrategySelector substring-matcher tightened - v1.6.1.18
compactandrealplksrmatchers were too broad.anime-compact-x4(anime-category) andnomos2-realplksr-x4(video-quality DAT2-class) no longer falsely accepted for RealTime - no more frame drops mid-playback. - 4 frame-loop
File.Copy→ async streaming -VideoFrameProcessor+ProcessingMethodExecutorerror-fallback paths now useFileStream + CopyToAsyncwithuseAsync:true. NAS-mount thread-block eliminated. - FaceRestore backend allowlist symmetric to frontend - backend
FaceRestoreLoadreadscategory="face_restore"from same embedded JSON as the v1.6.1.19 frontend dropdown. New face-restore models won't get HTTP 400 from backend anymore. - Filter-preset list deduplicated 4× → 1× - new
_validFilterPresetsstatic readonly inUpscalerController. - Honest XML-doc disclosure of 6 dead-config toggles -
EnableModelPreloading,EnableHealthMonitoring,EnableModelAutoCleanup,EnableQualityMetrics,EnableFaceEnhancement,EnableGrainManagementnow flagged as "no-op pending v1.7.0 pipeline implementation". No silent UI-lying. - +13 regression tests - new
ProcessingStrategySelectorTests.cs. Tests grew 72 → 85. - Verification:
dotnet build -c Release- 0 warnings, 0 errors.dotnet test- 85/85 passing. v1.6.1.20 saved configs are bit-for-bit compatible.
v1.6.1.20 - Adoption Completion + Cancellation + Async-IO
Released May 2026. Follow-up patch closing the gaps the v1.6.1.19 post-release self-audit found. The v1.6.1.19 refactor introduced the ModelAvailability source-of-truth class but didn't adopt it everywhere. Plus 3 new bug classes (Cancellation, Sync-IO, csproj Self-Reference) that surfaced during the deep-scan.
- Adoption: HardwareBenchmarkService.cs:123 -
status.CurrentModel ?? "realesrgan-x4"was bypassingEnsureModelAvailable. Now wrapped. If the Docker service ever reports a self-host model ascurrent_model, it falls back to plugin default instead of being silently propagated. - Adoption: UpscalerCore.cs Single-Frame returns - 7 hardcoded returns now route through
PickAvailable. Today no behavior change (none of these IDs are in KnownUnavailable); regression-guard for future additions, symmetric to multi-frame paths gated since v1.6.1.17. - NEW BUG CLASS: 9× HttpContext.RequestAborted added to UpscalerController HttpClient calls (
/gpus,/models/load,/benchmark,/face-restore/{load,status,unload},/metrics,/gpu-verify,/health/detailed). Prevents 120s server-side hangs when client disconnects. - NEW BUG CLASS: CacheManager.cs:307 async streaming - synchronous
File.Copyreplaced withFileStream + CopyToAsync(useAsync:true). Was blocking thread-pool thread 5-30s on NAS-mounted disks per cached frame. - NEW BUG CLASS: csproj-Comments timeless - removed explicit
v1.6.1.19version-strings fromJellyfinUpscalerPlugin.csprojcomments. Pauschal version-bump regex would have falsely re-attributed v1.6.1.19 features to v1.6.1.20. - +7 new tests -
SingleFramePaths_AlwaysRouteThroughPickAvailable [Theory]with 7 InlineData cases. Tests grew 65 → 72 passing. - Verification:
dotnet build -c Release- 0 warnings, 0 errors.dotnet test- 72/72 passing. No model changes, no schema changes - v1.6.1.19 saved configs are bit-for-bit compatible.
v1.6.1.19 - Single-Source-of-Truth for Model Availability
Released May 2026. Structural fix for the drift class that v1.6.1.17 and v1.6.1.18 patched point-by-point. Three audit-driven cleanups, plus a refactor that collapses 3+ duplicate hardcoded model-availability lists into one source-of-truth.
- New
ModelAvailabilitystatic class - extracted theKnownUnavailableHashSet (5 self-host model IDs) andPickAvailable()picker out ofUpscalerCoreintoServices/ModelAvailability.cs.UpscalerCorenow wraps with logging,HardwareBenchmarkServiceconsults the same source via a newEnsureModelAvailable()helper. Closes the sibling-bug class the v1.6.1.18 audit identified. - HardwareBenchmarkService hardened - the 7 hardcoded
RecommendedModel/FallbackModelassignments inCalculateOptimalSettings+CreateDefaultHardwareProfilenow route throughEnsureModelAvailable. Today this is a regression-guard (bothrealesrgan-x4andfsrcnn-x2are always-available); if either is ever flipped to self-host, the helper warns + falls back instead of recommending an unreachable model. - Face-Restore dropdown auto-populated - was hardcoded HTML
<option>s withgfpgan-v1.4/codeformer. NowloadModels()populates#FaceRestoreModelfromcategory=face_restoreon Settings page open (preserves saved value, falls back gracefully if the registry has 0 face-restore entries). - site/index.html homepage card content fix - the v1.6.1.18 card on the homepage incorrectly showed the v1.6.1.16 FFmpeg-fix description because the v17/v18 version-bump scripts
s/1.6.1.16/1.6.1.18/gbumped the title without rewriting the body text. Card now shows the actual v1.6.1.19 release content (and the version-bump pattern is documented as a known issue to be replaced by an autogen script). - +28 new tests -
JellyfinUpscalerPlugin.Tests/Services/ModelAvailabilityTests.cscovers contract assertions, case-insensitivity, fallback-chain semantics, and an explicitHaveCount(5)drift-lock that forces review on any HashSet edit. Tests grew 37 → 65 passing. - Verification:
dotnet build -c Release- 0 warnings, 0 errors.dotnet test- 65/65 passing. No new models, no schema changes - v1.6.1.18 saved configs are bit-for-bit compatible.
v1.6.1.18 - Live-Action Resolver + RealTime-AI Whitelist
Released May 2026. Follow-up patch fixing 3 sibling bugs an external audit caught after v1.6.1.17 shipped. The v1.6.1.17 review fixed the anime-side of these bugs but missed the symmetric live-action twin and the compact-family RealTime-AI rejection. No new models, no schema changes - surgical patch.
- PreferredLiveActionModel was Dead-Config - exact symmetric twin of the v1.6.1.17 anime fix. Field defined, UI dropdown rendered + persisted, but
ResolveModelForVideo()never read it. Symmetric hook added: setting "Preferred Live-Action Model" to e.g.drct-l-x4in Settings now actually does what the UI says it does. Fallback chain:override → ultrasharp-v2-x4 → nomos2-realplksr-x4 → realesrgan-x4. - RealTime-AI rejected v1.6.1.17's "Speed Champion" -
ProcessingStrategySelector.IsRealTimeAIFeasible()had a hardcoded 9-entry HashSet that drifted from the 14-entry registry.bhi-realplksr-x4,nomosuni-compact-x2,lsdir-compact-x4,swinir-small-x2/x4were all silently rejected. HashSet expanded to 14 + substring safety-net (compact,realplksr). - docs/MODEL-HOSTING.md was 5 releases out of date - still referenced "v1.6.1.12 catalog". Now points to v1.6.1.17's
drct-l-x4as a HAT alternative andreal-cugan-x4as APISR alternative for users who don't want to self-host. - Drift-protection: +1 new
[Theory]inUpscalerCoreAutoModelTestslocks down the live-action path. Future contributor who flipsrealbasicvsr-x4available without updating_knownUnavailablegets a red CI build. - Verification:
dotnet build -c Release- 0 warnings, 0 errors.dotnet test- 37/37 passing (was 33). v1.6.1.17 saved configs are bit-for-bit compatible.
v1.6.1.17 - Auto-Mode Drift Fix + 5 New SOTA Models
Released May 2026. Fixes a critical Auto-Mode bug, eliminates 4 cases of model-catalog drift, and adds 5 new SOTA upscaler models. Catalog grew 43 → 48 models.
- Auto-Mode multi-frame VSR was silently broken:
ResolveModelForVideo()returnedanimesr-v2-x4/realbasicvsr-x4/edvr-m-x4unconditionally for multi-frame batch jobs - but all three areavailable: Falseupstream (no public ONNX mirror). NewPickAvailable()helper consults a_knownUnavailableHashSet and walks fallback chains. Anime+multi-frame →realesrgan-animevideo-x4; very-low-res →ultrasharp-v2-x4; general →ultrasharp-v2-x4→nomos2-realplksr-x4→realesrgan-x4. - PreferredAnimeModel was Dead-Config: default was
"", and the resolver never read the field. Fixed in two parts: default →anime-compact-x4, plus the resolver now actually readsConfig.PreferredAnimeModeland routes throughPickAvailable. - 4 catalog drifts cleaned up: Controller fallback list 12 → 48 models via embedded
Resources/models-fallback.json;site/models.htmlauto-generated from registry (removed 8 fictional models likewaifu2x-cunet-x2,hat-l-x4,swinir-l-x4);Services/ModelManager.csremoved (200 LoC dead code, header still claimed v1.5.5.4); Docker service VERSION bumped 1.6.1.15 → 1.6.1.17 (was missed in v1.6.1.16). - 5 new SOTA models:
real-cugan-x2/real-cugan-x4(Bilibili anime, cleaner linework than Real-ESRGAN-anime),drct-l-x4(Phips/aaronespasa, sharper than DAT2 on photo content),bhi-realplksr-x4(Phhofm, 2× throughput vs DAT2),rife-v4.25(yuvraj108c, current SOTA frame interpolation). - UI polish: Upscale-Model dropdown filters out
category=interpolation(RIFE) andcategory=face_restore(GFPGAN/CodeFormer) - these have separate endpoints.PreferredAnimeModel+PreferredLiveActionModelare now proper dropdowns (was free-text, prone to typos). - Drift-protection: 11 new unit tests in
UpscalerCoreAutoModelTestslock down all multi-frame fallback chains. Future contributors who fliprealbasicvsr-x4toavailable: Truewithout updating_knownUnavailableget a red CI build instead of a silent regression. NewScripts/sync-fallback-models.ps1regenerates the JSON resource fromapp/main.py. - Verification:
dotnet build -c Release- 0 warnings, 0 errors.dotnet test- 33/33 passing (was 22). DLL size dropped 1.60 MB → 1.41 MB.
v1.6.1.16 - Three singletons, not one
Released April 2026. Issue #64 fix: LibraryUpscaleScanTask failing with Cannot start process because a file name has not been provided.
- Root cause: three service singletons (
VideoAnalyzer,VideoFrameProcessor,ProcessingMethodExecutor) each capturedMediaEncoder.EncoderPath/ProbePathasreadonlystrings at construction. When Jellyfin constructed the plugin beforeMediaEncoderfinished resolving paths, those strings were empty - forever. - Fix: made the cached paths mutable, added
UpdateFFmpegPath()/UpdateFFprobePath()entry points, and introducedEnsureFFmpegReady()inVideoProcessorthat re-queriesMediaEncoderand propagates to every sub-service on every job entry. - Verification: Pre-fix: nightly scan failed at 0/70 files. Post-fix (live-tested on Jellyfin 10.11.8): scan reached 31% with per-file
Video analysis: 1280x720 @ 30.0fpslog lines andFFmpeg ready: ffmpeg=/usr/lib/jellyfin-ffmpeg/ffmpeg.
v1.6.1.14 - Admin gates for jobs endpoint
- Security fix:
/Upscaler/jobsno longer returns absolute file paths to non-admin authenticated users. Gated withRequiresElevation. - Improved Test Connection diagnostics - now reports whether the failure was network-level, auth-level, or token-mismatch.
v1.6.1.12 - RIFE v4.7/v4.8/v4.9
- New RIFE frame-interpolation catalog: v4.9 (quality), v4.8 (balanced), v4.7 (fast).
- Old references to
rife-v4.6andrife-v4.6-litein saved configs are auto-mapped viaMODEL_ALIASES; no user action needed. - Scene cut detection toggle on the Motion tab - avoids ghosting across hard cuts.
v1.6.1.10 - HAT family
- Added
hat-s-x4,hat-m-x4,hat-l-x4to the catalog for live-action at higher quality than Real-ESRGAN. - Nomos8k-trained HAT variant (
nomos8k-hat-x4) as [self-host required].
v1.6.1.8 - Face restoration pipeline
- GFPGAN v1.4 and CodeFormer added as first-class models.
- Full end-to-end pipeline
/face-restore/pipeline- detects faces, restores them, upscales the surrounding frame, feathered paste-back. - Toggle on the player quick-menu (Face Restore tab) for opt-in per-stream use.
v1.6.1.5 - Filter presets + live preview
- Six filter sliders (gamma, sharpness, temperature, vignette, grain, denoise) applied live via
<video>.style.filter. - Filter preview endpoint
/Upscaler/filter-preview/frame/{itemId}- extracts a real frame from your library and renders before/after PNGs for the selected preset. - Seven shipped presets: Cinema, Anime, Retro, Vivid, HDR-SDR, Soft, Documentary.
v1.6.1.4 - Service auth rework
- All service endpoints behind a single
X-Api-Token. Previously,/logs-streamwas unauthenticated when the token was unset. - Dashboard shows
api_token_configuredandauth_enabledprominently. - Console tab in the plugin UI streams service logs via SSE, token-gated.
v1.6.1.0 - Split into plugin + service
The architectural rewrite that the current generation is based on.
- Plugin-side: .NET 9, Jellyfin 10.11.x-targeted, HTTP-only contract with the service.
- Service-side: FastAPI + ONNX Runtime in its own Docker container. CUDA / OpenVINO / ROCm / CPU images.
- Twelve output codec presets with tuned ffmpeg parameters.
- Three scheduled tasks: library upscale, image upscale, cache cleanup.
- This is the baseline that all 1.6.1.x bugfix releases build on.
Older releases
Pre-1.6.x releases bundled inference inside the plugin process. They're archived on the GitHub Releases page but are no longer maintained. Upgrade to the current 1.6.1.x line.
Version policy
| Segment | Bumps when |
|---|---|
1.x major | Jellyfin API target changes, or the plugin/service contract changes incompatibly. |
6.x minor | Plugin/service split generation. 1.6 = the current HTTP-split architecture. |
1.x feature | New features, new models, new UI tabs. |
16 patch | Bugfix only, no feature work, no config migrations. |