Skip to content

feat: migrate to .NET 8 - #28

Draft
greenlynxe wants to merge 11 commits into
mainfrom
feat/net8
Draft

feat: migrate to .NET 8#28
greenlynxe wants to merge 11 commits into
mainfrom
feat/net8

Conversation

@greenlynxe

@greenlynxe greenlynxe commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Migrates the backend from .NET 6 (EOL since November 2024) to .NET 8, using Radarr develop as the reference for target package versions.

  • Target net8.0 / net8.0-windows in all 25 projects
  • Microsoft./System. packages aligned on 8.x; MailKit 4.8 -> 4.16 (known advisory); coverlet.collector 6.0.2 from nuget.org
  • net8 breaking-change fixes: AuthenticationHandler constructors without ISystemClock, obsolete exception serialization constructors removed (SYSLIB0051), response headers set via indexer (ASP0019)
  • SDK pins 8.0.423 (mise, CI, azure-pipelines), net8.0 output paths everywhere, packages.lock.json regenerated

Also unblocks the NuGet dependency updates that were failing on net6 (MailKit chain requires System.Text.Encoding.CodePages >= 8.0).

Local validation: full solution builds with 0 warnings; unit tests green on 7/8 assemblies, 5 Core.Test failures under investigation (possibly Windows-local).

- Target net8.0 (and net8.0-windows) in all 25 projects
- Align Microsoft.*/System.* packages on 8.x (Radarr develop as
  reference); MailKit 4.8 -> 4.16 (known advisory, NuGet audit fails the
  build otherwise); coverlet.collector nightly preview -> 6.0.2 from
  nuget.org (nightly feed only carries 3.x)
- Fix net8 breaking changes: AuthenticationHandler constructors drop the
  obsolete ISystemClock (ASP.NET 8), remove obsolete exception
  serialization constructors (SYSLIB0051), set response headers via the
  indexer instead of IDictionary.Add (ASP0019)
- Update SDK pins to 8.0.423 (mise, CI, azure-pipelines) and net8.0
  output paths (build/test/docs scripts, Dockerfiles, launch.json)
- Regenerate packages.lock.json for the net8 dependency graphs
Since .NET 7 a RuntimeIdentifier no longer implies SelfContained; the
published binary was framework-dependent and crash-looped in the runtime
image (no dotnet installed). Pass -p:SelfContained=True like Radarr.
Builds deploy/Dockerfile and deploy/rreading-glasses on pushes to main
and feat/net8 (branch + sha tags, latest on main) so the GitOps homelab
can consume prebuilt images.
Since ASP.NET Core 7 the binding-source inference tied to custom
attributes implementing IApiBehaviorMetadata no longer applies, so every
JSON request body bound to an empty resource (saves silently failed
validation with default values). Mirror Radarr's net8 approach: explicit
[FromBody] on all 33 body-taking actions.
The instance name is a free display name in lectarr; the inherited rule
made the host config unsavable (and the error attached to a field not
visible in the initial authentication modal).
The Language fields (indexer Default Release Language, Language custom
format condition) use LanguageFieldConverter as SelectOptions, but
SchemaBuilder only handled enums and threw NotSupportedException -
breaking GET /api/v1/indexer/schema (Prowlarr sync) and the custom
format schema. Port Radarr's ISelectOptionsConverter branch and make the
converter implement it.
* feat(convert): convert imported ebooks to a preferred format

Settings > Media Management > Book Conversion: pick a preferred format
(epub/mobi/azw3/pdf). On import, ebooks in another format are converted
with calibre's ebook-convert, embedding clean metadata (edition title,
author, ISBN, language) into the output file. The converted file is
registered on the same edition; the original is kept, or recycled when
'Delete Original After Conversion' is enabled.

The converter binary is provided externally (e.g. the linuxserver
universal-calibre docker mod); a health check warns when conversion is
enabled without it.

Closes #30

* feat(convert): daily scheduled conversion sweep

Adds a 'Convert Book Files' scheduled task (24h, also manually
triggerable from System > Tasks) that runs the same conversion logic
over the whole library - catching pre-existing files, past imports and
previously failed conversions. No-ops quickly when no preferred format
is configured or the converter is missing.
The universal-calibre docker mod (used for format conversion) silently
no-ops on musl/alpine - it requires a glibc image. Publish linux-x64
instead of linux-musl-x64 and run on linuxserver's ubuntu base.
ebook-convert crashed with 'cannot import QColor from qt.core' during
image handling - the universal-calibre mod's Qt needs libEGL/libGL,
fontconfig and xkbcommon at runtime. Verified with a real mobi->epub
conversion in the cluster.
Implements #31: open imported epubs, sample prose from the middle of
the spine and detect the actual language - Unicode script ranges first
(ru/el/ja/ko/zh/he/th), then distinctive stop-word scoring for 16
Latin-script languages with a confidence score. The OPF dc:language is
read for logging but the content wins.

A new import specification compares the detected language with the
quality profile's required language: 'Log Only' records a warning,
'Reject on Mismatch' refuses the import (confidence >= 70% only).
Setting lives in Media Management, default Disabled.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant