releases/VideoDownloader.Browser/TabArchive.cs

63 lines
2 KiB
C#

using System.Text.Json;
namespace VideoDownloader.Browser;
public sealed record ArchivedTab(string Title, string Url, DateTime ClosedAt);
/// <summary>T3-2: 탭 아카이브 — 닫힘 이력 영속(최대 500, 같은 URL 연속은 제목 갱신), 검색·복구 지원.</summary>
public sealed class TabArchive
{
private const int Cap = 500;
private readonly string _path;
private readonly object _gate = new();
private List<ArchivedTab> _items;
public TabArchive(string path)
{
_path = path;
try
{
if (File.Exists(path))
_items = JsonSerializer.Deserialize<List<ArchivedTab>>(File.ReadAllText(path)) ?? new();
}
catch { }
_items ??= new List<ArchivedTab>();
}
public void Add(string title, string url)
{
if (string.IsNullOrWhiteSpace(url)) return;
lock (_gate)
{
_items.RemoveAll(t => t.Url.Equals(url, StringComparison.OrdinalIgnoreCase));
_items.Insert(0, new ArchivedTab(title, url, DateTime.Now));
if (_items.Count > Cap) _items.RemoveRange(Cap, _items.Count - Cap);
try
{
Directory.CreateDirectory(Path.GetDirectoryName(_path)!);
File.WriteAllText(_path, JsonSerializer.Serialize(_items));
}
catch { }
}
}
public List<ArchivedTab> Search(string query)
{
lock (_gate)
{
var q = query?.Trim() ?? "";
return _items.Where(t => q.Length == 0 ||
t.Title.Contains(q, StringComparison.OrdinalIgnoreCase) ||
t.Url.Contains(q, StringComparison.OrdinalIgnoreCase)).ToList();
}
}
public void Remove(string url)
{
lock (_gate)
{
_items.RemoveAll(t => t.Url.Equals(url, StringComparison.OrdinalIgnoreCase));
try { File.WriteAllText(_path, JsonSerializer.Serialize(_items)); } catch { }
}
}
}