비트 찍기 완료 및 클로드를 통한 api작업
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
// Synology DSM File Station API를 통해 NAS에 파일 업로드 및 songs.json 갱신
|
||||
public class NasPublisher : MonoBehaviour
|
||||
{
|
||||
[Header("NAS 접속 정보")]
|
||||
[SerializeField] private string nasBaseUrl = "http://192.168.55.3:5000"; // DSM 포트 (내부망)
|
||||
[SerializeField] private string nasAccount = "admin";
|
||||
[SerializeField] private string nasPassword = ""; // Inspector에서 입력
|
||||
[SerializeField] private string nasRootPath = "/web/beatsaber"; // NAS 내 절대경로
|
||||
|
||||
[Header("정적 서버 URL (songs.json 읽기용)")]
|
||||
[SerializeField] private string staticBaseUrl = "http://whdwo798.synology.me:8180/beatsaber";
|
||||
|
||||
private string _sid = ""; // DSM 세션 ID
|
||||
|
||||
// ── Public API ───────────────────────────────────────────
|
||||
|
||||
public IEnumerator Publish(
|
||||
SongInfo song,
|
||||
string audioPath,
|
||||
Dictionary<string, List<NoteData>> maps,
|
||||
Action<float> onProgress,
|
||||
Action onComplete,
|
||||
Action<string> onError)
|
||||
{
|
||||
// 1단계: DSM 로그인
|
||||
yield return Login(onError);
|
||||
if (string.IsNullOrEmpty(_sid)) yield break;
|
||||
onProgress?.Invoke(0.1f);
|
||||
|
||||
// 2단계: 오디오 업로드
|
||||
yield return UploadFile(
|
||||
audioPath,
|
||||
$"{nasRootPath}/music",
|
||||
$"{song.id}.mp3",
|
||||
onError);
|
||||
onProgress?.Invoke(0.4f);
|
||||
|
||||
// 3단계: 각 난이도 맵 JSON 업로드
|
||||
int total = maps.Count;
|
||||
int done = 0;
|
||||
|
||||
foreach (var kv in maps)
|
||||
{
|
||||
string fileName = $"Map_{song.id}_{kv.Key}.json";
|
||||
string json = BeatSageConverter.ToMapJson(kv.Value);
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
// 파일명에 맞춰 DifficultyInfo 업데이트
|
||||
AssignMapFile(song, kv.Key, fileName);
|
||||
|
||||
yield return UploadBytes(
|
||||
bytes, fileName,
|
||||
$"{nasRootPath}/maps",
|
||||
onError);
|
||||
|
||||
done++;
|
||||
onProgress?.Invoke(0.4f + (float)done / total * 0.3f);
|
||||
}
|
||||
|
||||
// 4단계: songs.json 다운로드 → 항목 추가 → 재업로드
|
||||
yield return PatchSongsJson(song, onError);
|
||||
onProgress?.Invoke(0.95f);
|
||||
|
||||
// 5단계: 로그아웃
|
||||
yield return Logout();
|
||||
|
||||
onProgress?.Invoke(1f);
|
||||
onComplete?.Invoke();
|
||||
Debug.Log($"[NasPublisher] '{song.title}' NAS 업로드 완료");
|
||||
}
|
||||
|
||||
// ── DSM 인증 ─────────────────────────────────────────────
|
||||
|
||||
private IEnumerator Login(Action<string> onError)
|
||||
{
|
||||
string url = $"{nasBaseUrl}/webapi/auth.cgi" +
|
||||
$"?api=SYNO.API.Auth&version=3&method=login" +
|
||||
$"&account={UnityWebRequest.EscapeURL(nasAccount)}" +
|
||||
$"&passwd={UnityWebRequest.EscapeURL(nasPassword)}" +
|
||||
$"&session=FileStation&format=sid";
|
||||
|
||||
using var req = UnityWebRequest.Get(url);
|
||||
yield return req.SendWebRequest();
|
||||
|
||||
if (req.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
onError?.Invoke($"DSM 로그인 실패: {req.error}");
|
||||
yield break;
|
||||
}
|
||||
|
||||
_sid = ParseSid(req.downloadHandler.text);
|
||||
if (string.IsNullOrEmpty(_sid))
|
||||
onError?.Invoke("DSM sid 파싱 실패 — 계정 정보를 확인하세요");
|
||||
}
|
||||
|
||||
private IEnumerator Logout()
|
||||
{
|
||||
string url = $"{nasBaseUrl}/webapi/auth.cgi" +
|
||||
$"?api=SYNO.API.Auth&version=1&method=logout&session=FileStation&_sid={_sid}";
|
||||
using var req = UnityWebRequest.Get(url);
|
||||
yield return req.SendWebRequest();
|
||||
_sid = "";
|
||||
}
|
||||
|
||||
// ── 파일 업로드 ───────────────────────────────────────────
|
||||
|
||||
private IEnumerator UploadFile(string localPath, string nasFolder,
|
||||
string fileName, Action<string> onError)
|
||||
{
|
||||
byte[] bytes = File.ReadAllBytes(localPath);
|
||||
yield return UploadBytes(bytes, fileName, nasFolder, onError);
|
||||
}
|
||||
|
||||
private IEnumerator UploadBytes(byte[] bytes, string fileName,
|
||||
string nasFolder, Action<string> onError)
|
||||
{
|
||||
string url = $"{nasBaseUrl}/webapi/entry.cgi";
|
||||
|
||||
var form = new List<IMultipartFormSection>
|
||||
{
|
||||
new MultipartFormDataSection("api", "SYNO.FileStation.Upload"),
|
||||
new MultipartFormDataSection("version", "2"),
|
||||
new MultipartFormDataSection("method", "upload"),
|
||||
new MultipartFormDataSection("path", nasFolder),
|
||||
new MultipartFormDataSection("overwrite", "true"),
|
||||
new MultipartFormDataSection("_sid", _sid),
|
||||
new MultipartFormFileSection("file", bytes, fileName, "application/octet-stream"),
|
||||
};
|
||||
|
||||
using var req = UnityWebRequest.Post(url, form);
|
||||
yield return req.SendWebRequest();
|
||||
|
||||
if (req.result != UnityWebRequest.Result.Success)
|
||||
onError?.Invoke($"업로드 실패({fileName}): {req.error}");
|
||||
else
|
||||
Debug.Log($"[NasPublisher] 업로드 완료: {fileName}");
|
||||
}
|
||||
|
||||
// ── songs.json 패치 ───────────────────────────────────────
|
||||
|
||||
private IEnumerator PatchSongsJson(SongInfo newSong, Action<string> onError)
|
||||
{
|
||||
// 현재 songs.json 가져오기 (정적 서버에서 읽음)
|
||||
SongsList songsList = null;
|
||||
|
||||
using (var req = UnityWebRequest.Get($"{staticBaseUrl}/songs.json"))
|
||||
{
|
||||
yield return req.SendWebRequest();
|
||||
|
||||
if (req.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
songsList = JsonUtility.FromJson<SongsList>(req.downloadHandler.text);
|
||||
}
|
||||
}
|
||||
|
||||
if (songsList == null)
|
||||
songsList = new SongsList { version = "1.0", songs = new System.Collections.Generic.List<SongInfo>() };
|
||||
|
||||
// 같은 id가 이미 있으면 교체, 없으면 추가
|
||||
int existingIdx = songsList.songs.FindIndex(s => s.id == newSong.id);
|
||||
if (existingIdx >= 0)
|
||||
songsList.songs[existingIdx] = newSong;
|
||||
else
|
||||
songsList.songs.Add(newSong);
|
||||
|
||||
// 수정된 songs.json 업로드
|
||||
byte[] jsonBytes = Encoding.UTF8.GetBytes(JsonUtility.ToJson(songsList, true));
|
||||
yield return UploadBytes(jsonBytes, "songs.json", nasRootPath, onError);
|
||||
}
|
||||
|
||||
// ── 유틸 ─────────────────────────────────────────────────
|
||||
|
||||
private static string ParseSid(string json)
|
||||
{
|
||||
const string key = "\"sid\":\"";
|
||||
int start = json.IndexOf(key, StringComparison.Ordinal);
|
||||
if (start < 0) return null;
|
||||
start += key.Length;
|
||||
int end = json.IndexOf('"', start);
|
||||
return end > start ? json.Substring(start, end - start) : null;
|
||||
}
|
||||
|
||||
private static void AssignMapFile(SongInfo song, string difficulty, string fileName)
|
||||
{
|
||||
var info = song.difficulties.Get(difficulty);
|
||||
if (info != null) info.mapFile = $"maps/{fileName}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user