104 lines
4.0 KiB
JavaScript
104 lines
4.0 KiB
JavaScript
// SonicForge Studio Project Storage & .sfs File Service
|
|
(function() {
|
|
const SFS_VERSION = "1.0.0";
|
|
|
|
function exportProjectToSFS(projectState) {
|
|
let projectObj = {};
|
|
if (projectState.main_session) {
|
|
projectObj = projectState;
|
|
} else {
|
|
projectObj = {
|
|
id: projectState.id || `proj_${Date.now()}`,
|
|
name: projectState.name || "Dự án mới",
|
|
tracks: (projectState.tracks || []).map(t => ({
|
|
id: t.id,
|
|
name: t.name,
|
|
startTime: t.startTime,
|
|
height: t.height,
|
|
volumeDb: t.volumeDb,
|
|
pan: t.pan,
|
|
muted: t.muted,
|
|
solo: t.solo,
|
|
color: t.color,
|
|
markers: t.markers || [],
|
|
serverFileId: t.serverFileId || null,
|
|
clips: t.clips || [],
|
|
sections: t.sections || [],
|
|
midiItems: t.midiItems || [],
|
|
channelInfo: t.channelInfo || null
|
|
}))
|
|
};
|
|
}
|
|
|
|
const sfsBundle = {
|
|
format: "SONICFORGE_STUDIO_PROJECT",
|
|
version: SFS_VERSION,
|
|
timestamp: Date.now(),
|
|
domain: window.location.origin,
|
|
project: projectObj
|
|
};
|
|
|
|
const jsonStr = JSON.stringify(sfsBundle, null, 2);
|
|
const blob = new Blob([jsonStr], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
const displayName = projectObj.metadata?.title || projectObj.name || 'project';
|
|
a.download = `${displayName.replace(/\s+/g, '_')}.sfs`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
async function importProjectFromSFSFile(file) {
|
|
const text = await file.text();
|
|
const sfsBundle = JSON.parse(text);
|
|
if (sfsBundle.format !== "SONICFORGE_STUDIO_PROJECT") {
|
|
throw new Error("Tệp tin không đúng định dạng .sfs của SonicForge Studio");
|
|
}
|
|
return sfsBundle.project;
|
|
}
|
|
|
|
let autoSaveTimer = null;
|
|
let lastGetProjectStateCallback = null;
|
|
function scheduleTempAutoSave(getProjectStateCallback) {
|
|
if (getProjectStateCallback) lastGetProjectStateCallback = getProjectStateCallback;
|
|
if (autoSaveTimer) clearTimeout(autoSaveTimer);
|
|
autoSaveTimer = setTimeout(async () => {
|
|
try {
|
|
const state = lastGetProjectStateCallback ? lastGetProjectStateCallback() : null;
|
|
if (!state || (!state.tracks && !state.main_session)) return;
|
|
const dataJson = JSON.stringify(state);
|
|
localStorage.setItem('sonic_temp_project', dataJson);
|
|
if (window.SonicAPI && localStorage.getItem('sonic_token')) {
|
|
await window.SonicAPI.saveTempProject(dataJson).catch(() => {});
|
|
}
|
|
} catch (e) {
|
|
console.warn("Auto-save temp project warning:", e);
|
|
}
|
|
}, 2000);
|
|
}
|
|
// Lưu NGAY (bỏ debounce 2s) — dùng cho thay đổi cần bền vững tức thì (đổi màu track)
|
|
async function flushTempAutoSave() {
|
|
if (autoSaveTimer) { clearTimeout(autoSaveTimer); autoSaveTimer = null; }
|
|
try {
|
|
const state = lastGetProjectStateCallback ? lastGetProjectStateCallback() : null;
|
|
if (!state || (!state.tracks && !state.main_session)) return;
|
|
const dataJson = JSON.stringify(state);
|
|
localStorage.setItem('sonic_temp_project', dataJson);
|
|
if (window.SonicAPI && localStorage.getItem('sonic_token')) {
|
|
await window.SonicAPI.saveTempProject(dataJson).catch(() => {});
|
|
}
|
|
} catch (e) {
|
|
console.warn("Flush temp project warning:", e);
|
|
}
|
|
}
|
|
|
|
window.SonicStorage = {
|
|
exportProjectToSFS,
|
|
importProjectFromSFSFile,
|
|
scheduleTempAutoSave,
|
|
flushTempAutoSave
|
|
};
|
|
})();
|