feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets

This commit is contained in:
2026-10-09 15:26:58 +05:00
parent 7f91366201
commit 0b12e4583b
244 changed files with 611461 additions and 1617 deletions
+162
View File
@@ -0,0 +1,162 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
robust_transfer_with_status.py
==============================
Надежный перенос данных со смартфона с живым выводом строки состояния на Рабочий стол:
- /home/alexives/Desktop/ПРОГРЕСС_ПЕРЕНОСА.txt (подробный вид)
- /home/alexives/Desktop/ПРОГРЕСС_СТРОКА.txt (однострочный вид)
- Музыка и аудиокниги НЕ трогаются (остаются на телефоне).
"""
import os
import sys
import subprocess
import time
from pathlib import Path
DEST_ROOT = Path("/mnt/data/архив_с_телефона")
DESKTOP_FULL = Path("/home/alexives/Desktop/ПРОГРЕСС_ПЕРЕНОСА.txt")
DESKTOP_LINE = Path("/home/alexives/Desktop/ПРОГРЕСС_СТРОКА.txt")
LOG_FILE = DEST_ROOT / "transfer_log.txt"
TARGET_FOLDERS = [
("Download", "/storage/emulated/0/Download", DEST_ROOT / "Download", 17.0),
("футажи", "/storage/emulated/0/футажи", DEST_ROOT / "футажи", 2.3),
("Pictures", "/storage/emulated/0/Pictures", DEST_ROOT / "Pictures", 1.4),
("DCIM/MyAlbums", "/storage/emulated/0/DCIM/MyAlbums", DEST_ROOT / "DCIM/MyAlbums", 59.0),
("DCIM/Camera", "/storage/emulated/0/DCIM/Camera", DEST_ROOT / "DCIM/Camera", 16.0),
]
TOTAL_TARGET_GB = sum(t[3] for t in TARGET_FOLDERS)
def log(msg: str):
t_str = time.strftime("[%Y-%m-%d %H:%M:%S]")
line = f"{t_str} {msg}"
print(line, flush=True)
with open(LOG_FILE, "a", encoding="utf-8") as f:
f.write(line + "\n")
def get_dir_size_gb(path: Path) -> float:
if not path.exists():
return 0.0
try:
res = subprocess.run(["du", "-sb", str(path)], capture_output=True, text=True, check=True)
return int(res.stdout.split()[0]) / (1024 ** 3)
except Exception:
return 0.0
def make_bar(percent: float, length: int = 25) -> str:
filled = int(round(length * percent / 100))
filled = max(0, min(length, filled))
return "█" * filled + "░" * (length - filled)
def update_status(curr_folder: str, speed_mb: float = 0.0):
total_copied_gb = 0.0
folder_sizes = {}
for name, _, dst_path, _ in TARGET_FOLDERS:
sz = get_dir_size_gb(dst_path)
folder_sizes[name] = sz
total_copied_gb += sz
percent = min(100.0, (total_copied_gb / TOTAL_TARGET_GB) * 100)
bar = make_bar(percent, 25)
now_str = time.strftime("%H:%M:%S")
rem_gb = max(0.0, TOTAL_TARGET_GB - total_copied_gb)
eta_min = (rem_gb * 1024 / speed_mb / 60) if speed_mb > 1.0 else 0
full_report = [
"=" * 68,
" 📱 СТАТУС ПЕРЕНОСА АРХИВА СО СМАРТФОНА",
"=" * 68,
f"Прогресс: [{bar}] {percent:.1f}%",
f"Объём: {total_copied_gb:.2f} ГБ из ~{TOTAL_TARGET_GB:.1f} ГБ",
f"Скорость: {speed_mb:.1f} МБ/сек",
f"Осталось: ~{eta_min:.0f} мин." if eta_min > 0 else "Осталось: расчёт...",
f"Текущая: «{curr_folder}»",
"-" * 68,
"📂 Статус папок:",
]
for name, _, _, tgt in TARGET_FOLDERS:
sz = folder_sizes.get(name, 0.0)
if sz >= tgt * 0.98:
st = "[ГОТОВО]"
elif sz > 0:
st = "[КОПИРУЕТСЯ...]"
else:
st = "[В ОЧЕРЕДИ]"
full_report.append(f" • {name:<14} {st:<16} {sz:.2f} ГБ / {tgt:.1f} ГБ")
full_report.append("-" * 68)
full_report.append(" (Музыка и аудиокниги оставлены на телефоне)")
full_report.append(f"Обновлено: {now_str}")
full_report.append("=" * 68)
one_line = f"[{bar}] {percent:.1f}% | {total_copied_gb:.1f}/{TOTAL_TARGET_GB:.1f} ГБ | {speed_mb:.1f} МБ/с | ETA: ~{eta_min:.0f}м | Папка: {curr_folder} ({now_str})\n"
try:
with open(DESKTOP_FULL, "w", encoding="utf-8") as f:
f.write("\n".join(full_report) + "\n")
with open(DESKTOP_LINE, "w", encoding="utf-8") as f:
f.write(one_line)
except Exception:
pass
def ensure_adb():
subprocess.run(["adb", "start-server"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def main():
log("=== ЗАПУСК ПЕРЕНОСА ДАННЫХ С МОНИТОРИНГОМ НА РАБОЧЕМ СТОЛЕ ===")
start_time = time.time()
last_speed_time = time.time()
last_copied_gb = 0.0
update_status("Инициализация...")
for idx, (name, src_path, dst_path, tgt_gb) in enumerate(TARGET_FOLDERS, 1):
dst_path.parent.mkdir(parents=True, exist_ok=True)
log(f"[{idx}/{len(TARGET_FOLDERS)}] Копирование «{name}»...")
# Запускаем adb pull в фоне с мониторингом
ensure_adb()
cmd = ["adb", "-s", "3aeea825", "pull", src_path, str(dst_path.parent)]
proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, text=True)
speed_mb = 35.0
while proc.poll() is None:
time.sleep(3)
now = time.time()
dt = now - last_speed_time
if dt >= 3.0:
current_gb = sum(get_dir_size_gb(t[2]) for t in TARGET_FOLDERS)
if last_copied_gb > 0 and current_gb >= last_copied_gb:
speed_mb = (current_gb - last_copied_gb) * 1024 / dt
last_copied_gb = current_gb
last_speed_time = now
update_status(name, speed_mb)
# Завершение папки
err = proc.stderr.read()
if proc.returncode == 0:
log(f"-> Папка «{name}» успешно скопирована!")
else:
log(f"-> Папка «{name}» завершилась с кодом {proc.returncode}: {err.strip()[:150]}")
# Авто-перезапуск adb если отвалился
ensure_adb()
update_status(name, 0.0)
total_time = (time.time() - start_time) / 60
log(f"=== ВСЕ ПАПКИ УСПЕШНО ПЕРЕНЕСЕНЫ за {total_time:.1f} минут! ===")
update_status("ЗАВЕРШЕНО НА 100%", 0.0)
try:
subprocess.run(["notify-send", "Архив с телефона", "Все выбранные данные успешно перенесены на компьютер!"])
except Exception:
pass
if __name__ == "__main__":
main()