summaryrefslogtreecommitdiff
path: root/apps/web/src/lib
diff options
context:
space:
mode:
authorryu <ryumacodes@gmail.com>2025-08-07 19:37:06 +0500
committerGitHub <noreply@github.com>2025-08-07 19:37:06 +0500
commite71788014d137a74f10420601451ddfbb84701bb (patch)
tree2c08f7fbbc7537b12935e842981830aed976ce87 /apps/web/src/lib
parent6412158003f295a350fc66800796f30c8f3c534b (diff)
parentd022a78ae2330665e7d763fdc6e831a71f3b9ea1 (diff)
downloadopencut-e71788014d137a74f10420601451ddfbb84701bb.tar.gz
Merge branch 'main' into feat/timeline-return-to-start
Diffstat (limited to 'apps/web/src/lib')
-rw-r--r--apps/web/src/lib/rate-limit.ts6
-rw-r--r--apps/web/src/lib/storage/storage-service.ts96
-rw-r--r--apps/web/src/lib/storage/types.ts2
-rw-r--r--apps/web/src/lib/waitlist.ts13
4 files changed, 101 insertions, 16 deletions
diff --git a/apps/web/src/lib/rate-limit.ts b/apps/web/src/lib/rate-limit.ts
index e1996cf5..92f70805 100644
--- a/apps/web/src/lib/rate-limit.ts
+++ b/apps/web/src/lib/rate-limit.ts
@@ -8,9 +8,9 @@ const redis = new Redis({
token: env.UPSTASH_REDIS_REST_TOKEN,
});
-export const waitlistRateLimit = new Ratelimit({
+export const baseRateLimit = new Ratelimit({
redis,
- limiter: Ratelimit.slidingWindow(5, "1 m"), // 5 requests per minute
+ limiter: Ratelimit.slidingWindow(100, "1 m"), // 100 requests per minute
analytics: true,
- prefix: "waitlist-rate-limit",
+ prefix: "rate-limit",
});
diff --git a/apps/web/src/lib/storage/storage-service.ts b/apps/web/src/lib/storage/storage-service.ts
index 0037dbdb..98001591 100644
--- a/apps/web/src/lib/storage/storage-service.ts
+++ b/apps/web/src/lib/storage/storage-service.ts
@@ -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
@@ -63,6 +72,8 @@ class StorageService {
backgroundColor: project.backgroundColor,
backgroundType: project.backgroundType,
blurIntensity: project.blurIntensity,
+ bookmarks: project.bookmarks,
+ fps: project.fps,
};
await this.projectsAdapter.set(project.id, serializedProject);
@@ -83,6 +94,8 @@ class StorageService {
backgroundColor: serializedProject.backgroundColor,
backgroundType: serializedProject.backgroundType,
blurIntensity: serializedProject.blurIntensity,
+ bookmarks: serializedProject.bookmarks,
+ fps: serializedProject.fps,
};
}
@@ -260,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();
diff --git a/apps/web/src/lib/storage/types.ts b/apps/web/src/lib/storage/types.ts
index b662c164..127b1690 100644
--- a/apps/web/src/lib/storage/types.ts
+++ b/apps/web/src/lib/storage/types.ts
@@ -30,6 +30,7 @@ export interface StorageConfig {
projectsDb: string;
mediaDb: string;
timelineDb: string;
+ savedSoundsDb: string;
version: number;
}
@@ -37,6 +38,7 @@ export interface StorageConfig {
export type SerializedProject = Omit<TProject, "createdAt" | "updatedAt"> & {
createdAt: string;
updatedAt: string;
+ bookmarks?: number[];
};
// Extend FileSystemDirectoryHandle with missing async iterator methods
diff --git a/apps/web/src/lib/waitlist.ts b/apps/web/src/lib/waitlist.ts
deleted file mode 100644
index 43a620b0..00000000
--- a/apps/web/src/lib/waitlist.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { db, sql, waitlist } from "@opencut/db";
-
-export async function getWaitlistCount() {
- try {
- const result = await db
- .select({ count: sql<number>`count(*)` })
- .from(waitlist);
- return result[0]?.count || 0;
- } catch (error) {
- console.error("Failed to fetch waitlist count:", error);
- return 0;
- }
-}