Fix three regressions the video-kind split introduced

All three were found by running the thing rather than reading it, and the
first one is serious.

1. probeable() compared the LIBRARY kind against a hardcoded list. Splitting
   video into movies/tv/adult/hentai left every new kind out of that list, so
   a movies or tv library was never probed and stored no codec facts at all.
   With no facts, resolve cannot tell an unplayable file from a playable one:
   an HEVC file reported "playable via html5" for a browser that cannot decode
   HEVC, and transcoding would never have triggered for anything.

   It now tests the kind the rows carry, through library.ItemKindFor, so every
   video library is probed exactly as the original video kind was and a future
   video kind cannot repeat this.

2. jellyfin CollectionType() had no case for the new kinds, so a Jellyfin
   client saw movies, tv, adult and hentai libraries with no collection type.

3. kindNoun() fell through to its default for the new kinds, which reads "tv"
   in a sentence rather than "shows".

Also hardened the empty-kind fallback in upsertItem to resolve through
ItemKindFor, so it cannot store a library's own name where 'video' belongs.

Verified end-to-end: codec facts are recorded again (v=h264 and v=hevc), an
h264 file resolves to engine html5, and the HEVC file resolves to engine
transcode. That last line is the whole feature working: scan records the
facts, resolve sees the browser cannot decode it, and the server offers to
re-encode it instead of saying the file is unplayable.
This commit is contained in:
mithral 2026-10-12 12:10:01 -04:00
parent 5281a6690d
commit 7ed74825e7
3 changed files with 21 additions and 5 deletions

View file

@ -385,6 +385,10 @@ func kindNoun(kind string) string {
return "photos" return "photos"
case "games": case "games":
return "games" return "games"
case "movies", "adult", "hentai", "video":
return "films"
case "tv":
return "shows"
default: default:
return strings.ReplaceAll(kind, "-", " ") return strings.ReplaceAll(kind, "-", " ")
} }

View file

@ -257,8 +257,10 @@ func CollectionType(kind string) string {
switch kind { switch kind {
case "series": case "series":
return "tvshows" return "tvshows"
case "video": case "video", "movies", "adult", "hentai":
return "movies" return "movies"
case "tv":
return "tvshows"
case "audiobooks", "music": case "audiobooks", "music":
return "music" return "music"
case "photos": case "photos":

View file

@ -742,7 +742,10 @@ func upsertGroup(ctx context.Context, tx *sql.Tx, lib library.Library, g group,
func upsertItem(ctx context.Context, tx *sql.Tx, lib library.Library, g group, parentID int64) (int64, error) { func upsertItem(ctx context.Context, tx *sql.Tx, lib library.Library, g group, parentID int64) (int64, error) {
kind := g.kind kind := g.kind
if kind == "" { if kind == "" {
kind = lib.Kind // The group always carries a kind; this is the belt-and-braces path. It
// resolves through ItemKindFor so a video library stores 'video' rather
// than its own name, which is what every query for playable video asks.
kind = library.ItemKindFor(lib.Kind)
} }
var season, episode any var season, episode any
if g.season > 0 { if g.season > 0 {
@ -971,9 +974,16 @@ func probeBatch(ctx context.Context, lib library.Library, groups map[string]grou
// probeable reports whether a library kind holds files worth probing for codec // probeable reports whether a library kind holds files worth probing for codec
// facts. Only video and the audio kinds have media streams; ebooks, comics, // facts. Only video and the audio kinds have media streams; ebooks, comics,
// photos, and games are never probed. // photos and games are never probed.
func probeable(kind string) bool { //
switch kind { // The test is on the kind its ROWS carry, not on the library's own kind. Every
// video library stores 'video' (library.MediaType.ItemKind), so a movies, tv,
// adult or hentai library is probed exactly like the original video kind was.
// Comparing the library kind against a list was how splitting the video kinds
// silently stopped probing them, and with no codec facts resolve cannot tell an
// unplayable file from a playable one.
func probeable(libKind string) bool {
switch library.ItemKindFor(libKind) {
case "video", "audiobooks", "music": case "video", "audiobooks", "music":
return true return true
default: default: