Files
999/scripts/robust_transfer_with_status.py

163 lines
6.4 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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()