230 lines
9.2 KiB
Python
230 lines
9.2 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
fix_illustrations_master.py
|
||
===========================
|
||
Глобальное исправление каталога и привязок иллюстраций:
|
||
1. Восстановление префикса assets/illustrations/ для всех 916 файлов
|
||
2. Полное удаление 28 фейковых виньеток Керлота (MD5 edb1a8f53f9b5502ae38e297711cdf6a)
|
||
3. Полное удаление 146 страниц оглавления/введения Бира (soderzhanie, vvedenie)
|
||
4. Исправление конкретных ложных привязок:
|
||
- сверчок (убираем свастики)
|
||
- свастика (убираем критского осьминога)
|
||
- василиск (убираем вазу на могиле)
|
||
- шип (убираем шлем Афины)
|
||
- фиолетовый (убираем триграммы)
|
||
- бамбук и баньян (убираем бабочку)
|
||
- фаллос (убираем фейковую виньетку)
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import json
|
||
import hashlib
|
||
from pathlib import Path
|
||
from typing import Dict, Any, List
|
||
|
||
ROOT = Path("/home/alexives/Desktop/StudioProjects/999")
|
||
CATALOG_PATH = ROOT / "assets/data/oracle_illustrations_catalog.json"
|
||
PASSPORTS_PATH = ROOT / "assets/data/oracle_passports.json"
|
||
STAGING_PATH = ROOT / "assets/data/oracle_passports_staging.json"
|
||
EXTERNAL_PATH = ROOT / "assets/data/oracle_external_symbols.json"
|
||
ILL_DIR = ROOT / "assets/illustrations"
|
||
|
||
FAKE_CIRLOT_MD5 = "edb1a8f53f9b5502ae38e297711cdf6a"
|
||
|
||
def normalize_path(p: str) -> str:
|
||
if not p:
|
||
return ""
|
||
p = p.strip()
|
||
if not p.startswith("assets/illustrations/"):
|
||
fname = os.path.basename(p)
|
||
return f"assets/illustrations/{fname}"
|
||
return p
|
||
|
||
def main():
|
||
print("=== НАЧАЛО ИСПРАВЛЕНИЯ ЦЕЛОСТНОСТИ ИЛЛЮСТРАЦИЙ ===")
|
||
|
||
with open(CATALOG_PATH, "r", encoding="utf-8") as f:
|
||
catalog = json.load(f)
|
||
|
||
with open(PASSPORTS_PATH, "r", encoding="utf-8") as f:
|
||
passports = json.load(f)
|
||
|
||
with open(STAGING_PATH, "r", encoding="utf-8") as f:
|
||
staging = json.load(f)
|
||
|
||
with open(EXTERNAL_PATH, "r", encoding="utf-8") as f:
|
||
external = json.load(f)
|
||
|
||
# 1. Поиск запрещенных / фейковых файлов
|
||
blacklisted_files = set()
|
||
for f in ILL_DIR.glob("*"):
|
||
if f.is_file():
|
||
fname = f.name
|
||
# Оглавление и введение Бира
|
||
if "soderzhanie" in fname.lower() or "vvedenie" in fname.lower():
|
||
blacklisted_files.add(fname)
|
||
blacklisted_files.add(f"assets/illustrations/{fname}")
|
||
# Фейковая виньетка Керлота
|
||
try:
|
||
h = hashlib.md5(f.read_bytes()).hexdigest()
|
||
if h == FAKE_CIRLOT_MD5:
|
||
blacklisted_files.add(fname)
|
||
blacklisted_files.add(f"assets/illustrations/{fname}")
|
||
except Exception:
|
||
pass
|
||
|
||
print(f"Обнаружено {len(blacklisted_files)} запрещенных файлов (виньетки и оглавления).")
|
||
|
||
# Удаляем запрещенные файлы с диска
|
||
deleted_disk_count = 0
|
||
for bf in blacklisted_files:
|
||
p = ROOT / bf
|
||
if p.exists():
|
||
try:
|
||
p.unlink()
|
||
deleted_disk_count += 1
|
||
except Exception:
|
||
pass
|
||
print(f"Удалено с диска: {deleted_disk_count} файлов.")
|
||
|
||
# 2. Фильтрация и исправление путей в Catalog
|
||
new_catalog = []
|
||
for item in catalog:
|
||
raw_f = item.get("file") or item.get("path") or ""
|
||
fname = os.path.basename(raw_f)
|
||
if fname in blacklisted_files or raw_f in blacklisted_files:
|
||
continue
|
||
|
||
fixed_path = normalize_path(raw_f)
|
||
item["file"] = fixed_path
|
||
if "path" in item:
|
||
item["path"] = fixed_path
|
||
|
||
# Проверяем конкретные ложные привязки
|
||
norm = item.get("normalized", "").lower()
|
||
cap = (item.get("caption") or "").lower()
|
||
|
||
# сверчок со значком свастики из Уильямса
|
||
if norm == "сверчок" and "wil_370" in fixed_path:
|
||
continue
|
||
|
||
# осьминог у свастики
|
||
if norm == "свастика" and ("осьминог" in cap or "cooper_p229" in fixed_path):
|
||
continue
|
||
|
||
# ваза у василиска
|
||
if norm == "василиск" and ("ваза" in cap or "cooper_p30" in fixed_path):
|
||
continue
|
||
|
||
# шлем у шипа
|
||
if norm == "шип" and ("шлем" in cap or "cooper_p385" in fixed_path):
|
||
continue
|
||
|
||
# триграммы у фиолетового
|
||
if norm == "фиолетовый" and "cooper_p357" in fixed_path:
|
||
continue
|
||
|
||
# бабочка у бамбука и баньяна
|
||
if norm in ("бамбук", "баньян") and "cooper_p17" in fixed_path:
|
||
continue
|
||
|
||
# Проверяем наличие файла на диске
|
||
if (ROOT / fixed_path).exists():
|
||
new_catalog.append(item)
|
||
|
||
print(f"Каталог очищен: осталось {len(new_catalog)} валидных иллюстраций (было {len(catalog)}).")
|
||
|
||
# 3. Фильтрация и нормализация в Passports
|
||
for db_name, db in [("passports", passports), ("staging", staging)]:
|
||
for pid, p in db.items():
|
||
old_ills = p.get("illustrations", [])
|
||
new_ills = []
|
||
for ill in old_ills:
|
||
raw_f = ill.get("file") or ill.get("path") or ""
|
||
fname = os.path.basename(raw_f)
|
||
if fname in blacklisted_files or raw_f in blacklisted_files:
|
||
continue
|
||
|
||
fixed_path = normalize_path(raw_f)
|
||
ill["file"] = fixed_path
|
||
if "path" in ill:
|
||
ill["path"] = fixed_path
|
||
|
||
w = p.get("word", "").lower()
|
||
cap = (ill.get("caption") or "").lower()
|
||
|
||
if w == "сверчок" and "wil_370" in fixed_path:
|
||
continue
|
||
if w == "свастика" and ("осьминог" in cap or "cooper_p229" in fixed_path):
|
||
continue
|
||
if w == "василиск" and ("ваза" in cap or "cooper_p30" in fixed_path):
|
||
continue
|
||
if w == "шип" and ("шлем" in cap or "cooper_p385" in fixed_path):
|
||
continue
|
||
if w == "фиолетовый" and "cooper_p357" in fixed_path:
|
||
continue
|
||
if w in ("бамбук", "баньян") and "cooper_p17" in fixed_path:
|
||
continue
|
||
|
||
if (ROOT / fixed_path).exists():
|
||
new_ills.append(ill)
|
||
|
||
p["illustrations"] = new_ills
|
||
|
||
# 4. Фильтрация и нормализация в External Symbols
|
||
for term, obj in external.items():
|
||
old_ills = obj.get("illustrations", [])
|
||
new_ills = []
|
||
for ill in old_ills:
|
||
raw_f = ill.get("file") or ill.get("path") or ""
|
||
fname = os.path.basename(raw_f)
|
||
if fname in blacklisted_files or raw_f in blacklisted_files:
|
||
continue
|
||
|
||
fixed_path = normalize_path(raw_f)
|
||
ill["file"] = fixed_path
|
||
if "path" in ill:
|
||
ill["path"] = fixed_path
|
||
|
||
t_lower = term.lower()
|
||
cap = (ill.get("caption") or "").lower()
|
||
|
||
if t_lower == "сверчок" and "wil_370" in fixed_path:
|
||
continue
|
||
if t_lower == "свастика" and ("осьминог" in cap or "cooper_p229" in fixed_path):
|
||
continue
|
||
if t_lower == "василиск" and ("ваза" in cap or "cooper_p30" in fixed_path):
|
||
continue
|
||
if t_lower == "шип" and ("шлем" in cap or "cooper_p385" in fixed_path):
|
||
continue
|
||
if t_lower == "фиолетовый" and "cooper_p357" in fixed_path:
|
||
continue
|
||
if t_lower in ("бамбук", "баньян") and "cooper_p17" in fixed_path:
|
||
continue
|
||
|
||
if (ROOT / fixed_path).exists():
|
||
new_ills.append(ill)
|
||
|
||
obj["illustrations"] = new_ills
|
||
|
||
# 5. Сохранение всех JSON баз
|
||
with open(CATALOG_PATH, "w", encoding="utf-8") as f:
|
||
json.dump(new_catalog, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(PASSPORTS_PATH, "w", encoding="utf-8") as f:
|
||
json.dump(passports, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(STAGING_PATH, "w", encoding="utf-8") as f:
|
||
json.dump(staging, f, ensure_ascii=False, indent=2)
|
||
|
||
with open(EXTERNAL_PATH, "w", encoding="utf-8") as f:
|
||
json.dump(external, f, ensure_ascii=False, indent=2)
|
||
|
||
print("Все JSON базы данных успешно обновлены и сохранены!")
|
||
print("=== ЗАВЕРШЕНО ===")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|