import 'dart:io'; import 'package:path/path.dart' as p; import '../../core/output_paths.dart'; import '../../l10n/tr.dart'; /// 동영상 파일 옮기기. 약속: [moveFileInto] 는 파일을 폴더 안으로 옮기고 (같은 이름이 있으면 "이름 (2).mp4") 옮긴 경로를 준다. /// 다른 드라이브 · SD 카드면 복사 후 지우며, 원본을 지우지 못하면 사본을 지우고 오류를 낸다 (두 벌이 남지 않게). /// [moveResults] 는 만든 결과물 (jj_mkv 의 이름.mkv · 이름_AI.srt · 이름_ko.srt …) 을 옮긴 동영상의 jj_mkv 로 옮기고 그 수를 준다. class VideoFiles { /// 목록에 넣은 뒤 파일이 옮겨지거나 지워졌을 때 static String get missingMessage => tr('동영상 파일이 없습니다 (옮겨졌거나 지워졌습니다). 목록에서 빼고 다시 추가하세요.'); static Future moveFileInto(String from, String dir) async { final stem = p.basenameWithoutExtension(from), ext = p.extension(from); var to = p.join(dir, p.basename(from)); for (var n = 2; File(to).existsSync(); n++) { to = p.join(dir, '$stem ($n)$ext'); } try { await File(from).rename(to); } on FileSystemException { try { await File(from).copy(to); await File(from).delete(); } catch (_) { // 원본을 지우지 못하면 (열려 있음 등) 옮긴 것이 아니다 - 방금 만든 사본을 지워 두 벌이 남지 않게 (원본은 그대로) try { if (File(from).existsSync()) await File(to).delete(); } catch (_) {} rethrow; } } return to; } /// [log]: 못 옮긴 결과물 (나머지는 계속 옮긴다) static Future moveResults(String oldVideo, String newVideo, {required void Function(String msg) log}) async { final from = outputDirFor(oldVideo), to = outputDirFor(newVideo); if (p.equals(from, to) || !Directory(from).existsSync()) return 0; final stem = p.basenameWithoutExtension(oldVideo); final mine = RegExp('^${RegExp.escape(stem)}(\\.mkv|_[A-Za-z-]+\\.(srt|ass|ssa|smi|vtt|sub))\$', caseSensitive: false); var n = 0; for (final f in Directory(from).listSync().whereType()) { if (!mine.hasMatch(p.basename(f.path))) continue; try { await Directory(to).create(recursive: true); await moveFileInto(f.path, to); n++; } catch (e) { log(trf('결과물 이동 실패: {0} ({1})', [p.basename(f.path), e])); } } return n; } }