Enhance project structure and add new files for enrichment and analysis
- Updated AGENTS.md to reflect changes in CLI commands and module organization, including the addition of an enrichment step and new functional modules. - Introduced analysis.json, identities.json, inventory.csv, and plan.json to support enriched metadata and execution planning. - Added CODE_IMPROVEMENTS.md to document identified code issues and proposed solutions for future enhancements. - Updated README.md to include new enrichment features and configuration options. - Removed unused dependency on ffmpeg-python from pyproject.toml. These changes improve the overall functionality and maintainability of the Video Library Manager project.
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""Analyze command implementation."""
|
||||
|
||||
import json
|
||||
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
|
||||
from vlm.models import MovieIdentity, SeriesIdentity
|
||||
from vlm.utils import utc_now
|
||||
|
||||
|
||||
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_identities, series_identities, video_files = identities_to_analysis_input(
|
||||
identities_data, inventory_files=inventory_files
|
||||
)
|
||||
|
||||
click.echo("Analyzing series completeness...")
|
||||
completeness_results = analyze_series_completeness(series_identities)
|
||||
|
||||
click.echo("Detecting duplicates...")
|
||||
n_movies = len(movie_identities)
|
||||
identity_file_pairs = (
|
||||
list(zip(movie_identities, video_files[:n_movies]))
|
||||
+ list(zip(series_identities, video_files[n_movies:]))
|
||||
)
|
||||
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)
|
||||
|
||||
generation_timestamp = utc_now().strftime("%Y-%m-%dT%H:%M:%S")
|
||||
completeness_list = [
|
||||
{
|
||||
"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 = []
|
||||
for d in duplicate_groups:
|
||||
if isinstance(d.identity, MovieIdentity):
|
||||
identity_info = {"type": "movie", "title": d.identity.title, "year": d.identity.year}
|
||||
else:
|
||||
identity_info = {
|
||||
"type": "series",
|
||||
"title": d.identity.title,
|
||||
"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,
|
||||
}
|
||||
)
|
||||
analysis_data = {
|
||||
"metadata": {
|
||||
"generated": generation_timestamp,
|
||||
"source_identities": str(input),
|
||||
"total_movies": len(movies_data),
|
||||
"total_series": len(series_data),
|
||||
},
|
||||
"completeness": completeness_list,
|
||||
"duplicates": duplicates_list,
|
||||
}
|
||||
with open(output, "w", encoding="utf-8") as jsonfile:
|
||||
json.dump(analysis_data, jsonfile, indent=2, ensure_ascii=False)
|
||||
|
||||
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}"
|
||||
)
|
||||
Reference in New Issue
Block a user