summaryrefslogtreecommitdiff
path: root/apps/web/src/lib
diff options
context:
space:
mode:
authorZaid-maker <53424436+Zaid-maker@users.noreply.github.com>2025-06-24 16:59:44 +0500
committerZaid-maker <53424436+Zaid-maker@users.noreply.github.com>2025-06-24 16:59:44 +0500
commit62051de6c11dde40e2929c030e4418f87b137e42 (patch)
tree3492ed2abd6a127512a6ce09543bcf770bcd53d5 /apps/web/src/lib
parent7c83b8e70b2024d79f053bd40e6f633969c2c1f5 (diff)
parent900deab065ef17941262f48524af786cac302945 (diff)
downloadopencut-62051de6c11dde40e2929c030e4418f87b137e42.tar.gz
Merge branch 'main' into implement-workflows
Diffstat (limited to 'apps/web/src/lib')
-rw-r--r--apps/web/src/lib/auth-client.ts4
-rw-r--r--apps/web/src/lib/auth.ts23
-rw-r--r--apps/web/src/lib/db/index.tsx14
-rw-r--r--apps/web/src/lib/db/schema.ts69
-rw-r--r--apps/web/src/lib/fetchGhStars.ts29
-rw-r--r--apps/web/src/lib/ffmpeg-utils.ts64
6 files changed, 78 insertions, 125 deletions
diff --git a/apps/web/src/lib/auth-client.ts b/apps/web/src/lib/auth-client.ts
deleted file mode 100644
index 7c467e7e..00000000
--- a/apps/web/src/lib/auth-client.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { createAuthClient } from "better-auth/react";
-export const authClient = createAuthClient({
- baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL!,
-});
diff --git a/apps/web/src/lib/auth.ts b/apps/web/src/lib/auth.ts
deleted file mode 100644
index 4cfaa6f2..00000000
--- a/apps/web/src/lib/auth.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { betterAuth } from "better-auth";
-import { drizzleAdapter } from "better-auth/adapters/drizzle";
-import { db } from "./db";
-
-export const auth = betterAuth({
- database: drizzleAdapter(db, {
- provider: "pg",
- usePlural: true,
- }),
- secret: process.env.BETTER_AUTH_SECRET!,
- user: {
- deleteUser: {
- enabled: true,
- },
- },
- emailAndPassword: {
- enabled: true,
- },
- appName: "OpenCut",
- trustedOrigins: ["http://localhost:3000"],
-});
-
-export type Auth = typeof auth;
diff --git a/apps/web/src/lib/db/index.tsx b/apps/web/src/lib/db/index.tsx
deleted file mode 100644
index b66c6e39..00000000
--- a/apps/web/src/lib/db/index.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { drizzle } from "drizzle-orm/node-postgres";
-import { Pool } from "pg";
-import * as schema from "./schema";
-
-const pool = new Pool({
- connectionString: process.env.DATABASE_URL,
- max: 3,
- idleTimeoutMillis: 10000,
- connectionTimeoutMillis: 15000,
- query_timeout: 20000,
- statement_timeout: 20000,
-});
-
-export const db = drizzle(pool, { schema });
diff --git a/apps/web/src/lib/db/schema.ts b/apps/web/src/lib/db/schema.ts
deleted file mode 100644
index 7c38724a..00000000
--- a/apps/web/src/lib/db/schema.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
-
-export const users = pgTable("users", {
- id: text("id").primaryKey(),
- name: text("name").notNull(),
- email: text("email").notNull().unique(),
- emailVerified: boolean("email_verified")
- .$defaultFn(() => false)
- .notNull(),
- image: text("image"),
- createdAt: timestamp("created_at")
- .$defaultFn(() => /* @__PURE__ */ new Date())
- .notNull(),
- updatedAt: timestamp("updated_at")
- .$defaultFn(() => /* @__PURE__ */ new Date())
- .notNull(),
-}).enableRLS();
-
-export const sessions = pgTable("sessions", {
- id: text("id").primaryKey(),
- expiresAt: timestamp("expires_at").notNull(),
- token: text("token").notNull().unique(),
- createdAt: timestamp("created_at").notNull(),
- updatedAt: timestamp("updated_at").notNull(),
- ipAddress: text("ip_address"),
- userAgent: text("user_agent"),
- userId: text("user_id")
- .notNull()
- .references(() => users.id, { onDelete: "cascade" }),
-}).enableRLS();
-
-export const accounts = pgTable("accounts", {
- id: text("id").primaryKey(),
- accountId: text("account_id").notNull(),
- providerId: text("provider_id").notNull(),
- userId: text("user_id")
- .notNull()
- .references(() => users.id, { onDelete: "cascade" }),
- accessToken: text("access_token"),
- refreshToken: text("refresh_token"),
- idToken: text("id_token"),
- accessTokenExpiresAt: timestamp("access_token_expires_at"),
- refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
- scope: text("scope"),
- password: text("password"),
- createdAt: timestamp("created_at").notNull(),
- updatedAt: timestamp("updated_at").notNull(),
-}).enableRLS();
-
-export const verifications = pgTable("verifications", {
- id: text("id").primaryKey(),
- identifier: text("identifier").notNull(),
- value: text("value").notNull(),
- expiresAt: timestamp("expires_at").notNull(),
- createdAt: timestamp("created_at").$defaultFn(
- () => /* @__PURE__ */ new Date()
- ),
- updatedAt: timestamp("updated_at").$defaultFn(
- () => /* @__PURE__ */ new Date()
- ),
-}).enableRLS();
-
-export const waitlist = pgTable("waitlist", {
- id: text("id").primaryKey(),
- email: text("email").notNull().unique(),
- createdAt: timestamp("created_at")
- .$defaultFn(() => /* @__PURE__ */ new Date())
- .notNull(),
-}).enableRLS();
diff --git a/apps/web/src/lib/fetchGhStars.ts b/apps/web/src/lib/fetchGhStars.ts
new file mode 100644
index 00000000..e0236840
--- /dev/null
+++ b/apps/web/src/lib/fetchGhStars.ts
@@ -0,0 +1,29 @@
+export async function getStars(): Promise<string> {
+ try {
+ const res = await fetch(
+ "https://api.github.com/repos/OpenCut-app/OpenCut",
+ {
+ next: { revalidate: 3600 },
+ }
+ );
+
+ if (!res.ok) {
+ throw new Error(`GitHub API error: ${res.status} ${res.statusText}`);
+ }
+ const data = await res.json();
+ const count = data.stargazers_count;
+
+ if (typeof count !== "number") {
+ throw new Error("Invalid stargazers_count from GitHub API");
+ }
+
+ if (count >= 1_000_000)
+ return (count / 1_000_000).toFixed(1).replace(/\.0$/, "") + "M";
+ if (count >= 1_000)
+ return (count / 1_000).toFixed(1).replace(/\.0$/, "") + "k";
+ return count.toString();
+ } catch (error) {
+ console.error("Failed to fetch GitHub stars:", error);
+ return "1.5k";
+ }
+}
diff --git a/apps/web/src/lib/ffmpeg-utils.ts b/apps/web/src/lib/ffmpeg-utils.ts
index 56085a21..ae0c267b 100644
--- a/apps/web/src/lib/ffmpeg-utils.ts
+++ b/apps/web/src/lib/ffmpeg-utils.ts
@@ -102,26 +102,60 @@ export const getVideoInfo = async (videoFile: File): Promise<{
fps: number;
}> => {
const ffmpeg = await initFFmpeg();
-
+
const inputName = 'input.mp4';
-
+
// Write input file
await ffmpeg.writeFile(inputName, new Uint8Array(await videoFile.arrayBuffer()));
-
- // Get video info
- await ffmpeg.exec(['-i', inputName, '-f', 'null', '-']);
-
- // Note: In a real implementation, you'd parse the FFmpeg output
- // For now, we'll return default values and enhance this later
-
+
+ // Capture FFmpeg stderr output with a one-time listener pattern
+ let ffmpegOutput = '';
+ let listening = true;
+ const listener = (data: string) => {
+ if (listening) ffmpegOutput += data;
+ };
+ ffmpeg.on('log', ({ message }) => listener(message));
+
+ // Run ffmpeg to get info (stderr will contain the info)
+ try {
+ await ffmpeg.exec(['-i', inputName, '-f', 'null', '-']);
+ } catch (error) {
+ listening = false;
+ await ffmpeg.deleteFile(inputName);
+ console.error('FFmpeg execution failed:', error);
+ throw new Error('Failed to extract video info. The file may be corrupted or in an unsupported format.');
+ }
+
+ // Disable listener after exec completes
+ listening = false;
+
// Cleanup
await ffmpeg.deleteFile(inputName);
-
+
+ // Parse output for duration, resolution, and fps
+ // Example: Duration: 00:00:10.00, start: 0.000000, bitrate: 1234 kb/s
+ // Example: Stream #0:0: Video: h264 (High), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 30 fps, 30 tbr, 90k tbn, 60 tbc
+
+ const durationMatch = ffmpegOutput.match(/Duration: (\d+):(\d+):([\d.]+)/);
+ let duration = 0;
+ if (durationMatch) {
+ const [, h, m, s] = durationMatch;
+ duration = parseInt(h) * 3600 + parseInt(m) * 60 + parseFloat(s);
+ }
+
+ const videoStreamMatch = ffmpegOutput.match(/Video:.* (\d+)x(\d+)[^,]*, ([\d.]+) fps/);
+ let width = 0, height = 0, fps = 0;
+ if (videoStreamMatch) {
+ width = parseInt(videoStreamMatch[1]);
+ height = parseInt(videoStreamMatch[2]);
+ fps = parseFloat(videoStreamMatch[3]);
+ }
+
return {
- duration: 10, // Placeholder - would parse from FFmpeg output
- width: 1920, // Placeholder
- height: 1080, // Placeholder
- fps: 30 // Placeholder
+ duration,
+ width,
+ height,
+ fps
};
};
@@ -194,4 +228,4 @@ export const extractAudio = async (
await ffmpeg.deleteFile(outputName);
return blob;
-}; \ No newline at end of file
+}; \ No newline at end of file