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