Ctrl K
ComunidadGuías…

tests/test_fc2_cast_review.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# -*- coding: utf-8 -*-
"""FC2 演员复核清单:账本已有的演员与 fc2cmadb 对不上的番号列出来,只出清单不写库。"""
from __future__ import annotations

import json
import sqlite3
import tempfile
import unittest
from pathlib import Path

from peach.jav_cover_fetch import NotFound
from peach.review_csv import read_candidates, read_rows
from scripts.fc2_cast_review import build_parser, run
from support.ledger import fresh_ledger


class _Mirror:
    """按番号回 fc2cmadb 那一页;没登记的番号是 404,登记成异常的原样抛。"""

    def __init__(self, pages):
        self.pages = pages
        self.asked = []

    def site(self, source, code):
        self.asked.append((source, code))
        page = self.pages.get(code)
        if page is None:
            raise NotFound("HTTP 404")
        if isinstance(page, Exception):
            raise page
        return page


def _page(code, *names):
    return {"id": code, "source_url": f"https://fc2cmadb.com/articles/{code.rsplit('-', 1)[-1]}",
            "actresses": list(names)}


class Fc2CastReviewTests(unittest.TestCase):
    def setUp(self):
        tmp = tempfile.TemporaryDirectory()
        self.addCleanup(tmp.cleanup)
        self.root = Path(tmp.name).resolve()
        self.db = fresh_ledger(self.root)
        self.snapshots = self.root / "library-metadata"
        self.snapshots.mkdir()
        self.output = self.root / "generated" / "fc2-cast-candidates.csv"
        con = sqlite3.connect(self.db)
        try:
            con.executemany(
                "INSERT INTO asset(id,location,path,name,medium,size,first_seen,code)"
                " VALUES(?,'local',?,?,'video',100,'2026-01-01',?)",
                [(1, r"R:\media\a.mp4", "a.mp4", "FC2-PPV-2629971"),
                 (2, r"R:\media\b.mp4", "b.mp4", "FC2-PPV-1449453"),
                 (3, r"R:\media\c.mp4", "c.mp4", "FC2-PPV-3518061"),
                 (4, r"R:\media\d.mp4", "d.mp4", "FC2-PPV-2851534")])
            con.executemany(
                "INSERT INTO entity(id,kind,canonical_name,normalized_name,metadata_json,"
                "created_at,updated_at) VALUES(?,'performer',?,?,'{}','t','t')",
                [(11, "安娜", "安娜"), (12, "Chisa", "chisa"), (13, "梨奈", "梨奈"), (14, "みお", "みお")])
            con.execute("INSERT INTO entity_alias(entity_id,alias,normalized_alias,source)"
                        " VALUES(13,'りな','りな','test')")
            con.executemany(
                "INSERT INTO asset_entity(asset_id,entity_id,role,source,confidence)"
                " VALUES(?,?,'performer',?,1.0)",
                [(1, 11, "javinizer:javdb:performer"), (2, 12, "javinizer:javdb:performer"),
                 (3, 13, "javinizer:javdb:performer"), (4, 14, "user")])
            con.commit()
        finally:
            con.close()

    def _snapshot(self, code, *names):
        (self.snapshots / f"{code}-fc2cmadb.json").write_text(
            json.dumps(_page(code, *names), ensure_ascii=False), encoding="utf-8")

    def _run(self, *extra, provider=None):
        self.pauses = []
        args = build_parser().parse_args(
            ["--db", str(self.db), "--snapshots", str(self.snapshots),
             "--output", str(self.output), "--misses", str(self.root / "misses.json"), *extra])
        return run(args, provider=provider, sleep=self.pauses.append)

    def test_a_different_name_on_the_mirror_becomes_one_review_row(self):
        self._snapshot("FC2-PPV-2629971", "あんな")
        self._snapshot("FC2-PPV-3518061", "りな")
        result = self._run("--offline")
        rows = read_rows(self.output)
        self.assertEqual([row["item_key"] for row in rows], ["FC2-PPV-2629971:performers:fc2cmadb"])
        self.assertEqual(rows[0]["current_value"], "安娜")
        candidate = json.loads(rows[0]["candidates_json"])[0]
        self.assertEqual((candidate["source"], candidate["display_value"]), ("fc2cmadb", "あんな"))
        self.assertEqual(result["review"], 1)
        # 别名登记过的同一个人不算分歧;没存快照的离线时算「站上没有」。
        self.assertEqual((result["agreed_or_empty"], result["not_on_mirror"]), (1, 1))

    def test_a_code_with_a_cast_the_user_set_is_left_alone(self):
        self._snapshot("FC2-PPV-2851534", "梨奈")
        self._run("--offline")
        self.assertEqual(read_rows(self.output), [])

    def test_the_review_page_reads_the_list_as_metadata_fields(self):
        self._snapshot("FC2-PPV-1449453", "大村阿美香")
        self._run("--offline")
        rows, _label, skipped = read_candidates("metadata_fields", self.output.parent)
        self.assertEqual(skipped, 0)
        self.assertEqual([(row["item_key"], row["field"]) for row in rows],
                         [("FC2-PPV-1449453:performers:fc2cmadb", "performers")])

    def test_a_live_answer_is_kept_as_a_snapshot_and_not_asked_twice(self):
        mirror = _Mirror({"FC2-PPV-1449453": _page("FC2-PPV-1449453", "大村阿美香")})
        first = self._run(provider=mirror)
        self.assertEqual((first["review"], first["not_on_mirror"]), (1, 2))
        self.assertTrue((self.snapshots / "FC2-PPV-1449453-fc2cmadb.json").is_file())
        asked = len(mirror.asked)
        self._run(provider=mirror)
        self.assertNotIn(("fc2cmadb", "FC2-PPV-1449453"), mirror.asked[asked:])

    def test_a_code_the_mirror_does_not_have_is_not_asked_again(self):
        mirror = _Mirror({})
        self._run(provider=mirror)
        self.assertEqual(len(mirror.asked), 3)
        result = self._run(provider=mirror)
        self.assertEqual(len(mirror.asked), 3)
        self.assertEqual(result["not_on_mirror"], 3)

    def test_live_questions_are_spaced_but_snapshots_are_not(self):
        self._snapshot("FC2-PPV-1449453", "大村阿美香")
        self._run("--interval", "7", provider=_Mirror({}))
        # 三个番号里一个有快照,剩下两次联网之间停一次。
        self.assertEqual(self.pauses, [7.0])

    def test_a_snapshot_without_the_cast_column_is_asked_once_more(self):
        """女优栏要单独再问一跳,没问过那一跳的快照是空的(`2629971` 站上是 `あんな`)。"""
        self._snapshot("FC2-PPV-2629971")
        self._snapshot("FC2-PPV-3518061")
        mirror = _Mirror({"FC2-PPV-2629971": _page("FC2-PPV-2629971", "あんな"),
                          "FC2-PPV-3518061": _page("FC2-PPV-3518061")})
        self._run(provider=mirror)
        self.assertEqual([row["code"] for row in read_rows(self.output)], ["FC2-PPV-2629971"])
        asked = len(mirror.asked)
        self._run(provider=mirror)
        # 重问过仍空的一周内不再问;有了女优栏的读快照。
        self.assertNotIn("FC2-PPV-3518061", [code for _, code in mirror.asked[asked:]])
        self.assertNotIn("FC2-PPV-2629971", [code for _, code in mirror.asked[asked:]])

    def test_a_failure_other_than_absence_stops_and_keeps_what_was_found(self):
        mirror = _Mirror({"FC2-PPV-1449453": _page("FC2-PPV-1449453", "大村阿美香"),
                          "FC2-PPV-2629971": TimeoutError("read timed out")})
        result = self._run(provider=mirror)
        self.assertTrue(result["stopped"].startswith("FC2-PPV-2629971"))
        self.assertEqual([row["code"] for row in read_rows(self.output)], ["FC2-PPV-1449453"])


if __name__ == "__main__":
    unittest.main()