비트 찍기 완료 및 클로드를 통한 api작업
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user