52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""Duplicate group resolution: choose which file to keep when consuming analysis."""
|
|||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import Union
|
||
|
|
|
||
|
|
from vlm.models import MovieIdentity, SeriesIdentity
|
||
|
|
|
||
|
|
|
||
|
|
def choose_keep_index(
|
||
|
|
items: list[tuple[Path, Union[MovieIdentity, SeriesIdentity]]],
|
||
|
|
strategy: str,
|
||
|
|
) -> int | None:
|
||
|
|
"""Choose the index of the item to keep in a duplicate group.
|
||
|
|
|
||
|
|
Strategies:
|
||
|
|
- by_reputation: Prefer items with reputation_score; then sort by score desc,
|
||
|
|
then reputation_votes desc, then first_seen (input order). Keep index 0 after sort.
|
||
|
|
- first_seen: Keep the first item (index 0).
|
||
|
|
- manual: Return None; caller should not generate quarantine ops, only record in metadata.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
items: List of (path, identity) for the duplicate group.
|
||
|
|
strategy: One of "by_reputation", "first_seen", "manual".
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Index in [0, len(items)) to keep, or None for manual.
|
||
|
|
"""
|
||
|
|
if strategy == "manual":
|
||
|
|
return None
|
||
|
|
if strategy == "first_seen":
|
||
|
|
return 0
|
||
|
|
if strategy == "by_reputation":
|
||
|
|
return _by_reputation_index(items)
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
def _by_reputation_index(
|
||
|
|
items: list[tuple[Path, Union[MovieIdentity, SeriesIdentity]]],
|
||
|
|
) -> int:
|
||
|
|
"""Sort by: has reputation > no reputation; then score desc; then votes desc; then order. Return 0."""
|
||
|
|
def key(idx_reason: tuple[int, tuple[Path, Union[MovieIdentity, SeriesIdentity]]]) -> tuple:
|
||
|
|
idx, (path, identity) = idx_reason
|
||
|
|
has_rep = identity.reputation_score is not None
|
||
|
|
score = identity.reputation_score if identity.reputation_score is not None else -1.0
|
||
|
|
votes = identity.reputation_votes if identity.reputation_votes is not None else -1
|
||
|
|
# Prefer has reputation (True > False), then higher score, then higher votes, then lower index
|
||
|
|
return (not has_rep, -score, -votes, idx)
|
||
|
|
|
||
|
|
indexed = list(enumerate(items))
|
||
|
|
indexed.sort(key=key)
|
||
|
|
return indexed[0][0]
|