75 lines
2.2 KiB
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(); // 없는 파일을 뺐거나 맞추는 동안 이 창에서 바꾼 것이 있으면 다시 적는다
|
|
}
|
|
}
|
|
}
|