using System.Text.Json; namespace VideoDownloader.Mobile; public sealed record OfflineItem(string Id, string FileName, long SizeBytes); /// /// 폰 오프라인 저장(U4): 라이브러리 항목을 앱 전용 폴더에 저장·목록·삭제. /// manifest.json(id→파일명)으로 서버 항목과 매핑한다. /// public sealed class OfflineStore { private readonly string _dir; private readonly string _manifestPath; private readonly object _gate = new(); private Dictionary _manifest; /// baseDir 아래 offline/ 폴더 사용(호스트가 앱 데이터 디렉터리 주입). public OfflineStore(string baseDir) { _dir = Path.Combine(baseDir, "offline"); _manifestPath = Path.Combine(_dir, "manifest.json"); try { if (File.Exists(_manifestPath)) _manifest = JsonSerializer.Deserialize>(File.ReadAllText(_manifestPath)) ?? new(); } catch { } _manifest ??= new Dictionary(); } public string Directory => _dir; public string PathFor(string id) => Path.Combine(_dir, id + Path.GetExtension(_manifest.GetValueOrDefault(id, ".mp4"))); public bool Exists(string id) { lock (_gate) { var p = PathFor(id); return File.Exists(p) && _manifest.ContainsKey(id); } } /// 다운로드 완료 후 등록. public void Record(string id, string fileName) { lock (_gate) { System.IO.Directory.CreateDirectory(_dir); _manifest[id] = fileName; Save(); } } public void Delete(string id) { lock (_gate) { try { if (File.Exists(PathFor(id))) File.Delete(PathFor(id)); } catch { } _manifest.Remove(id); Save(); } } public List List() { lock (_gate) return _manifest.Select(kv => { var p = PathFor(kv.Key); return new OfflineItem(kv.Key, kv.Value, File.Exists(p) ? new FileInfo(p).Length : 0); }).Where(i => i.SizeBytes > 0).ToList(); } private void Save() { try { System.IO.Directory.CreateDirectory(_dir); File.WriteAllText(_manifestPath, JsonSerializer.Serialize(_manifest)); } catch { } }}