fix: missing media files when renaming + saving the project
This commit is contained in:
@@ -7,13 +7,14 @@ import { OPFS_CONSTANTS } from '../../constants/coreConstants';
|
||||
export class KGAudioFileStorage {
|
||||
/**
|
||||
* Store an audio file in the project's media/ directory.
|
||||
* Creates the project and media directories if they don't exist yet.
|
||||
*/
|
||||
public static async storeAudioFile(
|
||||
projectName: string,
|
||||
fileId: string,
|
||||
file: File
|
||||
): Promise<void> {
|
||||
const mediaDir = await KGAudioFileStorage.getMediaDir(projectName);
|
||||
const mediaDir = await KGAudioFileStorage.getOrCreateMediaDir(projectName);
|
||||
const fileHandle = await mediaDir.getFileHandle(fileId, { create: true });
|
||||
const writable = await fileHandle.createWritable();
|
||||
await writable.write(await file.arrayBuffer());
|
||||
@@ -61,7 +62,8 @@ export class KGAudioFileStorage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the media directory handle for a project.
|
||||
* Get the media directory handle for an existing project (read/delete path).
|
||||
* Does NOT create directories — fails if project folder doesn't exist.
|
||||
*/
|
||||
private static async getMediaDir(projectName: string): Promise<FileSystemDirectoryHandle> {
|
||||
const root = await navigator.storage.getDirectory();
|
||||
@@ -69,4 +71,15 @@ export class KGAudioFileStorage {
|
||||
const projectDir = await projectsDir.getDirectoryHandle(projectName);
|
||||
return projectDir.getDirectoryHandle(OPFS_CONSTANTS.MEDIA_DIR, { create: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create the media directory handle for a project (write path).
|
||||
* Creates project and media directories if they don't exist.
|
||||
*/
|
||||
private static async getOrCreateMediaDir(projectName: string): Promise<FileSystemDirectoryHandle> {
|
||||
const root = await navigator.storage.getDirectory();
|
||||
const projectsDir = await root.getDirectoryHandle(OPFS_CONSTANTS.ROOT_DIR, { create: true });
|
||||
const projectDir = await projectsDir.getDirectoryHandle(projectName, { create: true });
|
||||
return projectDir.getDirectoryHandle(OPFS_CONSTANTS.MEDIA_DIR, { create: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,10 +206,31 @@ export class KGProjectStorage {
|
||||
project.setName(newName);
|
||||
await this.save(newName, project, false);
|
||||
|
||||
// Copy media files from old to new location
|
||||
await this.copyMediaFiles(oldName, newName);
|
||||
|
||||
// Delete old location
|
||||
await this.delete(oldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a project under a new name, migrating media files from the old folder.
|
||||
* Used when the user renames the project and saves. Handles the case where the
|
||||
* old folder doesn't exist yet (new project never saved).
|
||||
*/
|
||||
public async saveWithRename(oldName: string, newName: string, data: KGProject): Promise<void> {
|
||||
this.ensureInitialized();
|
||||
|
||||
// Save project JSON to the new folder
|
||||
await this.save(newName, data, false);
|
||||
|
||||
// Migrate media files only if the old folder exists
|
||||
if (await this.exists(oldName)) {
|
||||
await this.copyMediaFiles(oldName, newName);
|
||||
await this.delete(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export a project folder as a zip Blob (.kgstudio bundle).
|
||||
* Includes project.json, meta.json, and all files in media/.
|
||||
@@ -374,6 +395,42 @@ export class KGProjectStorage {
|
||||
return candidate;
|
||||
}
|
||||
|
||||
// --- Media migration ---
|
||||
|
||||
/**
|
||||
* Copy all files from projects/<fromName>/media/ to projects/<toName>/media/.
|
||||
* If the source media directory doesn't exist, returns without error.
|
||||
*/
|
||||
private async copyMediaFiles(fromName: string, toName: string): Promise<void> {
|
||||
try {
|
||||
const fromDir = await this.projectsDirHandle!.getDirectoryHandle(fromName);
|
||||
let fromMedia: FileSystemDirectoryHandle;
|
||||
try {
|
||||
fromMedia = await fromDir.getDirectoryHandle(OPFS_CONSTANTS.MEDIA_DIR);
|
||||
} catch {
|
||||
// No media directory in source — nothing to copy
|
||||
return;
|
||||
}
|
||||
|
||||
const toDir = await this.projectsDirHandle!.getDirectoryHandle(toName);
|
||||
const toMedia = await toDir.getDirectoryHandle(OPFS_CONSTANTS.MEDIA_DIR, { create: true });
|
||||
|
||||
for await (const entry of fromMedia.values()) {
|
||||
if (entry.kind === 'file') {
|
||||
const fileHandle = entry as FileSystemFileHandle;
|
||||
const file = await fileHandle.getFile();
|
||||
const newHandle = await toMedia.getFileHandle(entry.name, { create: true });
|
||||
const writable = await newHandle.createWritable();
|
||||
await writable.write(await file.arrayBuffer());
|
||||
await writable.close();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error copying media files from "${fromName}" to "${toName}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// --- File I/O helpers ---
|
||||
|
||||
private async writeFile(
|
||||
|
||||
Reference in New Issue
Block a user