refactor CLI command modules and synchronize docs
This commit is contained in:
+29
-29
@@ -5,7 +5,7 @@ Tests series completeness analysis, duplicate detection, and quality comparison.
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from vlm.models import SeriesIdentity, SeasonCompleteness, MovieIdentity, VideoFile, DuplicateGroup
|
||||
from vlm.analysis import analyze_series_completeness, detect_duplicates, compare_quality
|
||||
|
||||
@@ -193,7 +193,7 @@ class TestDuplicateDetection:
|
||||
Path("/movies/The.Matrix.1999.1080p.mkv"),
|
||||
"The.Matrix.1999.1080p.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264"
|
||||
@@ -202,7 +202,7 @@ class TestDuplicateDetection:
|
||||
Path("/movies/The.Matrix.1999.720p.mkv"),
|
||||
"The.Matrix.1999.720p.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1280x720",
|
||||
codec="h264"
|
||||
@@ -211,7 +211,7 @@ class TestDuplicateDetection:
|
||||
Path("/movies/Inception.2010.mkv"),
|
||||
"Inception.2010.mkv",
|
||||
1500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
),
|
||||
]
|
||||
@@ -239,7 +239,7 @@ class TestDuplicateDetection:
|
||||
Path("/series/Breaking.Bad.S01E01.1080p.mkv"),
|
||||
"Breaking.Bad.S01E01.1080p.mkv",
|
||||
1500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series",
|
||||
resolution="1920x1080"
|
||||
),
|
||||
@@ -247,7 +247,7 @@ class TestDuplicateDetection:
|
||||
Path("/series/Breaking.Bad.S01E01.720p.mkv"),
|
||||
"Breaking.Bad.S01E01.720p.mkv",
|
||||
800000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series",
|
||||
resolution="1280x720"
|
||||
),
|
||||
@@ -255,7 +255,7 @@ class TestDuplicateDetection:
|
||||
Path("/series/Breaking.Bad.S01E02.mkv"),
|
||||
"Breaking.Bad.S01E02.mkv",
|
||||
1200000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series"
|
||||
),
|
||||
]
|
||||
@@ -278,8 +278,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/movies/Movie.A.2020.mkv"), "Movie.A.2020.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie.B.2021.mkv"), "Movie.B.2021.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie.A.2020.mkv"), "Movie.A.2020.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Movie.B.2021.mkv"), "Movie.B.2021.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -294,8 +294,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/movies/Unknown.Movie.mkv"), "Unknown.Movie.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Unknown.Movie.2.mkv"), "Unknown.Movie.2.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Unknown.Movie.mkv"), "Unknown.Movie.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Unknown.Movie.2.mkv"), "Unknown.Movie.2.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -311,8 +311,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/series/Unknown.Show.E01.mkv"), "Unknown.Show.E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Unknown.Show.Episode.1.mkv"), "Unknown.Show.Episode.1.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Unknown.Show.E01.mkv"), "Unknown.Show.E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Unknown.Show.Episode.1.mkv"), "Unknown.Show.Episode.1.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -327,8 +327,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/series/Show.Name.S01.mkv"), "Show.Name.S01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.Name.Season.1.mkv"), "Show.Name.Season.1.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.Name.S01.mkv"), "Show.Name.S01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.Name.Season.1.mkv"), "Show.Name.Season.1.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -347,7 +347,7 @@ class TestDuplicateDetection:
|
||||
Path("/movies/Test.Movie.2020.1080p.mkv"),
|
||||
"Test.Movie.2020.1080p.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264",
|
||||
@@ -358,7 +358,7 @@ class TestDuplicateDetection:
|
||||
Path("/movies/Test.Movie.2020.720p.mkv"),
|
||||
"Test.Movie.2020.720p.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1280x720",
|
||||
codec="h264",
|
||||
@@ -395,9 +395,9 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/series/Show.S01E01-E02.mkv"), "Show.S01E01-E02.mkv", 2000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E01-E02.mkv"), "Show.S01E01-E02.mkv", 2000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -413,8 +413,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/movies/The.Thing.1982.mkv"), "The.Thing.1982.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/The.Thing.2011.mkv"), "The.Thing.2011.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/The.Thing.1982.mkv"), "The.Thing.1982.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/The.Thing.2011.mkv"), "The.Thing.2011.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -429,8 +429,8 @@ class TestDuplicateDetection:
|
||||
]
|
||||
|
||||
files = [
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S02E01.mkv"), "Show.S02E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.S02E01.mkv"), "Show.S02E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
]
|
||||
|
||||
result = detect_duplicates(list(zip(identities, files)))
|
||||
@@ -448,7 +448,7 @@ class TestQualityComparison:
|
||||
Path("/test/file1.mkv"),
|
||||
"file1.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264",
|
||||
@@ -459,7 +459,7 @@ class TestQualityComparison:
|
||||
Path("/test/file2.mkv"),
|
||||
"file2.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1280x720",
|
||||
codec="h265",
|
||||
@@ -490,7 +490,7 @@ class TestQualityComparison:
|
||||
Path("/test/file1.mkv"),
|
||||
"file1.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080"
|
||||
# codec, duration, bitrate not available
|
||||
@@ -499,7 +499,7 @@ class TestQualityComparison:
|
||||
Path("/test/file2.mkv"),
|
||||
"file2.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
# No optional metadata
|
||||
),
|
||||
@@ -532,7 +532,7 @@ class TestQualityComparison:
|
||||
Path("/test/file.mkv"),
|
||||
"file.mkv",
|
||||
1500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264"
|
||||
|
||||
@@ -6,7 +6,7 @@ Each test validates a specific property from the design document.
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from hypothesis import given, strategies as st, settings
|
||||
from vlm.models import (
|
||||
SeriesIdentity, SeasonCompleteness, MovieIdentity, VideoFile, DuplicateGroup
|
||||
@@ -74,7 +74,7 @@ def video_file_strategy(draw, filename=None, category="movie"):
|
||||
|
||||
path = Path(f"/{category}/{filename}")
|
||||
size_bytes = draw(st.integers(min_value=1000000, max_value=10000000000))
|
||||
modified_timestamp = datetime.now()
|
||||
modified_timestamp = datetime.now(timezone.utc)
|
||||
|
||||
# Optional metadata
|
||||
has_metadata = draw(st.booleans())
|
||||
@@ -226,7 +226,7 @@ def test_property_12_duplicate_detection_movies(title, year, duplicate_count):
|
||||
Path(f"/movies/{filename}"),
|
||||
filename,
|
||||
1000000000 + i * 100000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
))
|
||||
|
||||
@@ -272,7 +272,7 @@ def test_property_13_duplicate_detection_series(title, season, episode, duplicat
|
||||
Path(f"/series/{filename}"),
|
||||
filename,
|
||||
1000000000 + i * 100000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series"
|
||||
))
|
||||
|
||||
@@ -321,7 +321,7 @@ def test_property_14_duplicate_quality_comparison(title, year, file_count):
|
||||
Path(f"/movies/{filename}"),
|
||||
filename,
|
||||
1000000000 + i * 100000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264",
|
||||
@@ -333,7 +333,7 @@ def test_property_14_duplicate_quality_comparison(title, year, file_count):
|
||||
Path(f"/movies/{filename}"),
|
||||
filename,
|
||||
1000000000 + i * 100000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
))
|
||||
|
||||
@@ -429,7 +429,7 @@ def test_property_43_duplicate_report_grouping(duplicate_count, format):
|
||||
Path(f"/movies/{filename}"),
|
||||
filename,
|
||||
1000000000 + j * 500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080" if j == 0 else "1280x720",
|
||||
codec="h264"
|
||||
@@ -492,7 +492,7 @@ def test_property_44_summary_report_accuracy(file_count, categories):
|
||||
Path(f"/{category}/{filename}"),
|
||||
filename,
|
||||
size,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
category
|
||||
))
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
from click.testing import CliRunner
|
||||
@@ -46,7 +46,7 @@ def sample_rollback_log(tmp_path):
|
||||
),
|
||||
success=True,
|
||||
error_message=None,
|
||||
executed_at=datetime.now()
|
||||
executed_at=datetime.now(timezone.utc)
|
||||
),
|
||||
OperationResult(
|
||||
operation=FileOperation(
|
||||
@@ -59,14 +59,14 @@ def sample_rollback_log(tmp_path):
|
||||
),
|
||||
success=True,
|
||||
error_message=None,
|
||||
executed_at=datetime.now()
|
||||
executed_at=datetime.now(timezone.utc)
|
||||
)
|
||||
]
|
||||
|
||||
rollback_log = RollbackLog(
|
||||
log_id="test-log-id",
|
||||
execution_plan_id="test-plan-id",
|
||||
executed_at=datetime.now(),
|
||||
executed_at=datetime.now(timezone.utc),
|
||||
operations=operations
|
||||
)
|
||||
|
||||
|
||||
+14
-14
@@ -4,7 +4,7 @@ Tests execution mode handling, dry-run simulation, and actual file operations.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
@@ -73,7 +73,7 @@ def sample_plan(temp_test_dir):
|
||||
|
||||
return ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 1, "rename": 1}
|
||||
)
|
||||
@@ -208,7 +208,7 @@ class TestDryRunSimulation:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[no_op_operation],
|
||||
summary={"no-op": 1}
|
||||
)
|
||||
@@ -233,7 +233,7 @@ class TestDryRunSimulation:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[conflicted_operation],
|
||||
summary={"move": 1}
|
||||
)
|
||||
@@ -285,7 +285,7 @@ class TestExecuteMode:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[operation],
|
||||
summary={"move": 1}
|
||||
)
|
||||
@@ -319,7 +319,7 @@ class TestExecuteMode:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[operation],
|
||||
summary={"move": 1}
|
||||
)
|
||||
@@ -352,7 +352,7 @@ class TestExecuteMode:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[conflicted_operation],
|
||||
summary={"move": 1}
|
||||
)
|
||||
@@ -427,7 +427,7 @@ class TestRollbackLog:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 2}
|
||||
)
|
||||
@@ -480,7 +480,7 @@ class TestExecutionSummary:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 2, "no-op": 1}
|
||||
)
|
||||
@@ -573,7 +573,7 @@ class TestRollbackLogSaving:
|
||||
data = json.load(f)
|
||||
|
||||
# Verify timestamps are in ISO format
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
executed_at = datetime.fromisoformat(data["executed_at"])
|
||||
assert executed_at is not None
|
||||
|
||||
@@ -670,7 +670,7 @@ class TestRollbackExecution:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 2}
|
||||
)
|
||||
@@ -759,7 +759,7 @@ class TestRollbackExecution:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 1, "no-op": 1}
|
||||
)
|
||||
@@ -877,7 +877,7 @@ class TestRollbackExecution:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=operations,
|
||||
summary={"move": 2}
|
||||
)
|
||||
@@ -920,7 +920,7 @@ class TestRollbackExecution:
|
||||
|
||||
plan = ExecutionPlan(
|
||||
plan_id=str(uuid4()),
|
||||
created_at=datetime.now(),
|
||||
created_at=datetime.now(timezone.utc),
|
||||
operations=[
|
||||
FileOperation(
|
||||
operation_type="quarantine",
|
||||
|
||||
+46
-46
@@ -1,7 +1,7 @@
|
||||
"""Unit tests for plan generator."""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
from vlm.config import Config
|
||||
@@ -36,7 +36,7 @@ def test_generate_plan_for_movie_with_year(config):
|
||||
path=Path("/mnt/nas/videos/movie/Some.Movie.2020.1080p.mkv"),
|
||||
filename="Some.Movie.2020.1080p.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -67,7 +67,7 @@ def test_generate_plan_for_movie_without_year(config):
|
||||
path=Path("/mnt/nas/videos/movie/random_movie.mkv"),
|
||||
filename="random_movie.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -94,7 +94,7 @@ def test_generate_plan_for_series_with_season_and_episode(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.Name.S01E05.mkv"),
|
||||
filename="Show.Name.S01E05.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
|
||||
@@ -123,7 +123,7 @@ def test_generate_plan_blocks_series_with_high_season(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.Name.S20E01.mkv"),
|
||||
filename="Show.Name.S20E01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
identity = SeriesIdentity(
|
||||
@@ -147,7 +147,7 @@ def test_generate_plan_blocks_series_with_high_episode(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.Name.S01E120.mkv"),
|
||||
filename="Show.Name.S01E120.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
identity = SeriesIdentity(
|
||||
@@ -171,7 +171,7 @@ def test_generate_plan_sample_is_noop_by_default(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.Name.Sample.S01E01.mkv"),
|
||||
filename="Show.Name.Sample.S01E01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
identity = SeriesIdentity(
|
||||
@@ -196,7 +196,7 @@ def test_generate_plan_sample_can_be_included_via_config(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.Name.Sample.S01E01.mkv"),
|
||||
filename="Show.Name.Sample.S01E01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
identity = SeriesIdentity(
|
||||
@@ -219,7 +219,7 @@ def test_generate_plan_for_series_without_season(config):
|
||||
path=Path("/mnt/nas/videos/series/ambiguous_show.mkv"),
|
||||
filename="ambiguous_show.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
|
||||
@@ -247,7 +247,7 @@ def test_generate_plan_for_anime_category(config):
|
||||
path=Path("/mnt/nas/videos/anime/Some.Anime.01.mkv"),
|
||||
filename="Some.Anime.01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="anime"
|
||||
)
|
||||
|
||||
@@ -267,7 +267,7 @@ def test_generate_plan_for_other_category(config):
|
||||
path=Path("/mnt/nas/videos/other/random.mkv"),
|
||||
filename="random.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="other"
|
||||
)
|
||||
|
||||
@@ -286,7 +286,7 @@ def test_generate_plan_preserves_category_boundaries(config):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -311,7 +311,7 @@ def test_generate_plan_for_multi_episode_file(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.S01E01E02.mkv"),
|
||||
filename="Show.S01E01E02.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
|
||||
@@ -338,7 +338,7 @@ def test_generate_plan_file_already_at_target(config):
|
||||
path=Path("/mnt/nas/videos/movie/Some Movie (2020)/Some Movie (2020).mkv"),
|
||||
filename="Some Movie (2020).mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -364,7 +364,7 @@ def test_generate_plan_rename_vs_move(config):
|
||||
path=Path("/mnt/nas/videos/movie/Some Movie (2020)/old_name.mkv"),
|
||||
filename="old_name.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -385,7 +385,7 @@ def test_generate_plan_rename_vs_move(config):
|
||||
path=Path("/mnt/nas/videos/movie/wrong_dir/Some Movie (2020).mkv"),
|
||||
filename="Some Movie (2020).mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -403,7 +403,7 @@ def test_generate_plan_summary(config):
|
||||
path=Path("/mnt/nas/videos/movie/Movie1.2020.mkv"),
|
||||
filename="Movie1.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -420,7 +420,7 @@ def test_generate_plan_summary(config):
|
||||
path=Path("/mnt/nas/videos/movie/Movie2.mkv"),
|
||||
filename="Movie2.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -437,7 +437,7 @@ def test_generate_plan_summary(config):
|
||||
path=Path("/mnt/nas/videos/anime/Anime.01.mkv"),
|
||||
filename="Anime.01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="anime"
|
||||
),
|
||||
None
|
||||
@@ -448,7 +448,7 @@ def test_generate_plan_summary(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.S01E01.mkv"),
|
||||
filename="Show.S01E01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
),
|
||||
SeriesIdentity(
|
||||
@@ -480,14 +480,14 @@ def test_generate_plan_with_analysis_by_quality(config):
|
||||
path=p_720,
|
||||
filename="Test.2020.720p.WEB-DL.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
vf_1080 = VideoFile(
|
||||
path=p_1080,
|
||||
filename="Test.2020.1080p.BluRay.mkv",
|
||||
size_bytes=2000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
identity = MovieIdentity(
|
||||
@@ -528,14 +528,14 @@ def test_generate_plan_with_analysis_by_reputation_quality_time_reason(config):
|
||||
path=p_old,
|
||||
filename="Test.2020.720p.WEB-DL.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
vf_new = VideoFile(
|
||||
path=p_new,
|
||||
filename="Test.2020.1080p.BluRay.mkv",
|
||||
size_bytes=2000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
identity = MovieIdentity(
|
||||
@@ -574,14 +574,14 @@ def test_generate_plan_with_analysis_by_reputation_missing_scores_uses_fallback_
|
||||
path=p_web,
|
||||
filename="Test.2020.2160p.WEB-DL.mkv",
|
||||
size_bytes=3000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
vf_bluray = VideoFile(
|
||||
path=p_bluray,
|
||||
filename="Test.2020.1080p.BluRay.mkv",
|
||||
size_bytes=2000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
identity = MovieIdentity(
|
||||
@@ -622,14 +622,14 @@ def test_generate_plan_human_summary_marks_disc_files_as_high_risk(config):
|
||||
path=p_disc1,
|
||||
filename="The.Best.of.Youth.DISC1.mkv",
|
||||
size_bytes=2000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
vf2 = VideoFile(
|
||||
path=p_disc2,
|
||||
filename="The.Best.of.Youth.DISC2.mkv",
|
||||
size_bytes=1800000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie",
|
||||
)
|
||||
identity = MovieIdentity(
|
||||
@@ -669,7 +669,7 @@ def test_generate_plan_with_different_extensions(config):
|
||||
path=Path(f"/mnt/nas/videos/movie/Movie.2020{ext}"),
|
||||
filename=f"Movie.2020{ext}",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -704,7 +704,7 @@ def test_conflict_detection_for_movie(config, tmp_path):
|
||||
path=tmp_path / "movie" / "Some.Movie.2020.1080p.mkv",
|
||||
filename="Some.Movie.2020.1080p.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -741,7 +741,7 @@ def test_conflict_detection_for_series(config, tmp_path):
|
||||
path=tmp_path / "series" / "Show.Name.S01E05.1080p.mkv",
|
||||
filename="Show.Name.S01E05.1080p.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
|
||||
@@ -776,7 +776,7 @@ def test_no_conflict_when_destination_does_not_exist(config, tmp_path):
|
||||
path=source_dir / "Some.Movie.2020.mkv",
|
||||
filename="Some.Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -814,7 +814,7 @@ def test_conflict_detection_with_multiple_files(config, tmp_path):
|
||||
path=tmp_path / "movie" / "Movie1.2020.mkv",
|
||||
filename="Movie1.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -831,7 +831,7 @@ def test_conflict_detection_with_multiple_files(config, tmp_path):
|
||||
path=tmp_path / "movie" / "Movie2.2021.mkv",
|
||||
filename="Movie2.2021.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -864,7 +864,7 @@ def test_save_plan_to_json(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -909,7 +909,7 @@ def test_load_plan_from_json(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -963,7 +963,7 @@ def test_save_and_load_plan_with_conflicts(config, tmp_path):
|
||||
path=tmp_path / "movie" / "Movie.2020.mkv",
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -1003,7 +1003,7 @@ def test_save_and_load_plan_with_no_op_operations(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/anime/Anime.01.mkv"),
|
||||
filename="Anime.01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="anime"
|
||||
),
|
||||
None
|
||||
@@ -1014,7 +1014,7 @@ def test_save_and_load_plan_with_no_op_operations(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.mkv"),
|
||||
filename="Movie.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -1048,7 +1048,7 @@ def test_save_plan_json_is_human_readable(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -1089,7 +1089,7 @@ def test_save_plan_with_multiple_operations(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie1.2020.mkv"),
|
||||
filename="Movie1.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
),
|
||||
MovieIdentity(
|
||||
@@ -1106,7 +1106,7 @@ def test_save_plan_with_multiple_operations(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/series/Show.S01E01.mkv"),
|
||||
filename="Show.S01E01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
),
|
||||
SeriesIdentity(
|
||||
@@ -1124,7 +1124,7 @@ def test_save_plan_with_multiple_operations(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/anime/Anime.01.mkv"),
|
||||
filename="Anime.01.mkv",
|
||||
size_bytes=500000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="anime"
|
||||
),
|
||||
None
|
||||
@@ -1176,7 +1176,7 @@ def test_plan_json_includes_all_required_fields(config, tmp_path):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -1214,7 +1214,7 @@ def test_movie_rejected_by_review_generates_noop(config):
|
||||
path=Path("/mnt/nas/videos/movie/Movie.2020.mkv"),
|
||||
filename="Movie.2020.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="movie"
|
||||
)
|
||||
|
||||
@@ -1238,7 +1238,7 @@ def test_series_rejected_by_review_generates_noop(config):
|
||||
path=Path("/mnt/nas/videos/series/Show.S01E01.mkv"),
|
||||
filename="Show.S01E01.mkv",
|
||||
size_bytes=1000000,
|
||||
modified_timestamp=datetime.now(),
|
||||
modified_timestamp=datetime.now(timezone.utc),
|
||||
category="series"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import json
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from vlm.quarantine import QuarantineManager
|
||||
from vlm.config import Config
|
||||
|
||||
+23
-23
@@ -185,7 +185,7 @@ class TestInventoryReport:
|
||||
Path("/test.mkv"),
|
||||
"test.mkv",
|
||||
1000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
)
|
||||
]
|
||||
@@ -377,7 +377,7 @@ class TestDuplicateReport:
|
||||
Path("/movies/The.Matrix.1999.1080p.mkv"),
|
||||
"The.Matrix.1999.1080p.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264",
|
||||
@@ -388,7 +388,7 @@ class TestDuplicateReport:
|
||||
Path("/movies/The.Matrix.1999.720p.mkv"),
|
||||
"The.Matrix.1999.720p.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1280x720",
|
||||
codec="h264"
|
||||
@@ -448,14 +448,14 @@ class TestDuplicateReport:
|
||||
Path("/movies/Inception.2010.1080p.mkv"),
|
||||
"Inception.2010.1080p.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
),
|
||||
VideoFile(
|
||||
Path("/movies/Inception.2010.720p.mkv"),
|
||||
"Inception.2010.720p.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
),
|
||||
]
|
||||
@@ -501,14 +501,14 @@ class TestDuplicateReport:
|
||||
Path("/series/Breaking.Bad.S01E01.1080p.mkv"),
|
||||
"Breaking.Bad.S01E01.1080p.mkv",
|
||||
1500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series"
|
||||
),
|
||||
VideoFile(
|
||||
Path("/series/Breaking.Bad.S01E01.720p.mkv"),
|
||||
"Breaking.Bad.S01E01.720p.mkv",
|
||||
800000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"series"
|
||||
),
|
||||
]
|
||||
@@ -564,8 +564,8 @@ class TestDuplicateReport:
|
||||
# Create two duplicate groups with different sizes
|
||||
identity1 = MovieIdentity("Small Movie", 2020, 0.9, False, "Small.Movie.mkv")
|
||||
files1 = [
|
||||
VideoFile(Path("/movies/Small.Movie.1.mkv"), "Small.Movie.1.mkv", 500000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Small.Movie.2.mkv"), "Small.Movie.2.mkv", 600000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Small.Movie.1.mkv"), "Small.Movie.1.mkv", 500000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Small.Movie.2.mkv"), "Small.Movie.2.mkv", 600000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
quality1 = [
|
||||
{'filename': 'Small.Movie.1.mkv', 'path': '/movies/Small.Movie.1.mkv', 'size_bytes': 500000000},
|
||||
@@ -574,8 +574,8 @@ class TestDuplicateReport:
|
||||
|
||||
identity2 = MovieIdentity("Large Movie", 2021, 0.9, False, "Large.Movie.mkv")
|
||||
files2 = [
|
||||
VideoFile(Path("/movies/Large.Movie.1.mkv"), "Large.Movie.1.mkv", 2000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Large.Movie.2.mkv"), "Large.Movie.2.mkv", 1800000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Large.Movie.1.mkv"), "Large.Movie.1.mkv", 2000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Large.Movie.2.mkv"), "Large.Movie.2.mkv", 1800000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
quality2 = [
|
||||
{'filename': 'Large.Movie.1.mkv', 'path': '/movies/Large.Movie.1.mkv', 'size_bytes': 2000000000},
|
||||
@@ -600,8 +600,8 @@ class TestDuplicateReport:
|
||||
"""Sort order should use quality_comparison sizes when VideoFile sizes are zero."""
|
||||
identity1 = MovieIdentity("Tiny", 2020, 0.9, False, "Tiny.mkv")
|
||||
files1 = [
|
||||
VideoFile(Path("/movies/Tiny.1.mkv"), "Tiny.1.mkv", 0, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Tiny.2.mkv"), "Tiny.2.mkv", 0, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Tiny.1.mkv"), "Tiny.1.mkv", 0, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Tiny.2.mkv"), "Tiny.2.mkv", 0, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
quality1 = [
|
||||
{"filename": "Tiny.1.mkv", "path": "/movies/Tiny.1.mkv", "size_bytes": 600000000},
|
||||
@@ -610,8 +610,8 @@ class TestDuplicateReport:
|
||||
|
||||
identity2 = MovieIdentity("Huge", 2021, 0.9, False, "Huge.mkv")
|
||||
files2 = [
|
||||
VideoFile(Path("/movies/Huge.1.mkv"), "Huge.1.mkv", 0, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Huge.2.mkv"), "Huge.2.mkv", 0, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Huge.1.mkv"), "Huge.1.mkv", 0, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Huge.2.mkv"), "Huge.2.mkv", 0, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
quality2 = [
|
||||
{"filename": "Huge.1.mkv", "path": "/movies/Huge.1.mkv", "size_bytes": 3000000000},
|
||||
@@ -632,12 +632,12 @@ class TestSummaryReport:
|
||||
def test_generate_summary_report(self):
|
||||
"""Test generating summary report with various files."""
|
||||
files = [
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 2000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 1500000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/anime/Anime1.mkv"), "Anime1.mkv", 800000000, datetime.now(), "anime"),
|
||||
VideoFile(Path("/other/Random.mkv"), "Random.mkv", 500000000, datetime.now(), "other"),
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 2000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 1500000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/anime/Anime1.mkv"), "Anime1.mkv", 800000000, datetime.now(timezone.utc), "anime"),
|
||||
VideoFile(Path("/other/Random.mkv"), "Random.mkv", 500000000, datetime.now(timezone.utc), "other"),
|
||||
]
|
||||
|
||||
library_root = Path("/mnt/nas/videos")
|
||||
@@ -677,8 +677,8 @@ class TestSummaryReport:
|
||||
def test_generate_summary_report_single_category(self):
|
||||
"""Test generating summary report with files in single category."""
|
||||
files = [
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 1000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 2000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 1000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 2000000000, datetime.now(timezone.utc), "movie"),
|
||||
]
|
||||
|
||||
library_root = Path("/mnt/nas/videos")
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests the complete workflow from analysis to report generation.
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timezone
|
||||
from vlm.models import SeriesIdentity, VideoFile, MovieIdentity
|
||||
from vlm.analysis import analyze_series_completeness, detect_duplicates
|
||||
from vlm.reports import generate_completeness_report, generate_duplicate_report, generate_summary_report
|
||||
@@ -59,7 +59,7 @@ class TestReportsIntegration:
|
||||
Path("/movies/The.Matrix.1999.1080p.mkv"),
|
||||
"The.Matrix.1999.1080p.mkv",
|
||||
2000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1920x1080",
|
||||
codec="h264"
|
||||
@@ -68,7 +68,7 @@ class TestReportsIntegration:
|
||||
Path("/movies/The.Matrix.1999.720p.mkv"),
|
||||
"The.Matrix.1999.720p.mkv",
|
||||
1000000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie",
|
||||
resolution="1280x720",
|
||||
codec="h264"
|
||||
@@ -77,7 +77,7 @@ class TestReportsIntegration:
|
||||
Path("/movies/Inception.2010.mkv"),
|
||||
"Inception.2010.mkv",
|
||||
1500000000,
|
||||
datetime.now(),
|
||||
datetime.now(timezone.utc),
|
||||
"movie"
|
||||
),
|
||||
]
|
||||
@@ -107,11 +107,11 @@ class TestReportsIntegration:
|
||||
"""Test summary report generation with mixed file types."""
|
||||
# Create test files
|
||||
files = [
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 2000000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 1500000000, datetime.now(), "movie"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(), "series"),
|
||||
VideoFile(Path("/anime/Anime1.mkv"), "Anime1.mkv", 800000000, datetime.now(), "anime"),
|
||||
VideoFile(Path("/movies/Movie1.mkv"), "Movie1.mkv", 2000000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/movies/Movie2.mkv"), "Movie2.mkv", 1500000000, datetime.now(timezone.utc), "movie"),
|
||||
VideoFile(Path("/series/Show.S01E01.mkv"), "Show.S01E01.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/series/Show.S01E02.mkv"), "Show.S01E02.mkv", 1000000000, datetime.now(timezone.utc), "series"),
|
||||
VideoFile(Path("/anime/Anime1.mkv"), "Anime1.mkv", 800000000, datetime.now(timezone.utc), "anime"),
|
||||
]
|
||||
|
||||
# Generate summary report
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ class TestLoadSaveState:
|
||||
store = StateStore(
|
||||
states={},
|
||||
version='1.0',
|
||||
last_updated=datetime.now()
|
||||
last_updated=datetime.now(timezone.utc)
|
||||
)
|
||||
|
||||
save_state(store, state_path)
|
||||
|
||||
Reference in New Issue
Block a user