// API 基地址 —— 独立 FastAPI 后端(配置见 src/config.js,可用 window.__DPM_API__ 覆盖) import { API_BASE as BASE } from '../config'; export const API_BASE = BASE; async function request(url, options = {}) { const res = await fetch(`${BASE}${url}`, { headers: { 'Content-Type': 'application/json' }, ...options, }); return res.json(); } function formEncode(data) { return Object.entries(data) .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`) .join('&'); } // ============ Auth ============ export async function login(username, password) { const res = await fetch(`${BASE}/api/login`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formEncode({ username, password }), }); return res.json(); } // ============ Settings ============ export async function getSettings() { const res = await fetch(`${BASE}/api/settings`); return res.json(); } export async function updateSettings(data) { return request('/api/settings', { method: 'POST', body: JSON.stringify(data), }); } // ============ Media Files ============ export async function getMediaFiles() { const res = await fetch(`${BASE}/media`); return res.json(); } export async function uploadFiles(files) { for (const file of files) { const fd = new FormData(); fd.append('file', file); const res = await fetch(`${BASE}/upload`, { method: 'POST', body: fd }); if (!res.ok) throw new Error(`上传失败 (${res.status})`); } } export async function uploadFilesWithProgress(files, onProgress) { for (let i = 0; i < files.length; i++) { const file = files[i]; await new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('POST', `${BASE}/upload`); xhr.upload.onprogress = (e) => { if (e.lengthComputable) { onProgress({ percent: Math.round((e.loaded / e.total) * 100), loaded: e.loaded, total: e.total, fileName: file.name, current: i + 1, total: files.length, }); } }; xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(); } else { reject(new Error(`上传失败 (${xhr.status})`)); } }; xhr.onerror = () => reject(new Error('网络错误,请检查连接')); xhr.ontimeout = () => reject(new Error('上传超时')); const fd = new FormData(); fd.append('file', file); xhr.send(fd); }); } } export async function addUrlMedia(url) { return request('/api/media/add-url', { method: 'POST', body: JSON.stringify({ url }), }); } export async function deleteMedia(path) { return request('/api/delete', { method: 'POST', body: JSON.stringify({ path }), }); } // ============ Playlist ============ export async function getPlaylist() { const res = await fetch(`${BASE}/api/playlist`); return res.json(); } export async function addToPlaylist(path) { return request('/api/playlist/add', { method: 'POST', body: JSON.stringify({ path }), }); } export async function removeFromPlaylist(path) { return request('/api/playlist/remove', { method: 'POST', body: JSON.stringify({ path }), }); } // ============ Playback Control ============ export async function sendControl(action) { return request('/api/control', { method: 'POST', body: JSON.stringify({ action }), }); } export async function getState() { const res = await fetch(`${BASE}/api/state`); return res.json(); } export async function updateState(state) { return request('/api/state', { method: 'POST', body: JSON.stringify({ state }), }); } // ============ Display Commands ============ export async function sendDisplayCommand(action) { return request('/api/display-command', { method: 'POST', body: JSON.stringify({ action }), }); }