#!/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()