125 lines
4.0 KiB
Python
125 lines
4.0 KiB
Python
"""Analyze command implementation."""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
import click
|
|
|
|
from vlm.analysis import analyze_series_completeness, detect_duplicates
|
|
from vlm.context import CLIContext
|
|
from vlm.io import (
|
|
identities_to_analysis_input,
|
|
load_identities_json,
|
|
load_inventory_csv,
|
|
save_analysis_json,
|
|
)
|
|
from vlm.models import (
|
|
AnalysisCompletenessRecord,
|
|
AnalysisDuplicateIdentityRecord,
|
|
AnalysisDuplicateRecord,
|
|
MovieIdentity,
|
|
SeriesIdentity,
|
|
)
|
|
|
|
|
|
def analyze_cmd(
|
|
ctx: CLIContext,
|
|
input: Path,
|
|
output: Path,
|
|
inventory: Optional[Path],
|
|
) -> None:
|
|
"""Run analysis: completeness and duplicate detection."""
|
|
config = ctx.config
|
|
logger = ctx.logger
|
|
|
|
click.echo(f"Analyzing identities from: {input}")
|
|
if inventory:
|
|
click.echo(f"Merging metadata from inventory: {inventory}")
|
|
click.echo()
|
|
|
|
identities_data = load_identities_json(input)
|
|
movies_data = identities_data.get("movies", [])
|
|
series_data = identities_data.get("series", [])
|
|
|
|
click.echo(f"Loaded {len(movies_data)} movies and {len(series_data)} series")
|
|
click.echo()
|
|
|
|
inventory_files = load_inventory_csv(inventory) if inventory else None
|
|
movie_pairs, series_pairs = identities_to_analysis_input(
|
|
identities_data, inventory_files=inventory_files
|
|
)
|
|
series_identities = [identity for identity, _ in series_pairs]
|
|
|
|
click.echo("Analyzing series completeness...")
|
|
completeness_results = analyze_series_completeness(series_identities)
|
|
|
|
click.echo("Detecting duplicates...")
|
|
identity_file_pairs = movie_pairs + series_pairs
|
|
duplicate_groups = detect_duplicates(identity_file_pairs)
|
|
|
|
click.echo()
|
|
click.echo("Analysis complete!")
|
|
click.echo()
|
|
click.echo("Results:")
|
|
click.echo(f" Series with episode gaps: {len(completeness_results)}")
|
|
if completeness_results:
|
|
total_missing = sum(len(c.episodes_missing) for c in completeness_results)
|
|
click.echo(f" - Total missing episodes: {total_missing}")
|
|
click.echo(f" Duplicate groups found: {len(duplicate_groups)}")
|
|
if duplicate_groups:
|
|
total_duplicates = sum(len(g.files) for g in duplicate_groups)
|
|
click.echo(f" - Total duplicate files: {total_duplicates}")
|
|
|
|
click.echo()
|
|
click.echo(f"Saving analysis results to: {output}")
|
|
output.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
completeness_list: list[AnalysisCompletenessRecord] = [
|
|
{
|
|
"series_title": c.series_title,
|
|
"season": c.season,
|
|
"episodes_found": c.episodes_found,
|
|
"episodes_missing": c.episodes_missing,
|
|
}
|
|
for c in completeness_results
|
|
]
|
|
duplicates_list: list[AnalysisDuplicateRecord] = []
|
|
for d in duplicate_groups:
|
|
if isinstance(d.identity, MovieIdentity):
|
|
identity_info: AnalysisDuplicateIdentityRecord = {
|
|
"type": "movie",
|
|
"title": d.identity.title,
|
|
"year": d.identity.year,
|
|
"season": None,
|
|
"episodes": [],
|
|
}
|
|
else:
|
|
identity_info = {
|
|
"type": "series",
|
|
"title": d.identity.title,
|
|
"year": None,
|
|
"season": d.identity.season,
|
|
"episodes": d.identity.episodes,
|
|
}
|
|
duplicates_list.append(
|
|
{
|
|
"identity": identity_info,
|
|
"files": [str(f.path) for f in d.files],
|
|
"quality_comparison": d.quality_comparison,
|
|
}
|
|
)
|
|
save_analysis_json(
|
|
completeness=completeness_list,
|
|
duplicates=duplicates_list,
|
|
source_identities=input,
|
|
total_movies=len(movies_data),
|
|
total_series=len(series_data),
|
|
output=output,
|
|
)
|
|
|
|
click.echo("Analysis results saved successfully!")
|
|
logger.info(
|
|
f"Analysis completed: {len(completeness_results)} incomplete series, "
|
|
f"{len(duplicate_groups)} duplicate groups, saved to {output}"
|
|
)
|