Files
silo-server/internal/naming/group_identity_test.go
0d0d7bab1e fix(naming): let trailing bare IMDb ids anchor group identity (#113)
* fix(naming): let trailing bare IMDb ids anchor group identity

hasStructuredIDAnchor only consulted ParseStructuredFolderIDs, so folders
tagged with an unbracketed trailing id ("Eggs Run (2021) tt8049994") still
went ambiguous on title conflicts. ParseFolderIDs now returns only explicit
evidence (structured tags plus unambiguous tt-prefixed ids), so use it for
the anchor check. Covers the last 3 ambiguous-with-IDs groups on dev.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(naming): persist file-stem trailing IMDb ids into group identity

InferGroupIdentity anchored on file-level trailing bare IMDb ids via
hasStructuredIDAnchor but extracted file-stem IDs with
ParseStructuredFolderIDs, so the id that justified resolving a title
conflict never reached GroupIdentity/ScannedMediaGroup and downstream
matching saw a resolved group without it. Use ParseFolderIDs for the
file-stem extraction to mirror the anchor check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-09 17:12:05 -04:00

130 lines
4.3 KiB
Go

package naming
import "testing"
// A renamed release inside a provider-tagged folder must stay resolved: the
// structured IDs anchor the identity even though folder and file titles are
// unrelated (Radarr keeps the folder name from grab time while the release
// inside carries the retitled name).
func TestInferGroupIdentity_StructuredIDsResolveMovieTitleConflict(t *testing.T) {
group := InferGroupIdentity(
"/movies/20s/On Fire {imdb-tt28078628} {tmdb-1196791}/Soul on Fire (2025) [WEBDL-1080p 8-bit h264 EAC3 5.1]-FLUX.mkv",
"movies",
RootAssignment{
RootPath: "/movies/20s/On Fire {imdb-tt28078628} {tmdb-1196791}",
InferredType: "movie",
},
)
if got, want := group.State, "resolved"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
if got, want := group.BaseTitle, "On Fire"; got != want {
t.Fatalf("BaseTitle = %q, want %q", got, want)
}
if got, want := group.TmdbID, "1196791"; got != want {
t.Fatalf("TmdbID = %q, want %q", got, want)
}
if got, want := group.ImdbID, "tt28078628"; got != want {
t.Fatalf("ImdbID = %q, want %q", got, want)
}
}
// An unbracketed trailing IMDb id anchors identity the same way a structured
// tag does — the tt prefix is unambiguous. Mirrors the dev-library case
// "Eggs Run (2021) tt8049994" whose file carries a different release title.
func TestInferGroupIdentity_TrailingImdbIDResolvesMovieTitleConflict(t *testing.T) {
group := InferGroupIdentity(
"/movies-int/es/Eggs Run (2021) tt8049994/Huevitos Congelados (2022) [WEBDL-1080p]-GRP.mkv",
"movies",
RootAssignment{
RootPath: "/movies-int/es/Eggs Run (2021) tt8049994",
InferredType: "movie",
},
)
if got, want := group.State, "resolved"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
if got, want := group.ImdbID, "tt8049994"; got != want {
t.Fatalf("ImdbID = %q, want %q", got, want)
}
}
// A trailing IMDb id on the file stem (folder carries none) must both anchor
// the identity and be persisted into the group, so downstream matching sees
// the provider ID that justified the resolution.
func TestInferGroupIdentity_FileLevelTrailingImdbIDAnchorsAndPersists(t *testing.T) {
group := InferGroupIdentity(
"/movies/On Fire (2024)/Soul on Fire tt28078628.mkv",
"movies",
RootAssignment{
RootPath: "/movies/On Fire (2024)",
InferredType: "movie",
},
)
if got, want := group.State, "resolved"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
if got, want := group.ImdbID, "tt28078628"; got != want {
t.Fatalf("ImdbID = %q, want %q", got, want)
}
}
// Without provider IDs the same folder/file title conflict must still be
// flagged ambiguous — there is nothing to anchor the identity.
func TestInferGroupIdentity_TitleConflictWithoutIDsStaysAmbiguous(t *testing.T) {
group := InferGroupIdentity(
"/movies/20s/On Fire (2024)/Soul on Fire (2025) [WEBDL-1080p 8-bit h264 EAC3 5.1]-FLUX.mkv",
"movies",
RootAssignment{
RootPath: "/movies/20s/On Fire (2024)",
InferredType: "movie",
},
)
if got, want := group.State, "ambiguous"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
}
func TestInferGroupIdentity_StructuredIDsResolveSeriesTitleConflict(t *testing.T) {
group := InferGroupIdentity(
"/tv/Border Control - Sweden (2023) {tvdb-442777}/Season 01/Gränsbevakarna Sverige S01E01.mkv",
"series",
RootAssignment{
RootPath: "/tv/Border Control - Sweden (2023) {tvdb-442777}",
InferredType: "series",
Title: "Gränsbevakarna Sverige",
HasSeasonStructure: true,
HasEpisodePattern: true,
},
)
if got, want := group.State, "resolved"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
if got, want := group.TvdbID, "442777"; got != want {
t.Fatalf("TvdbID = %q, want %q", got, want)
}
}
func TestInferGroupIdentity_SeriesTitleConflictWithoutIDsStaysAmbiguous(t *testing.T) {
group := InferGroupIdentity(
"/tv/Border Control - Sweden (2023)/Season 01/Gränsbevakarna Sverige S01E01.mkv",
"series",
RootAssignment{
RootPath: "/tv/Border Control - Sweden (2023)",
InferredType: "series",
Title: "Gränsbevakarna Sverige",
HasSeasonStructure: true,
HasEpisodePattern: true,
},
)
if got, want := group.State, "ambiguous"; got != want {
t.Fatalf("State = %q, want %q", got, want)
}
}