#!/usr/bin/env bats # Seam: scripts/media-tvdupes.py — the episode-level duplicate census for the TV # library. # # The failure this seam exists to prevent is the one that almost cost real # content: two folders of one show look like copies, and a folder-level "keep # the bigger folder" deletes the half of the series only the smaller folder # holds (the 2026-11-02 census found 10 such complementary pairs). So every # assertion here is about WHICH files land in the plan and WHICH the tool # refuses to touch — never about its internals. Everything runs on a synthetic # library in the test's own tmpdir: no media server, no network, no array. load helpers TOOL="$REPO_ROOT/scripts/media-tvdupes.py" # at PATH SIZE — a file of deterministic bytes. at() { mkdir -p "$(dirname "$1")"; head -c "$2" /dev/zero > "$1"; } # sources FILE — the sources the plan moves, one per line. sources() { awk -F'\t' '$1=="move"{print $2}' "$1"; } # destinations FILE — where the plan puts them. destinations() { awk -F'\t' '$1=="move"{print $3}' "$1"; } # plan_moves FILE — how many files the plan stages. plan_moves() { [ -f "$1" ] || { echo 0; return; } awk -F'\t' '$1=="move"' "$1" | wc -l } setup() { LIB="$BATS_TEST_TMPDIR/TVShows" HOLD="$BATS_TEST_TMPDIR/.AGENTTRASH/20991231-tv-duplicates" PLAN="$BATS_TEST_TMPDIR/plan.tsv" mkdir -p "$LIB" "$HOLD" } @test "the smaller copy of an episode is staged and the larger stays put" { at "$LIB/Doc Who (2005) [tvdbid-78804]/Season 01/Doc Who - S01E01 - Pilot.mkv" 4000 at "$LIB/Doc Who (2005) [tvdbid-78804]/Season 01/backup/Doc.Who.S01E01.720p.mkv" 1200 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 1 ] run sources "$PLAN" [[ "$output" == *"backup/Doc.Who.S01E01.720p.mkv"* ]] [[ "$output" != *"Pilot.mkv"* ]] run destinations "$PLAN" [[ "$output" == "$HOLD/"* ]] } @test "an equal-size pair stages exactly one copy" { at "$LIB/Equal (2001) [tvdbid-11]/Season 01/Equal - S01E01.mkv" 2500 at "$LIB/Equal (2001) [tvdbid-11]/Rip/Equal - S01E01.mkv" 2500 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 1 ] } @test "a file holding one episode nothing else has is never staged" { # The shape that defeats a folder-level verdict: Season 02 exists only here, # so the folder that looks like a leftover is the only copy of an episode. at "$LIB/King (2010) [tvdbid-21]/Season 01/King - S01E01 - One.mkv" 3000 at "$LIB/King (2010) [tvdbid-21]/Season 01/backup/King - S01E01 - One.mkv" 900 at "$LIB/King (2010) [tvdbid-21]/Season 02/King - S02E01 - Two.mkv" 800 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 0 ] run sources "$PLAN" [[ "$output" != *"S02E01"* ]] [[ "$output" == *"backup/King - S01E01 - One.mkv"* ]] } @test "a two-in-one pack competes for every episode in its range" { at "$LIB/Range (2012) [tvdbid-31]/Season 01/Range - S01E01.mkv" 1500 at "$LIB/Range (2012) [tvdbid-31]/Season 01/Range - S01E02.mkv" 1500 at "$LIB/Range (2012) [tvdbid-31]/Packs/Range - S01E01-02.mkv" 2400 # The pack is the biggest carrier of BOTH episodes, so the two rips go. run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$(plan_moves "$PLAN")" -eq 2 ] run sources "$PLAN" [[ "$output" == *"Season 01/Range - S01E01.mkv"* ]] [[ "$output" != *"Packs/Range - S01E01-02.mkv"* ]] # Make the season file the bigger carrier of E02 and the pack becomes the # only carrier of E01: it stays, however small it is. rm "$LIB/Range (2012) [tvdbid-31]/Season 01/Range - S01E01.mkv" rm "$LIB/Range (2012) [tvdbid-31]/Season 01/Range - S01E02.mkv" at "$LIB/Range (2012) [tvdbid-31]/Season 01/Range - S01E02.mkv" 9000 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$(plan_moves "$PLAN")" -eq 0 ] } @test "two tvdb ids on the same words are never merged" { at "$LIB/Avatar The Last Airbender (2024) [tvdbid-385925]/Season 01/Avatar - S01E01.mkv" 9000 at "$LIB/Avatar The Last Airbender (1999) [tvdbid-74852]/Season 01/Avatar - S01E01.mkv" 500 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 0 ] [[ "$output" == *CONFLICT* ]] [[ "$output" == *"tvdb [74852] vs [385925]"* ]] } @test "a derived id that contradicts the folder's own tag never merges them" { # Measured 2026-11-02: Jellyfin's provider table carried a 2026 special's tvdb # id on the folder tagged [tvdbid-73838]. Unioning the two makes one show of a # 2000 series and a 2026 special, and the special's bigger files dominate the # original's pilot. The tag is the operator's word; the nfo and `--ids` layers # fill an untagged folder and never overrule a tagged one. at "$LIB/Middle (2000) [tvdbid-73838]/Season 01/Middle - S01E01 - Pilot.mkv" 800 at "$LIB/Middle (2026) [tvdbid-457779]/Season 01/Middle - S01E01 - Episode 1.mkv" 1100 IDS="$BATS_TEST_TMPDIR/ids.tsv" printf '%s\t%s\n' "Middle (2000) [tvdbid-73838]" 457779 > "$IDS" run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" --ids "$IDS" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 0 ] [[ "$output" == *"DISAGREE"* ]] [[ "$output" == *"tag tvdb [73838]"* ]] [[ "$output" == *"derived tvdb [457779]"* ]] } @test "an untagged drop is identified by the tvshow.nfo in the metadata view" { at "$LIB/Clone Wars/Season 01/Clone Wars - S01E01.mkv" 1200 at "$LIB/Clone Wars (2008) [tvdbid-84859]/Season 01/Clone Wars - S01E01.mkv" 4000 VIEW="$BATS_TEST_TMPDIR/view" mkdir -p "$VIEW/Clone Wars" printf '%s\n' 'Clone Wars' \ '84859' \ > "$VIEW/Clone Wars/tvshow.nfo" run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" --meta "$VIEW" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 1 ] run sources "$PLAN" [[ "$output" == *"Clone Wars/Season 01/Clone Wars - S01E01.mkv"* ]] # Without the nfo layer nothing identifies the drop, so nothing moves. run python3 "$TOOL" --library "$LIB" --hold "$HOLD" \ --out "$BATS_TEST_TMPDIR/no-meta.tsv" [ "$status" -eq 0 ] [[ "$output" == *UNRESOLVED* ]] [ "$(plan_moves "$BATS_TEST_TMPDIR/no-meta.tsv")" -eq 0 ] } @test "a file named by an id is keyed only when the witness names it" { BIG="$LIB/Edd (1999) [tvdbid-75897]/Season 01/Edd - S01E01 - Down the Line.mkv" SMALL="$LIB/Edd (1999) [tvdbid-75897]/Season 01/104348.mkv" at "$BIG" 2100 at "$SMALL" 700 WIT="$BATS_TEST_TMPDIR/witness.tsv" printf '%s\t1\t1\n' "$SMALL" > "$WIT" run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$(plan_moves "$PLAN")" -eq 0 ] [[ "$output" == *"unkeyed, never staged: 1 files"* ]] run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" --witness "$WIT" [ "$(plan_moves "$PLAN")" -eq 1 ] run sources "$PLAN" [[ "$output" == *104348.mkv* ]] } @test "the sidecars of a staged episode are staged with it" { at "$LIB/Side (2003) [tvdbid-41]/Season 01/Side - S01E01 - First.mkv" 3000 at "$LIB/Side (2003) [tvdbid-41]/Rip/Side - S01E01 - First.mkv" 1000 at "$LIB/Side (2003) [tvdbid-41]/Rip/Side - S01E01 - First.srt" 400 at "$LIB/Side (2003) [tvdbid-41]/Season 01/Side - S01E01 - First.srt" 450 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$(plan_moves "$PLAN")" -eq 2 ] run sources "$PLAN" [[ "$output" == *"Rip/Side - S01E01 - First.srt"* ]] [[ "$output" != *"Season 01/Side - S01E01 - First.srt"* ]] } @test "a hold inside the library is refused" { at "$LIB/Hostage (2007) [tvdbid-51]/Season 01/Hostage - S01E01.mkv" 100 run python3 "$TOOL" --library "$LIB" --hold "$LIB/.AGENTTRASH/hold" \ --out "$PLAN" [ "$status" -ne 0 ] [[ "$output" == *"--hold"* ]] } @test "a plan whose hold target is occupied is refused, plan and all" { at "$LIB/Gone (2009) [tvdbid-61]/Season 01/Gone - S01E01.mkv" 1000 at "$LIB/Gone (2009) [tvdbid-61]/Rip/Gone - S01E01.mkv" 400 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$(plan_moves "$PLAN")" -eq 1 ] # The hold already holds one of the destinations: the executor would refuse # it, so a plan that cannot run must not be handed over at all. mkdir -p "$HOLD/Gone (2009) [tvdbid-61]/Rip" at "$HOLD/Gone (2009) [tvdbid-61]/Rip/Gone - S01E01.mkv" 400 rm "$PLAN" run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 1 ] [[ "$output" == *"hold target occupied"* ]] [ ! -e "$PLAN" ] } @test "a library with nothing duplicated writes an empty plan" { at "$LIB/Unique (2015) [tvdbid-71]/Season 01/Unique - S01E01.mkv" 1000 at "$LIB/Other Show (2016) [tvdbid-72]/Season 01/Other Show - S01E01.mkv" 1000 run python3 "$TOOL" --library "$LIB" --hold "$HOLD" --out "$PLAN" [ "$status" -eq 0 ] [ "$(plan_moves "$PLAN")" -eq 0 ] [[ "$output" == *"plan: 0 moves"* ]] }