feat: sound effects functionality with freesound's api

This commit is contained in:
Maze Winther
2025-08-04 01:30:33 +02:00
parent c0651fec19
commit 48b694bbd8
18 changed files with 1457 additions and 45 deletions
@@ -9,9 +9,11 @@ import {
TimelineData,
} from "./types";
import { TimelineTrack } from "@/types/timeline";
import { SavedSoundsData, SavedSound, SoundEffect } from "@/types/sounds";
class StorageService {
private projectsAdapter: IndexedDBAdapter<SerializedProject>;
private savedSoundsAdapter: IndexedDBAdapter<SavedSoundsData>;
private config: StorageConfig;
constructor() {
@@ -19,6 +21,7 @@ class StorageService {
projectsDb: "video-editor-projects",
mediaDb: "video-editor-media",
timelineDb: "video-editor-timelines",
savedSoundsDb: "video-editor-saved-sounds",
version: 1,
};
@@ -27,6 +30,12 @@ class StorageService {
"projects",
this.config.version
);
this.savedSoundsAdapter = new IndexedDBAdapter<SavedSoundsData>(
this.config.savedSoundsDb,
"saved-sounds",
this.config.version
);
}
// Helper to get project-specific media adapters
@@ -264,6 +273,89 @@ class StorageService {
};
}
async loadSavedSounds(): Promise<SavedSoundsData> {
try {
const savedSoundsData = await this.savedSoundsAdapter.get("user-sounds");
return (
savedSoundsData || {
sounds: [],
lastModified: new Date().toISOString(),
}
);
} catch (error) {
console.error("Failed to load saved sounds:", error);
return { sounds: [], lastModified: new Date().toISOString() };
}
}
async saveSoundEffect(soundEffect: SoundEffect): Promise<void> {
try {
const currentData = await this.loadSavedSounds();
// Check if sound is already saved
if (currentData.sounds.some((sound) => sound.id === soundEffect.id)) {
return; // Already saved
}
const savedSound: SavedSound = {
id: soundEffect.id,
name: soundEffect.name,
username: soundEffect.username,
previewUrl: soundEffect.previewUrl,
downloadUrl: soundEffect.downloadUrl,
duration: soundEffect.duration,
tags: soundEffect.tags,
license: soundEffect.license,
savedAt: new Date().toISOString(),
};
const updatedData: SavedSoundsData = {
sounds: [...currentData.sounds, savedSound],
lastModified: new Date().toISOString(),
};
await this.savedSoundsAdapter.set("user-sounds", updatedData);
} catch (error) {
console.error("Failed to save sound effect:", error);
throw error;
}
}
async removeSavedSound(soundId: number): Promise<void> {
try {
const currentData = await this.loadSavedSounds();
const updatedData: SavedSoundsData = {
sounds: currentData.sounds.filter((sound) => sound.id !== soundId),
lastModified: new Date().toISOString(),
};
await this.savedSoundsAdapter.set("user-sounds", updatedData);
} catch (error) {
console.error("Failed to remove saved sound:", error);
throw error;
}
}
async isSoundSaved(soundId: number): Promise<boolean> {
try {
const currentData = await this.loadSavedSounds();
return currentData.sounds.some((sound) => sound.id === soundId);
} catch (error) {
console.error("Failed to check if sound is saved:", error);
return false;
}
}
async clearSavedSounds(): Promise<void> {
try {
await this.savedSoundsAdapter.remove("user-sounds");
} catch (error) {
console.error("Failed to clear saved sounds:", error);
throw error;
}
}
// Check browser support
isOPFSSupported(): boolean {
return OPFSAdapter.isSupported();
+1
View File
@@ -30,6 +30,7 @@ export interface StorageConfig {
projectsDb: string;
mediaDb: string;
timelineDb: string;
savedSoundsDb: string;
version: number;
}