JJ_MKVMaker/lib/app/controller/video_list_share.dart

75 lines
2.2 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
/// 동영상 목록 저장 · 창끼리 공유. 목록 (경로) 을 파일 하나에 적어 두고, 다시 켜면 그대로 불러오며, 창이 여러 개면
/// 1초마다 파일을 보고 다른 창에서 넣거나 지운 것을 따라 한다.
/// 약속: [save] 는 [paths] 가 바뀌었을 때만 임시 파일 → 이름 바꾸기로 쓴다 (다른 창이 반쯤 쓴 파일을 보지 않게).
/// [sync] 는 파일이 바뀌었으면 원하는 목록을 [apply] 에 넘긴다 (그동안 [save] 는 쉬고, 끝나면 한 번 다시 적는다).
class VideoListShare {
/// 지금 목록의 경로들
final List<String> Function() paths;
/// 파일에 적힌 목록에 맞춘다 (다른 창이 바꾼 것)
final Future<void> Function(List<String> want) apply;
VideoListShare({required this.paths, required this.apply});
String? _file;
String _saved = '[]';
Timer? _timer;
bool _syncing = false;
/// 저장 · 공유 시작 ([file] 을 먼저 불러온다)
Future<void> start(String file) async {
_file = file;
await sync();
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (_) => sync());
}
void stop() {
_timer?.cancel();
_timer = null;
}
void save() {
final file = _file;
if (file == null || _syncing) return;
final text = jsonEncode(paths());
if (text == _saved) return;
_saved = text;
try {
final tmp = File('$file.$pid.tmp')..writeAsStringSync(text, flush: true);
tmp.renameSync(file);
} catch (_) {}
}
Future<void> sync() async {
final file = _file;
if (file == null || _syncing) return;
String text;
try {
final f = File(file);
if (!f.existsSync()) return;
text = f.readAsStringSync();
} catch (_) {
return;
}
if (text == _saved) return;
List<String> want;
try {
want = (jsonDecode(text) as List).cast<String>();
} catch (_) {
return;
}
_syncing = true;
try {
_saved = text;
await apply(want);
} finally {
_syncing = false;
save(); // 없는 파일을 뺐거나 맞추는 동안 이 창에서 바꾼 것이 있으면 다시 적는다
}
}
}