using System; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; // 앱 시작 시 캐시 총 용량을 확인하고 1GB 초과 시 LRU 순으로 자동 삭제 public class CacheManager : MonoBehaviour { private const long MaxCacheBytes = 1L * 1024 * 1024 * 1024; // 1 GB private static string CacheRoot => Path.Combine(Application.temporaryCachePath, "beatsaber"); // ── Unity ──────────────────────────────────────────────── private void Start() { RunEviction(); } // ── Public API ─────────────────────────────────────────── public long TotalCacheBytes() { if (!Directory.Exists(CacheRoot)) return 0; return Directory.GetFiles(CacheRoot, "*", SearchOption.AllDirectories) .Sum(f => new FileInfo(f).Length); } // 강제 정리 (UI에서 수동 호출용) public void RunEviction() { if (!Directory.Exists(CacheRoot)) return; long total = TotalCacheBytes(); if (total <= MaxCacheBytes) { Debug.Log($"[CacheManager] 용량 정상: {FormatBytes(total)}"); return; } // 곡 폴더를 마지막 접근 시간 오름차순 정렬 (가장 오래된 것부터) List dirs = GetSongDirs(); dirs.Sort((a, b) => a.lastAccessed.CompareTo(b.lastAccessed)); foreach (SongDirInfo dir in dirs) { if (total <= MaxCacheBytes) break; total -= dir.sizeBytes; Directory.Delete(dir.path, recursive: true); SongLibrary.Instance?.MarkSongRemoved(dir.songId); Debug.Log($"[CacheManager] LRU 삭제: {dir.songId} ({FormatBytes(dir.sizeBytes)})"); } Debug.Log($"[CacheManager] 정리 완료 → 현재 {FormatBytes(total)}"); } // ── 내부 구현 ───────────────────────────────────────────── private List GetSongDirs() { var result = new List(); foreach (string dir in Directory.GetDirectories(CacheRoot)) { long size = Directory.GetFiles(dir, "*", SearchOption.AllDirectories) .Sum(f => new FileInfo(f).Length); // 마지막 접근 시간은 SongLibrary 기록 우선, 없으면 파일시스템 참조 DateTime lastAccessed = DateTime.MaxValue; string songId = Path.GetFileName(dir); LibraryEntry entry = SongLibrary.Instance?.GetAll() .Find(e => e.songId == songId); if (entry != null && DateTime.TryParse(entry.lastAccessedAt, out DateTime t)) lastAccessed = t; else lastAccessed = Directory.GetLastAccessTimeUtc(dir); result.Add(new SongDirInfo { songId = songId, path = dir, sizeBytes = size, lastAccessed = lastAccessed }); } return result; } private static string FormatBytes(long bytes) { if (bytes >= 1024 * 1024 * 1024) return $"{bytes / (1024f * 1024 * 1024):F2} GB"; if (bytes >= 1024 * 1024) return $"{bytes / (1024f * 1024):F1} MB"; return $"{bytes / 1024f:F0} KB"; } private struct SongDirInfo { public string songId; public string path; public long sizeBytes; public DateTime lastAccessed; } }