JJ_MKVMaker/lib/app/controller/video_files.dart

58 lines
2.5 KiB
Dart

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<String> 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<int> 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<File>()) {
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;
}
}