using System.Text.Json; namespace VideoDownloader.App.Browser; /// 즐겨찾기/히스토리 JSON 영속화 (%AppData%/VideoDownloader). /// #5 저장/로드 실패를 조용 삼킴하지 않고 browserstore.log 에 기록하며, /// 손상 파일은 백업 후 빈 목록을 반환(다음 저장이 원본을 덮어쓰는 데이터 손실 방지). public static class BrowserStore { private static string Dir => AppPaths.DataDir; private static string BookmarksPath => Path.Combine(Dir, "bookmarks.json"); private static string HistoryPath => Path.Combine(Dir, "history.json"); private static readonly JsonSerializerOptions JsonOpts = new() { WriteIndented = true }; public static List LoadBookmarks() { try { if (File.Exists(BookmarksPath)) return JsonSerializer.Deserialize>(File.ReadAllText(BookmarksPath)) ?? new(); } catch (Exception e) { LogLoadFail(BookmarksPath, e); } return new(); } public static void SaveBookmarks(List bookmarks) { try { Directory.CreateDirectory(Dir); File.WriteAllText(BookmarksPath, JsonSerializer.Serialize(bookmarks, JsonOpts)); } catch (Exception e) { LogFail("저장", BookmarksPath, e); } // 디스크 가득/권한/잠금 → UI 스레드 전파 대신 로그 } public static List LoadHistory() { try { if (File.Exists(HistoryPath)) return JsonSerializer.Deserialize>(File.ReadAllText(HistoryPath)) ?? new(); } catch (Exception e) { LogLoadFail(HistoryPath, e); } return new(); } public static void SaveHistory(List history) { try { Directory.CreateDirectory(Dir); File.WriteAllText(HistoryPath, JsonSerializer.Serialize(history, JsonOpts)); } catch (Exception e) { LogFail("저장", HistoryPath, e); } } /// 로드 실패(손상/권한/잠금) 시 원본을 .corrupt 백업한 뒤 로그. /// 빈 목록을 반환하더라도 원본이 남아 다음 저장이 사용자 데이터를 덮어쓰지 않게 한다. private static void LogLoadFail(string path, Exception e) { try { if (File.Exists(path)) File.Move(path, $"{path}.corrupt.{DateTime.Now:yyyyMMddHHmmss}.bak", overwrite: true); } catch { /* best-effort 백업 — 실패해도 계속 진행 */ } LogFail("로드", path, e); } private static void LogFail(string op, string path, Exception e) => Log($"{op} 실패({Path.GetFileName(path)}): {e.GetType().Name}: {e.Message}"); private static void Log(string msg) { try { Directory.CreateDirectory(Dir); File.AppendAllText(Path.Combine(Dir, "browserstore.log"), $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {msg}{Environment.NewLine}"); } catch { /* 로그마저 실패하면 조용히 */ } } }