// SonicForge Studio API Service window.API_BASE_URL = window.API_BASE_URL || window.location.origin; (function() { function getAuthToken() { return localStorage.getItem('sonic_token') || ''; } function getAuthHeaders() { const token = getAuthToken(); return { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }; } async function apiRequest(endpoint, options = {}) { const url = `${window.API_BASE_URL}${endpoint}`; const headers = { ...getAuthHeaders(), ...options.headers }; const response = await fetch(url, { ...options, headers }); if (response.status === 401) { localStorage.removeItem('sonic_token'); localStorage.removeItem('sonic_user'); } const data = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(data.detail || data.message || 'Lỗi kết nối API Server'); } return data; } window.SonicAPI = { login: (username, password) => apiRequest('/api/v1/auth/login', { method: 'POST', body: JSON.stringify({ username, password }) }), register: (username, email, password) => apiRequest('/api/v1/auth/register', { method: 'POST', body: JSON.stringify({ username, email, password }) }), changePassword: (old_password, new_password) => apiRequest('/api/v1/auth/change-password', { method: 'POST', body: JSON.stringify({ old_password, new_password }) }), getProfile: () => apiRequest('/api/v1/auth/profile', { method: 'GET' }), listUsers: () => apiRequest('/api/v1/admin/users', { method: 'GET' }), updateUserQuota: (userId, storageLimitMb, maxTracks = 16) => apiRequest(`/api/v1/admin/quotas/${userId}`, { method: 'PUT', body: JSON.stringify({ storage_limit_mb: storageLimitMb, max_tracks: maxTracks }) }), updateUserRole: (userId, role, isActive = true) => apiRequest(`/api/v1/admin/users/${userId}/role`, { method: 'PUT', body: JSON.stringify({ role, is_active: isActive }) }), deleteUser: (userId) => apiRequest(`/api/v1/admin/users/${userId}`, { method: 'DELETE' }), createUser: (username, email, password, role = 'standard') => apiRequest('/api/v1/admin/users', { method: 'POST', body: JSON.stringify({ username, email, password, role }) }), saveTempProject: (dataJson) => apiRequest('/api/v1/projects/temp', { method: 'POST', body: JSON.stringify({ data_json: dataJson }) }), getTempProject: () => apiRequest('/api/v1/projects/temp', { method: 'GET' }), saveCloudProject: (name, dataJson) => apiRequest('/api/v1/projects/cloud', { method: 'POST', body: JSON.stringify({ name, data_json: dataJson }) }), listCloudProjects: () => apiRequest('/api/v1/projects/cloud', { method: 'GET' }), getCloudProject: (projectId) => apiRequest(`/api/v1/projects/cloud/${projectId}`, { method: 'GET' }), deleteCloudProject: (projectId) => apiRequest(`/api/v1/projects/cloud/${projectId}`, { method: 'DELETE' }), updateCloudProject: (projectId, name, dataJson) => apiRequest(`/api/v1/projects/cloud/${projectId}`, { method: 'PUT', body: JSON.stringify({ name, data_json: dataJson }) }), listMyFiles: (activeFileIds) => apiRequest('/api/v1/audio/my-files', { method: 'POST', body: JSON.stringify({ active_file_ids: activeFileIds }) }), deleteMyFile: (fileId) => apiRequest(`/api/v1/audio/my-files/${fileId}`, { method: 'DELETE' }), aiScan: (trackId, fileId, minLoopDuration = 2.0, maxLoopDuration = 6.0) => apiRequest('/api/v1/audio/ai-scan', { method: 'POST', body: JSON.stringify({ track_id: trackId, file_id: fileId, min_loop_duration: minLoopDuration, max_loop_duration: maxLoopDuration }) }), aiCut: (sourceTrackId, fileId, selectionStart, selectionEnd) => apiRequest('/api/v1/audio/ai-cut', { method: 'POST', body: JSON.stringify({ source_track_id: sourceTrackId, file_id: fileId, selection_start: selectionStart, selection_end: selectionEnd }) }), runPythonTool: (toolType, trackId, fileId, timePos = 0.0, freq = 440.0, duration = 2.0, waveType = "sine") => apiRequest('/api/v1/audio/python-tool', { method: 'POST', body: JSON.stringify({ tool_type: toolType, track_id: trackId, file_id: fileId, time_pos: timePos, freq: freq, duration: duration, wave_type: waveType }) }), getAIConfigs: () => apiRequest('/api/v1/user/config/ai', { method: 'GET' }), saveAIConfigs: (providers) => apiRequest('/api/v1/user/config/ai', { method: 'POST', body: JSON.stringify({ providers }) }), getPreferences: () => apiRequest('/api/v1/user/preferences', { method: 'GET' }), savePreferences: (prefs) => apiRequest('/api/v1/user/preferences', { method: 'POST', body: JSON.stringify({ preferences: prefs }) }), listPlugins: () => apiRequest('/api/v1/plugins/available', { method: 'GET' }), getSoundfontCatalog: () => apiRequest('/api/v1/plugins/soundfonts/catalog', { method: 'GET' }), listDefaultSoundfonts: () => apiRequest('/api/v1/plugins/default-soundfonts', { method: 'GET' }), listSoundfontInstruments: (sfId) => apiRequest(`/api/v1/plugins/soundfont-instruments/${sfId}`, { method: 'GET' }), getAIPresets: () => apiRequest('/api/v1/ai/presets', { method: 'GET' }), saveAIPreset: (preset) => apiRequest('/api/v1/ai/presets', { method: 'POST', body: JSON.stringify(preset) }), deleteAIPreset: (presetId) => apiRequest(`/api/v1/ai/presets/${presetId}`, { method: 'DELETE' }), renderProject: (projectJson, outputFilename) => apiRequest('/api/v1/plugins/render', { method: 'POST', body: JSON.stringify({ project_json: projectJson, output_filename: outputFilename }) }), deleteSoundFont: (sfId) => apiRequest(`/api/v1/plugins/soundfont/${sfId}`, { method: 'DELETE' }), uploadSoundFont: async (file) => { const formData = new FormData(); formData.append('file', file); const token = localStorage.getItem('sonic_token') || ''; const resp = await fetch(`${window.API_BASE_URL}/api/v1/plugins/upload-soundfont`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}` }, body: formData }); if (!resp.ok) { const err = await resp.json().catch(() => ({})); throw new Error(err.detail || 'Upload failed'); } return resp.json(); } }; })();