148 lines
5.0 KiB
C#
148 lines
5.0 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
public class DownloadManager : MonoBehaviour
|
|
{
|
|
[SerializeField] private string baseUrl = "http://whdwo798.synology.me:8180/beatsaber";
|
|
|
|
private static string CacheRoot => Path.Combine(Application.temporaryCachePath, "beatsaber");
|
|
|
|
// ── Public API ───────────────────────────────────────────
|
|
|
|
public void FetchSongsList(Action<SongsList> onSuccess, Action<string> onError = null)
|
|
{
|
|
StartCoroutine(GetText($"{baseUrl}/songs.json", json =>
|
|
{
|
|
SongsList list = JsonUtility.FromJson<SongsList>(json);
|
|
if (list == null)
|
|
onError?.Invoke("songs.json 파싱 실패");
|
|
else
|
|
onSuccess?.Invoke(list);
|
|
}, onError));
|
|
}
|
|
|
|
// 오디오 + 선택 난이도 맵 다운로드
|
|
public void DownloadSong(SongInfo song, string difficulty,
|
|
Action<float> onProgress, Action onComplete, Action<string> onError = null)
|
|
{
|
|
StartCoroutine(DownloadSongCoroutine(song, difficulty, onProgress, onComplete, onError));
|
|
}
|
|
|
|
public void DeleteSong(string songId)
|
|
{
|
|
string dir = SongDir(songId);
|
|
if (Directory.Exists(dir))
|
|
{
|
|
Directory.Delete(dir, recursive: true);
|
|
Debug.Log($"[DownloadManager] 삭제: {songId}");
|
|
}
|
|
}
|
|
|
|
public void DeleteDifficulty(SongInfo song, string difficulty)
|
|
{
|
|
string path = MapPath(song, difficulty);
|
|
if (path != null && File.Exists(path))
|
|
File.Delete(path);
|
|
}
|
|
|
|
public bool IsSongDownloaded(string songId)
|
|
=> File.Exists(AudioPath(songId));
|
|
|
|
public bool IsDifficultyDownloaded(SongInfo song, string difficulty)
|
|
{
|
|
string path = MapPath(song, difficulty);
|
|
return path != null && File.Exists(path);
|
|
}
|
|
|
|
// Spawner에서 재생 경로를 얻을 때 사용
|
|
public string AudioPath(string songId)
|
|
=> Path.Combine(SongDir(songId), $"{songId}.mp3");
|
|
|
|
public string MapPath(SongInfo song, string difficulty)
|
|
{
|
|
DifficultyInfo info = song.difficulties.Get(difficulty);
|
|
if (info == null) return null;
|
|
return Path.Combine(SongDir(song.id), Path.GetFileName(info.mapFile));
|
|
}
|
|
|
|
// ── 내부 구현 ─────────────────────────────────────────────
|
|
|
|
private IEnumerator DownloadSongCoroutine(SongInfo song, string difficulty,
|
|
Action<float> onProgress, Action onComplete, Action<string> onError)
|
|
{
|
|
Directory.CreateDirectory(SongDir(song.id));
|
|
|
|
// 1단계: 오디오 (70%)
|
|
string audioPath = AudioPath(song.id);
|
|
if (!File.Exists(audioPath))
|
|
{
|
|
bool failed = false;
|
|
yield return DownloadFile(
|
|
$"{baseUrl}/{song.audioFile}", audioPath,
|
|
p => onProgress?.Invoke(p * 0.7f),
|
|
err => { onError?.Invoke(err); failed = true; });
|
|
if (failed) yield break;
|
|
}
|
|
|
|
// 2단계: 맵 파일 (30%)
|
|
DifficultyInfo diffInfo = song.difficulties.Get(difficulty);
|
|
if (diffInfo == null)
|
|
{
|
|
onError?.Invoke($"난이도 '{difficulty}' 없음");
|
|
yield break;
|
|
}
|
|
|
|
string mapPath = MapPath(song, difficulty);
|
|
if (!File.Exists(mapPath))
|
|
{
|
|
bool failed = false;
|
|
yield return DownloadFile(
|
|
$"{baseUrl}/{diffInfo.mapFile}", mapPath,
|
|
p => onProgress?.Invoke(0.7f + p * 0.3f),
|
|
err => { onError?.Invoke(err); failed = true; });
|
|
if (failed) yield break;
|
|
}
|
|
|
|
onProgress?.Invoke(1f);
|
|
onComplete?.Invoke();
|
|
Debug.Log($"[DownloadManager] 완료: {song.title} ({difficulty})");
|
|
}
|
|
|
|
private IEnumerator DownloadFile(string url, string savePath,
|
|
Action<float> onProgress, Action<string> onError)
|
|
{
|
|
using var req = UnityWebRequest.Get(url);
|
|
req.downloadHandler = new DownloadHandlerFile(savePath);
|
|
req.SendWebRequest();
|
|
|
|
while (!req.isDone)
|
|
{
|
|
onProgress?.Invoke(req.downloadProgress);
|
|
yield return null;
|
|
}
|
|
|
|
if (req.result != UnityWebRequest.Result.Success)
|
|
{
|
|
if (File.Exists(savePath)) File.Delete(savePath);
|
|
onError?.Invoke($"다운로드 실패: {url} — {req.error}");
|
|
}
|
|
}
|
|
|
|
private IEnumerator GetText(string url, Action<string> onSuccess, Action<string> onError)
|
|
{
|
|
using var req = UnityWebRequest.Get(url);
|
|
yield return req.SendWebRequest();
|
|
|
|
if (req.result != UnityWebRequest.Result.Success)
|
|
onError?.Invoke($"요청 실패: {url} — {req.error}");
|
|
else
|
|
onSuccess?.Invoke(req.downloadHandler.text);
|
|
}
|
|
|
|
private static string SongDir(string songId)
|
|
=> Path.Combine(CacheRoot, songId);
|
|
}
|