chore: snapshot current project updates

This commit is contained in:
windyboy
2026-02-13 13:36:39 +08:00
parent 5931f16a71
commit 0be802eac5
74 changed files with 594899 additions and 66082 deletions
+237
View File
@@ -117,6 +117,102 @@ def test_generate_plan_for_series_with_season_and_episode(config):
assert not operation.has_conflict
def test_generate_plan_blocks_series_with_high_season(config):
"""Series season above threshold should be no-op for manual review."""
video_file = VideoFile(
path=Path("/mnt/nas/videos/series/Show.Name.S20E01.mkv"),
filename="Show.Name.S20E01.mkv",
size_bytes=500000,
modified_timestamp=datetime.now(),
category="series"
)
identity = SeriesIdentity(
title="Show Name",
season=20,
episodes=[1],
confidence=0.9,
needs_review=False,
original_filename="Show.Name.S20E01.mkv"
)
plan = generate_plan([(video_file, identity)], config)
operation = plan.operations[0]
assert operation.operation_type == "no-op"
assert "season exceeds configured threshold" in operation.reason
def test_generate_plan_blocks_series_with_high_episode(config):
"""Series episode above threshold should be no-op for manual review."""
video_file = VideoFile(
path=Path("/mnt/nas/videos/series/Show.Name.S01E120.mkv"),
filename="Show.Name.S01E120.mkv",
size_bytes=500000,
modified_timestamp=datetime.now(),
category="series"
)
identity = SeriesIdentity(
title="Show Name",
season=1,
episodes=[120],
confidence=0.9,
needs_review=False,
original_filename="Show.Name.S01E120.mkv"
)
plan = generate_plan([(video_file, identity)], config)
operation = plan.operations[0]
assert operation.operation_type == "no-op"
assert "episode exceeds configured threshold" in operation.reason
def test_generate_plan_sample_is_noop_by_default(config):
"""Sample files should be excluded from organize actions by default."""
video_file = VideoFile(
path=Path("/mnt/nas/videos/series/Show.Name.Sample.S01E01.mkv"),
filename="Show.Name.Sample.S01E01.mkv",
size_bytes=500000,
modified_timestamp=datetime.now(),
category="series"
)
identity = SeriesIdentity(
title="Show Name",
season=1,
episodes=[1],
confidence=0.9,
needs_review=False,
original_filename="Show.Name.Sample.S01E01.mkv"
)
plan = generate_plan([(video_file, identity)], config)
operation = plan.operations[0]
assert operation.operation_type == "no-op"
assert "Sample file excluded" in operation.reason
def test_generate_plan_sample_can_be_included_via_config(config):
"""When include_sample_files is enabled, sample files can be organized."""
config.plan_include_sample_files = True
video_file = VideoFile(
path=Path("/mnt/nas/videos/series/Show.Name.Sample.S01E01.mkv"),
filename="Show.Name.Sample.S01E01.mkv",
size_bytes=500000,
modified_timestamp=datetime.now(),
category="series"
)
identity = SeriesIdentity(
title="Show Name",
season=1,
episodes=[1],
confidence=0.9,
needs_review=False,
original_filename="Show.Name.Sample.S01E01.mkv"
)
plan = generate_plan([(video_file, identity)], config)
operation = plan.operations[0]
assert operation.operation_type == "move"
def test_generate_plan_for_series_without_season(config):
"""Test plan generation for a series without season (needs review)."""
video_file = VideoFile(
@@ -423,6 +519,147 @@ def test_generate_plan_with_analysis_by_quality(config):
assert "画质" in plan.operations[0].reason
def test_generate_plan_with_analysis_by_reputation_quality_time_reason(config):
"""New strategy should quarantine duplicates with explicit reason text."""
config.duplicate_keep = "by_reputation_quality_time"
p_old = Path("/mnt/nas/videos/movie/Test.2020.720p.WEB-DL.mkv")
p_new = Path("/mnt/nas/videos/movie/Test.2020.1080p.BluRay.mkv")
vf_old = VideoFile(
path=p_old,
filename="Test.2020.720p.WEB-DL.mkv",
size_bytes=1000000,
modified_timestamp=datetime.now(),
category="movie",
)
vf_new = VideoFile(
path=p_new,
filename="Test.2020.1080p.BluRay.mkv",
size_bytes=2000000,
modified_timestamp=datetime.now(),
category="movie",
)
identity = MovieIdentity(
title="Test",
year=2020,
confidence=0.9,
needs_review=False,
original_filename="Test.2020.mkv",
)
identities = [(vf_old, identity), (vf_new, identity)]
analysis_data = {
"metadata": {"source_identities": "identities.json"},
"completeness": [],
"duplicates": [
{
"identity": {"type": "movie", "title": "Test", "year": 2020},
"files": [str(p_old), str(p_new)],
"quality_comparison": [
{"path": str(p_old), "resolution": "1280x720", "size_bytes": 1000000},
{"path": str(p_new), "resolution": "1920x1080", "size_bytes": 2000000},
],
}
],
}
plan = generate_plan(identities, config, analysis_data=analysis_data)
assert plan.summary["quarantine"] == 1
assert "外部评分>画质>时间" in plan.operations[0].reason
def test_generate_plan_with_analysis_by_reputation_missing_scores_uses_fallback_reason(config):
"""by_reputation should clearly state quality fallback when reputation is missing."""
config.duplicate_keep = "by_reputation"
p_web = Path("/mnt/nas/videos/movie/Test.2020.2160p.WEB-DL.mkv")
p_bluray = Path("/mnt/nas/videos/movie/Test.2020.1080p.BluRay.mkv")
vf_web = VideoFile(
path=p_web,
filename="Test.2020.2160p.WEB-DL.mkv",
size_bytes=3000000,
modified_timestamp=datetime.now(),
category="movie",
)
vf_bluray = VideoFile(
path=p_bluray,
filename="Test.2020.1080p.BluRay.mkv",
size_bytes=2000000,
modified_timestamp=datetime.now(),
category="movie",
)
identity = MovieIdentity(
title="Test",
year=2020,
confidence=0.9,
needs_review=False,
original_filename="Test.2020.mkv",
)
identities = [(vf_web, identity), (vf_bluray, identity)]
analysis_data = {
"metadata": {"source_identities": "identities.json"},
"completeness": [],
"duplicates": [
{
"identity": {"type": "movie", "title": "Test", "year": 2020},
"files": [str(p_web), str(p_bluray)],
"quality_comparison": [
{"path": str(p_web), "resolution": "3840x2160", "size_bytes": 3000000},
{"path": str(p_bluray), "resolution": "1920x1080", "size_bytes": 2000000},
],
}
],
}
plan = generate_plan(identities, config, analysis_data=analysis_data)
assert plan.summary["quarantine"] == 1
assert "评分缺失/并列" in plan.operations[0].reason
assert "删除建议(仅隔离建议" in plan.human_summary
assert "评分依据不足" in plan.human_summary
def test_generate_plan_human_summary_marks_disc_files_as_high_risk(config):
"""Disc/part files should be listed with a conservative risk note in summary."""
config.duplicate_keep = "by_reputation"
p_disc1 = Path("/mnt/nas/videos/movie/The.Best.of.Youth.DISC1.mkv")
p_disc2 = Path("/mnt/nas/videos/movie/The.Best.of.Youth.DISC2.mkv")
vf1 = VideoFile(
path=p_disc1,
filename="The.Best.of.Youth.DISC1.mkv",
size_bytes=2000000,
modified_timestamp=datetime.now(),
category="movie",
)
vf2 = VideoFile(
path=p_disc2,
filename="The.Best.of.Youth.DISC2.mkv",
size_bytes=1800000,
modified_timestamp=datetime.now(),
category="movie",
)
identity = MovieIdentity(
title="The Best of Youth",
year=2003,
confidence=0.9,
needs_review=False,
original_filename="The.Best.of.Youth.DISC1.mkv",
)
plan = generate_plan(
[(vf1, identity), (vf2, identity)],
config,
analysis_data={
"metadata": {"source_identities": "identities.json"},
"completeness": [],
"duplicates": [
{
"identity": {"type": "movie", "title": "The Best of Youth", "year": 2003},
"files": [str(p_disc1), str(p_disc2)],
"quality_comparison": [
{"path": str(p_disc1), "resolution": "1920x1080", "size_bytes": 2000000},
{"path": str(p_disc2), "resolution": "1920x1080", "size_bytes": 1800000},
],
}
],
},
)
assert "疑似多碟/分段文件" in plan.human_summary
def test_generate_plan_with_different_extensions(config):
"""Test plan generation preserves file extensions."""
extensions = [".mp4", ".mkv", ".avi"]