diff --git a/AI_RULES.md b/AI_RULES.md deleted file mode 100644 index 99f8cfb..0000000 --- a/AI_RULES.md +++ /dev/null @@ -1,23 +0,0 @@ -# Tech Stack - -- You are building a React application -- Use TypeScript. -- Use React Router. KEEP the routes in src/App.tsx -- Always put source code in the src folder. -- Put pages into src/pages/ -- Put components into src/components/ -- The main page (default page) is src/pages/Index.tsx -- UPDATE the main page to include the new components. OTHERWISE, the user can NOT see any components! -- ALWAYS try to use the shadcn/ui library. -- Tailwind CSS: always use Tailwind CSS for styling components. Utilize Tailwind classes extensively for layout, spacing, colors, and other design aspects. - -Github Commiting: - -DO NOT ADD [dyad] to commits when commiting to github - -Available packages and libraries: - -- The lucide-react package is installed for icons. -- You ALREADY have ALL the shadcn/ui components and their dependencies installed. So you don't need to install them again. -- You have ALL the necessary Radix UI components installed. -- Use prebuilt components from the shadcn/ui library after importing them. Note that these files shouldn't be edited, so make new components if you need to change them. diff --git a/api/deleteAccount.js b/api/deleteAccount.js new file mode 100644 index 0000000..c4c7eac --- /dev/null +++ b/api/deleteAccount.js @@ -0,0 +1,97 @@ +import { createClient } from '@supabase/supabase-js'; + +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type, Authorization', +}; + +export default async function handler(req) { + if (req.method === 'OPTIONS') { + return new Response(null, { status: 204, headers: corsHeaders }); + } + + if (req.method !== 'POST') { + return new Response(JSON.stringify({ error: 'Method not allowed' }), { + status: 405, + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + }); + } + + try { + // Get the authorization header from the request + const authHeader = req.headers.authorization || req.headers.get?.('authorization'); + + if (!authHeader || !authHeader.startsWith('Bearer ')) { + return new Response(JSON.stringify({ error: 'Missing or invalid authorization header' }), { + status: 401, + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + }); + } + + const accessToken = authHeader.replace('Bearer ', ''); + + // Create a client with the user's access token to verify their identity + const supabaseUrl = process.env.VITE_SUPABASE_URL || process.env.SUPABASE_URL; + const supabaseAnonKey = process.env.VITE_SUPABASE_ANON_KEY || process.env.SUPABASE_ANON_KEY; + + // Check for Supabase secret key (service role) under various common names + const supabaseSecretKey = process.env.SUPABASE_SECRET_KEY + || process.env.SUPABASE_SERVICE_ROLE_KEY + || process.env.SUPABASE_SERVICE_ROLE_SECRET; + + if (!supabaseUrl || !supabaseAnonKey) { + throw new Error('Supabase configuration missing'); + } + + if (!supabaseSecretKey) { + throw new Error('Supabase secret key not configured. Set SUPABASE_SECRET_KEY in your environment.'); + } + + // First, verify the user's token and get their user ID + const userClient = createClient(supabaseUrl, supabaseAnonKey, { + global: { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }, + }); + + const { data: { user }, error: userError } = await userClient.auth.getUser(); + + if (userError || !user) { + return new Response(JSON.stringify({ error: 'Invalid or expired session' }), { + status: 401, + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + }); + } + + // Now use the admin client with secret key to delete the user + const adminClient = createClient(supabaseUrl, supabaseSecretKey, { + auth: { + autoRefreshToken: false, + persistSession: false, + }, + }); + + const { error: deleteError } = await adminClient.auth.admin.deleteUser(user.id); + + if (deleteError) { + console.error('Delete user error:', deleteError); + throw new Error(deleteError.message || 'Failed to delete account'); + } + + return new Response(JSON.stringify({ success: true, message: 'Account deleted successfully' }), { + status: 200, + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + }); + + } catch (error) { + console.error('Account deletion error:', error); + const message = error instanceof Error ? error.message : 'Failed to delete account'; + return new Response(JSON.stringify({ error: message }), { + status: 500, + headers: { ...corsHeaders, 'Content-Type': 'application/json' }, + }); + } +} diff --git a/changelog.md b/changelog.md deleted file mode 100644 index d90d73d..0000000 --- a/changelog.md +++ /dev/null @@ -1,40 +0,0 @@ -# Oh! Renderdragon V2 - -![Static Badge](https://img.shields.io/badge/By-Codersoft-green?style=flat&link=https%3A%2F%2Fs0.renderdragon.org%2Fdocs) - -This update made me tired! We have made alot of changes in this update. New tools easter eggs and much more.... - -## Community Assets - -This update was requested alot and it is here... - -Allowing you to upload your assets to renderdragon to let other people on RendeDragon use your assets. This will allow to showcase your work or designs make yourself popular and allows you to get in the spotlight - -**CATCH: The file upload limit is only 20mb, but you can use direct links to bypass that limit** - -## s0 - -s0 is a API powered by renderdragon. It allows you to block scammers on your freelancing website or your discord server both through server. - -It got a list of more than 200+ Scammers ready to get blocked/banned from your website or discord server - -## AI Titles - -This feature is a badass the far one of the most requested and awesome to setup. NGL but this is a hit! It creates SEO friendly titles always! Just don't forget to don't get lazy on the prompting, The better the prompt the better you will be able to rank your video #1 - -## Youtube Tools - -A Powerful to see a video public analytics and download it's thumbnail. - -## Submitting your assets - -We have made a feauture, where you can upload assets/resources to get uploaded -on the official renderdragon assets list. - -### Bug fixes/Small features - -- Fixed name tag generator, generating in the wrong font. -- Fixed resource page annoying bug when select a category it, it displays "No Resources found" error for just a second -- Removed Load more button -- Changed API for Player renderer to get more easter eggs and more posses maybe...??? -- REINCARNATED the whole UI for guides diff --git a/index.html b/index.html index 6428785..3abba9a 100644 --- a/index.html +++ b/index.html @@ -1,48 +1,42 @@ - - - - - Renderdragon - Minecraft Content Creator Tools & Assets - - - - - - - - - - - - - - - - - - - - + + + + + + Renderdragon - Minecraft Content Creator Tools & Assets + + + + + + + + + + + + + + + + + + + + - - + + + + +
+ + - -
- - \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 11d6dc9..93637e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,7 +83,7 @@ "js-cookie": "^3.0.5", "kbar": "^0.1.0-beta.46", "motion": "^12.18.1", - "next": "^15.3.2", + "next": "15.3.6", "next-themes": "^0.3.0", "openai": "^4.103.0", "pixelarticons": "^1.8.1", @@ -1715,15 +1715,15 @@ ] }, "node_modules/@next/env": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.4.tgz", - "integrity": "sha512-ZkdYzBseS6UjYzz6ylVKPOK+//zLWvD6Ta+vpoye8cW11AjiQjGYVibF0xuvT4L0iJfAPfZLFidaEzAOywyOAQ==", + "version": "15.3.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.6.tgz", + "integrity": "sha512-/cK+QPcfRbDZxmI/uckT4lu9pHCfRIPBLqy88MhE+7Vg5hKrEYc333Ae76dn/cw2FBP2bR/GoK/4DU+U7by/Nw==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.4.tgz", - "integrity": "sha512-z0qIYTONmPRbwHWvpyrFXJd5F9YWLCsw3Sjrzj2ZvMYy9NPQMPZ1NjOJh4ojr4oQzcGYwgJKfidzehaNa1BpEg==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.5.tgz", + "integrity": "sha512-lM/8tilIsqBq+2nq9kbTW19vfwFve0NR7MxfkuSUbRSgXlMQoJYg+31+++XwKVSXk4uT23G2eF/7BRIKdn8t8w==", "cpu": [ "arm64" ], @@ -1737,9 +1737,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.4.tgz", - "integrity": "sha512-Z0FYJM8lritw5Wq+vpHYuCIzIlEMjewG2aRkc3Hi2rcbULknYL/xqfpBL23jQnCSrDUGAo/AEv0Z+s2bff9Zkw==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.5.tgz", + "integrity": "sha512-WhwegPQJ5IfoUNZUVsI9TRAlKpjGVK0tpJTL6KeiC4cux9774NYE9Wu/iCfIkL/5J8rPAkqZpG7n+EfiAfidXA==", "cpu": [ "x64" ], @@ -1753,9 +1753,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.4.tgz", - "integrity": "sha512-l8ZQOCCg7adwmsnFm8m5q9eIPAHdaB2F3cxhufYtVo84pymwKuWfpYTKcUiFcutJdp9xGHC+F1Uq3xnFU1B/7g==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.5.tgz", + "integrity": "sha512-LVD6uMOZ7XePg3KWYdGuzuvVboxujGjbcuP2jsPAN3MnLdLoZUXKRc6ixxfs03RH7qBdEHCZjyLP/jBdCJVRJQ==", "cpu": [ "arm64" ], @@ -1769,9 +1769,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.4.tgz", - "integrity": "sha512-wFyZ7X470YJQtpKot4xCY3gpdn8lE9nTlldG07/kJYexCUpX1piX+MBfZdvulo+t1yADFVEuzFfVHfklfEx8kw==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.5.tgz", + "integrity": "sha512-k8aVScYZ++BnS2P69ClK7v4nOu702jcF9AIHKu6llhHEtBSmM2zkPGl9yoqbSU/657IIIb0QHpdxEr0iW9z53A==", "cpu": [ "arm64" ], @@ -1785,9 +1785,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.4.tgz", - "integrity": "sha512-gEbH9rv9o7I12qPyvZNVTyP/PWKqOp8clvnoYZQiX800KkqsaJZuOXkWgMa7ANCCh/oEN2ZQheh3yH8/kWPSEg==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.5.tgz", + "integrity": "sha512-2xYU0DI9DGN/bAHzVwADid22ba5d/xrbrQlr2U+/Q5WkFUzeL0TDR963BdrtLS/4bMmKZGptLeg6282H/S2i8A==", "cpu": [ "x64" ], @@ -1801,9 +1801,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.4.tgz", - "integrity": "sha512-Cf8sr0ufuC/nu/yQ76AnarbSAXcwG/wj+1xFPNbyNo8ltA6kw5d5YqO8kQuwVIxk13SBdtgXrNyom3ZosHAy4A==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.5.tgz", + "integrity": "sha512-TRYIqAGf1KCbuAB0gjhdn5Ytd8fV+wJSM2Nh2is/xEqR8PZHxfQuaiNhoF50XfY90sNpaRMaGhF6E+qjV1b9Tg==", "cpu": [ "x64" ], @@ -1817,9 +1817,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.4.tgz", - "integrity": "sha512-ay5+qADDN3rwRbRpEhTOreOn1OyJIXS60tg9WMYTWCy3fB6rGoyjLVxc4dR9PYjEdR2iDYsaF5h03NA+XuYPQQ==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.5.tgz", + "integrity": "sha512-h04/7iMEUSMY6fDGCvdanKqlO1qYvzNxntZlCzfE8i5P0uqzVQWQquU1TIhlz0VqGQGXLrFDuTJVONpqGqjGKQ==", "cpu": [ "arm64" ], @@ -1833,9 +1833,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.4.tgz", - "integrity": "sha512-4kDt31Bc9DGyYs41FTL1/kNpDeHyha2TC0j5sRRoKCyrhNcfZ/nRQkAUlF27mETwm8QyHqIjHJitfcza2Iykfg==", + "version": "15.3.5", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.5.tgz", + "integrity": "sha512-5fhH6fccXxnX2KhllnGhkYMndhOiLOLEiVGYjP2nizqeGWkN10sA9taATlXwake2E2XMvYZjjz0Uj7T0y+z1yw==", "cpu": [ "x64" ], @@ -9581,12 +9581,13 @@ } }, "node_modules/next": { - "version": "15.3.4", - "resolved": "https://registry.npmjs.org/next/-/next-15.3.4.tgz", - "integrity": "sha512-mHKd50C+mCjam/gcnwqL1T1vPx/XQNFlXqFIVdgQdVAFY9iIQtY0IfaVflEYzKiqjeA7B0cYYMaCrmAYFjs4rA==", + "version": "15.3.6", + "resolved": "https://registry.npmjs.org/next/-/next-15.3.6.tgz", + "integrity": "sha512-oI6D1zbbsh6JzzZFDCSHnnx6Qpvd1fSkVJu/5d8uluqnxzuoqtodVZjYvNovooznUq8udSAiKp7MbwlfZ8Gm6w==", + "deprecated": "This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details.", "license": "MIT", "dependencies": { - "@next/env": "15.3.4", + "@next/env": "15.3.6", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -9601,14 +9602,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.3.4", - "@next/swc-darwin-x64": "15.3.4", - "@next/swc-linux-arm64-gnu": "15.3.4", - "@next/swc-linux-arm64-musl": "15.3.4", - "@next/swc-linux-x64-gnu": "15.3.4", - "@next/swc-linux-x64-musl": "15.3.4", - "@next/swc-win32-arm64-msvc": "15.3.4", - "@next/swc-win32-x64-msvc": "15.3.4", + "@next/swc-darwin-arm64": "15.3.5", + "@next/swc-darwin-x64": "15.3.5", + "@next/swc-linux-arm64-gnu": "15.3.5", + "@next/swc-linux-arm64-musl": "15.3.5", + "@next/swc-linux-x64-gnu": "15.3.5", + "@next/swc-linux-x64-musl": "15.3.5", + "@next/swc-win32-arm64-msvc": "15.3.5", + "@next/swc-win32-x64-msvc": "15.3.5", "sharp": "^0.34.1" }, "peerDependencies": { diff --git a/package.json b/package.json index 20f0aba..fb51d7f 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@distube/ytdl-core": "^4.16.12", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", + "@fontsource/geist-mono": "^5.2.7", + "@fontsource/geist-sans": "^5.2.5", "@google/genai": "^0.13.0", "@hcaptcha/react-hcaptcha": "^1.12.0", "@headlessui/react": "^2.2.4", @@ -81,12 +83,14 @@ "embla-carousel-react": "^8.6.0", "express": "^5.1.0", "ffmpeg-static": "^5.2.0", + "file-saver": "^2.0.5", "fluent-ffmpeg": "^2.1.3", "framer-motion": "^12.10.5", "gl-matrix": "^3.4.4", "html2canvas": "^1.4.1", "input-otp": "^1.4.2", "js-cookie": "^3.0.5", + "jszip": "^3.10.1", "kbar": "^0.1.0-beta.46", "motion": "^12.18.1", "next": "15.3.6", @@ -115,6 +119,7 @@ "tailwindcss-animate": "^1.0.7", "uploadthing": "^7.7.4", "vaul": "^0.9.9", + "video.js": "^8.23.4", "wavesurfer.js": "^7.9.5", "yt-dlp-wrap": "^2.3.12", "zod": "^3.24.4" @@ -122,6 +127,7 @@ "devDependencies": { "@eslint/js": "^9.26.0", "@tailwindcss/typography": "^0.5.16", + "@types/file-saver": "^2.0.7", "@types/node": "^22.15.17", "@types/react": "^18.3.21", "@types/react-dom": "^18.3.7", @@ -143,4 +149,4 @@ "@swc/core", "@vercel/speed-insights" ] -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f39c55..7e04305 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,6 +17,12 @@ importers: '@dnd-kit/sortable': specifier: ^10.0.0 version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1) + '@fontsource/geist-mono': + specifier: ^5.2.7 + version: 5.2.7 + '@fontsource/geist-sans': + specifier: ^5.2.5 + version: 5.2.5 '@google/genai': specifier: ^0.13.0 version: 0.13.0 @@ -209,6 +215,9 @@ importers: ffmpeg-static: specifier: ^5.2.0 version: 5.2.0 + file-saver: + specifier: ^2.0.5 + version: 2.0.5 fluent-ffmpeg: specifier: ^2.1.3 version: 2.1.3 @@ -227,6 +236,9 @@ importers: js-cookie: specifier: ^3.0.5 version: 3.0.5 + jszip: + specifier: ^3.10.1 + version: 3.10.1 kbar: specifier: ^0.1.0-beta.46 version: 0.1.0-beta.48(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -311,6 +323,9 @@ importers: vaul: specifier: ^0.9.9 version: 0.9.9(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + video.js: + specifier: ^8.23.4 + version: 8.23.4 wavesurfer.js: specifier: ^7.9.5 version: 7.11.0 @@ -327,6 +342,9 @@ importers: '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.19(tailwindcss@3.4.18) + '@types/file-saver': + specifier: ^2.0.7 + version: 2.0.7 '@types/node': specifier: ^22.15.17 version: 22.18.11 @@ -649,6 +667,12 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@fontsource/geist-mono@5.2.7': + resolution: {integrity: sha512-xVPVFISJg/K0VVd+aQN0Y7X/sw9hUcJPyDWFJ5GpyU3bHELhoRsJkPSRSHXW32mOi0xZCUQDOaPj1sqIFJ1FGg==} + + '@fontsource/geist-sans@5.2.5': + resolution: {integrity: sha512-anllOHyJbElRs9fV15TeDRqAeb1IKm4bSknPl6ZMoyPTx1BBy7logudcUwpNjmQLkzn4Q0JGQLRCUKJYoyST6A==} + '@google/genai@0.13.0': resolution: {integrity: sha512-eaEncWt875H7046T04mOpxpHJUM+jLIljEf+5QctRyOeChylE/nhpwm1bZWTRWoOu/t46R9r+PmgsJFhTpE7tQ==} engines: {node: '>=18.0.0'} @@ -1947,6 +1971,9 @@ packages: '@types/express@5.0.3': resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} + '@types/file-saver@2.0.7': + resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -2168,11 +2195,28 @@ packages: '@vercel/static-config@3.1.2': resolution: {integrity: sha512-2d+TXr6K30w86a+WbMbGm2W91O0UzO5VeemZYBBUJbCjk/5FLLGIi8aV6RS2+WmaRvtcqNTn2pUA7nCOK3bGcQ==} + '@videojs/http-streaming@3.17.2': + resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==} + engines: {node: '>=8', npm: '>=5'} + peerDependencies: + video.js: ^8.19.0 + + '@videojs/vhs-utils@4.1.1': + resolution: {integrity: sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==} + engines: {node: '>=8', npm: '>=5'} + + '@videojs/xhr@2.7.0': + resolution: {integrity: sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==} + '@vitejs/plugin-react-swc@3.11.0': resolution: {integrity: sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==} peerDependencies: vite: ^4 || ^5 || ^6 || ^7 + '@xmldom/xmldom@0.8.11': + resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} + engines: {node: '>=10.0.0'} + abbrev@3.0.1: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} @@ -2204,6 +2248,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + aes-decrypter@4.0.2: + resolution: {integrity: sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -2478,6 +2525,9 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.5: resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} engines: {node: '>= 0.10'} @@ -2600,6 +2650,9 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dom-walk@0.1.2: + resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + dotenv@16.6.1: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} @@ -2931,6 +2984,9 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-saver@2.0.5: + resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} + file-selector@0.6.0: resolution: {integrity: sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==} engines: {node: '>= 12'} @@ -3056,6 +3112,9 @@ packages: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} hasBin: true + global@4.4.0: + resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -3162,6 +3221,9 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -3218,6 +3280,9 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-function@1.0.2: + resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -3240,6 +3305,9 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -3279,6 +3347,9 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + jwa@2.0.1: resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} @@ -3298,6 +3369,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -3325,6 +3399,9 @@ packages: lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + m3u8-parser@7.2.0: + resolution: {integrity: sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==} + m3u8stream@0.8.6: resolution: {integrity: sha512-LZj8kIVf9KCphiHmH7sbFQTVe4tOemb202fWwvJwR9W5ENW/1hxJN6ksAWGhQgSBSa3jyWhnjKU1Fw1GaOdbyA==} engines: {node: '>=12'} @@ -3500,6 +3577,9 @@ packages: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} + min-document@2.19.2: + resolution: {integrity: sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==} + miniget@4.2.3: resolution: {integrity: sha512-SjbDPDICJ1zT+ZvQwK0hUcRY4wxlhhNpHL9nJOB2MEAXRGagTljsO8MEDzQMTFf0Q8g4QNi8P9lEm/g7e+qgzA==} engines: {node: '>=12'} @@ -3544,6 +3624,10 @@ packages: react-dom: optional: true + mpd-parser@1.3.1: + resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==} + hasBin: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -3561,6 +3645,11 @@ packages: multipasta@0.2.7: resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} + mux.js@7.1.0: + resolution: {integrity: sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==} + engines: {node: '>=8', npm: '>=5'} + hasBin: true + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -3585,6 +3674,7 @@ packages: next@15.3.6: resolution: {integrity: sha512-oI6D1zbbsh6JzzZFDCSHnnx6Qpvd1fSkVJu/5d8uluqnxzuoqtodVZjYvNovooznUq8udSAiKp7MbwlfZ8Gm6w==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/security-update-2025-12-11 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -3696,6 +3786,9 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -3766,6 +3859,10 @@ packages: pixelarticons@1.8.1: resolution: {integrity: sha512-4taoDCleft9RtzVHLA73VDnRBwJNqlwbW8ShO6S0G9b+bM5ArGe1MVFW9xpromuPvQgVUYCSjRxNAQuNtADqyA==} + pkcs7@1.0.4: + resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==} + hasBin: true + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -3829,6 +3926,13 @@ packages: resolution: {integrity: sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==} engines: {node: '>=10'} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + progress@2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -4029,6 +4133,9 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -4099,6 +4206,9 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -4124,6 +4234,9 @@ packages: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} @@ -4206,6 +4319,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} @@ -4512,6 +4628,21 @@ packages: victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} + video.js@8.23.4: + resolution: {integrity: sha512-qI0VTlYmKzEqRsz1Nppdfcaww4RSxZAq77z2oNSl3cNg2h6do5C8Ffl0KqWQ1OpD8desWXsCrde7tKJ9gGTEyQ==} + + videojs-contrib-quality-levels@4.1.0: + resolution: {integrity: sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==} + engines: {node: '>=16', npm: '>=8'} + peerDependencies: + video.js: ^8 + + videojs-font@4.2.0: + resolution: {integrity: sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==} + + videojs-vtt.js@0.15.5: + resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==} + vite-plugin-sitemap@0.7.1: resolution: {integrity: sha512-4NRTkiWytLuAmcikckrLcLl9iYA20+5v6l8XshcOrzxH1WR8H0O3S6sTQYfjMrE8su/LG6Y0cTodvOdcOIxaLw==} @@ -4854,6 +4985,10 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@fontsource/geist-mono@5.2.7': {} + + '@fontsource/geist-sans@5.2.5': {} + '@google/genai@0.13.0': dependencies: google-auth-library: 9.15.1 @@ -6108,6 +6243,8 @@ snapshots: '@types/express-serve-static-core': 5.1.0 '@types/serve-static': 1.15.9 + '@types/file-saver@2.0.7': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -6369,6 +6506,28 @@ snapshots: json-schema-to-ts: 1.6.4 ts-morph: 12.0.0 + '@videojs/http-streaming@3.17.2(video.js@8.23.4)': + dependencies: + '@babel/runtime': 7.28.4 + '@videojs/vhs-utils': 4.1.1 + aes-decrypter: 4.0.2 + global: 4.4.0 + m3u8-parser: 7.2.0 + mpd-parser: 1.3.1 + mux.js: 7.1.0 + video.js: 8.23.4 + + '@videojs/vhs-utils@4.1.1': + dependencies: + '@babel/runtime': 7.28.4 + global: 4.4.0 + + '@videojs/xhr@2.7.0': + dependencies: + '@babel/runtime': 7.28.4 + global: 4.4.0 + is-function: 1.0.2 + '@vitejs/plugin-react-swc@3.11.0(@swc/helpers@0.5.17)(vite@5.4.21(@types/node@22.18.11))': dependencies: '@rolldown/pluginutils': 1.0.0-beta.27 @@ -6377,6 +6536,8 @@ snapshots: transitivePeerDependencies: - '@swc/helpers' + '@xmldom/xmldom@0.8.11': {} + abbrev@3.0.1: {} abort-controller@3.0.0: @@ -6402,6 +6563,13 @@ snapshots: acorn@8.15.0: {} + aes-decrypter@4.0.2: + dependencies: + '@babel/runtime': 7.28.4 + '@videojs/vhs-utils': 4.1.1 + global: 4.4.0 + pkcs7: 1.0.4 + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -6667,6 +6835,8 @@ snapshots: cookie@0.7.2: {} + core-util-is@1.0.3: {} + cors@2.8.5: dependencies: object-assign: 4.1.1 @@ -6765,6 +6935,8 @@ snapshots: '@babel/runtime': 7.28.4 csstype: 3.1.3 + dom-walk@0.1.2: {} + dotenv@16.6.1: {} dunder-proto@1.0.1: @@ -7113,6 +7285,8 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-saver@2.0.5: {} + file-selector@0.6.0: dependencies: tslib: 2.8.1 @@ -7256,6 +7430,11 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + global@4.4.0: + dependencies: + min-document: 2.19.2 + process: 0.11.10 + globals@14.0.0: {} globals@15.15.0: {} @@ -7384,6 +7563,8 @@ snapshots: ignore@7.0.5: {} + immediate@3.0.6: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -7429,6 +7610,8 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-function@1.0.2: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -7443,6 +7626,8 @@ snapshots: is-stream@2.0.1: {} + isarray@1.0.0: {} + isexe@2.0.0: {} jackspeak@3.4.3: @@ -7478,6 +7663,13 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 @@ -7511,6 +7703,10 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lie@3.3.0: + dependencies: + immediate: 3.0.6 + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -7531,6 +7727,12 @@ snapshots: lru-cache@10.4.3: {} + m3u8-parser@7.2.0: + dependencies: + '@babel/runtime': 7.28.4 + '@videojs/vhs-utils': 4.1.1 + global: 4.4.0 + m3u8stream@0.8.6: dependencies: miniget: 4.2.3 @@ -7909,6 +8111,10 @@ snapshots: dependencies: mime-db: 1.54.0 + min-document@2.19.2: + dependencies: + dom-walk: 0.1.2 + miniget@4.2.3: {} minimatch@3.1.2: @@ -7941,6 +8147,13 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + mpd-parser@1.3.1: + dependencies: + '@babel/runtime': 7.28.4 + '@videojs/vhs-utils': 4.1.1 + '@xmldom/xmldom': 0.8.11 + global: 4.4.0 + mri@1.2.0: {} ms@2.1.3: {} @@ -7963,6 +8176,11 @@ snapshots: multipasta@0.2.7: {} + mux.js@7.1.0: + dependencies: + '@babel/runtime': 7.28.4 + global: 4.4.0 + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -8080,6 +8298,8 @@ snapshots: package-json-from-dist@1.0.1: {} + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -8133,6 +8353,10 @@ snapshots: pixelarticons@1.8.1: {} + pkcs7@1.0.4: + dependencies: + '@babel/runtime': 7.28.4 + postcss-import@15.1.0(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -8187,6 +8411,10 @@ snapshots: dependencies: parse-ms: 2.1.0 + process-nextick-args@2.0.1: {} + + process@0.11.10: {} + progress@2.0.3: {} prop-types@15.8.1: @@ -8393,6 +8621,16 @@ snapshots: dependencies: pify: 2.3.0 + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + readable-stream@3.6.2: dependencies: inherits: 2.0.4 @@ -8516,6 +8754,8 @@ snapshots: dependencies: tslib: 2.8.1 + safe-buffer@5.1.2: {} + safe-buffer@5.2.1: {} safer-buffer@2.1.2: {} @@ -8553,6 +8793,8 @@ snapshots: transitivePeerDependencies: - supports-color + setimmediate@1.0.5: {} + setprototypeof@1.2.0: {} shallowequal@1.1.0: {} @@ -8656,6 +8898,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 @@ -8990,6 +9236,32 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + video.js@8.23.4: + dependencies: + '@babel/runtime': 7.28.4 + '@videojs/http-streaming': 3.17.2(video.js@8.23.4) + '@videojs/vhs-utils': 4.1.1 + '@videojs/xhr': 2.7.0 + aes-decrypter: 4.0.2 + global: 4.4.0 + m3u8-parser: 7.2.0 + mpd-parser: 1.3.1 + mux.js: 7.1.0 + videojs-contrib-quality-levels: 4.1.0(video.js@8.23.4) + videojs-font: 4.2.0 + videojs-vtt.js: 0.15.5 + + videojs-contrib-quality-levels@4.1.0(video.js@8.23.4): + dependencies: + global: 4.4.0 + video.js: 8.23.4 + + videojs-font@4.2.0: {} + + videojs-vtt.js@0.15.5: + dependencies: + global: 4.4.0 + vite-plugin-sitemap@0.7.1: {} vite@5.4.21(@types/node@22.18.11): diff --git a/scripts/export_resources.ts b/scripts/export_resources.ts new file mode 100644 index 0000000..16f35e6 --- /dev/null +++ b/scripts/export_resources.ts @@ -0,0 +1,50 @@ + +import { createClient } from '@supabase/supabase-js'; +import fs from 'fs'; +import dotenv from 'dotenv'; + +dotenv.config(); + +const supabaseUrl = process.env.VITE_SUPABASE_URL; +const supabaseKey = process.env.VITE_SUPABASE_ANON_KEY; + +if (!supabaseUrl || !supabaseKey) { + console.error('Supabase credentials missing in .env'); + process.exit(1); +} + +const supabase = createClient(supabaseUrl, supabaseKey); + +async function exportResources() { + console.log('Fetching resources...'); + const { data, error } = await supabase + .from('resources') + .select('*'); + + if (error) { + console.error('Error fetching data:', error); + return; + } + + // Group by category for the structure the app likes + const grouped = data.reduce((acc, resource) => { + const cat = resource.category || 'uncategorized'; + if (!acc.categories[cat]) { + acc.categories[cat] = []; + } + acc.categories[cat].push({ + id: resource.id, + title: resource.title, + ext: resource.filetype, + url: resource.download_url, + credit: resource.credit, + // Add any others if needed + }); + return acc; + }, { categories: {} }); + + fs.writeFileSync('resources_export.json', JSON.stringify(grouped, null, 2)); + console.log('Exported to resources_export.json'); +} + +exportResources(); diff --git a/server.js b/server.js index 3766eeb..09a4bc6 100644 --- a/server.js +++ b/server.js @@ -6,6 +6,7 @@ import infoHandler from './api/info.js'; import downloadHandler from './api/download.js'; import downloadThumbnailHandler from './api/downloadThumbnail.js'; import generateTitlesHandler from './api/generateTitles.js'; +import deleteAccountHandler from './api/deleteAccount.js'; import { createRouteHandler } from 'uploadthing/express'; import { uploadRouter } from './src/integrations/uploadthing/router.js'; @@ -16,43 +17,44 @@ app.use(cors()); app.use(express.json()); const createAdapter = (handler) => (req, res) => { - const vercelReq = { - method: req.method, - headers: req.headers, - body: req.body, - url: `http://${req.headers.host}${req.originalUrl}`, - }; + const vercelReq = { + method: req.method, + headers: req.headers, + body: req.body, + url: `http://${req.headers.host}${req.originalUrl}`, + }; - handler(vercelReq).then(response => { - if (!response) { - if (!res.headersSent) { - res.status(500).send("Handler returned no response."); - } - return; - } + handler(vercelReq).then(response => { + if (!response) { + if (!res.headersSent) { + res.status(500).send("Handler returned no response."); + } + return; + } - res.status(response.status); - response.headers.forEach((value, key) => { - res.setHeader(key, value); - }); - - if (response.body) { - Readable.fromWeb(response.body).pipe(res); - } else { - res.end(); - } - }).catch(error => { - console.error("Handler error:", error); - if (!res.headersSent) { - res.status(500).json({ message: 'Internal Server Error' }); - } + res.status(response.status); + response.headers.forEach((value, key) => { + res.setHeader(key, value); }); + + if (response.body) { + Readable.fromWeb(response.body).pipe(res); + } else { + res.end(); + } + }).catch(error => { + console.error("Handler error:", error); + if (!res.headersSent) { + res.status(500).json({ message: 'Internal Server Error' }); + } + }); }; app.all('/api/info', createAdapter(infoHandler)); app.all('/api/download', createAdapter(downloadHandler)); app.all('/api/downloadThumbnail', createAdapter(downloadThumbnailHandler)); app.all('/api/generateTitles', createAdapter(generateTitlesHandler)); +app.all('/api/deleteAccount', createAdapter(deleteAccountHandler)); // UploadThing route app.use( '/api/uploadthing', diff --git a/src/App.tsx b/src/App.tsx index 0705162..6f1843d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,11 +6,12 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import VercelAnalytics from "@/components/VercelAnalytics"; import { SpeedInsights } from "@vercel/speed-insights/react"; -import { AuthProvider } from "@/hooks/useAuth"; +import { AuthProvider } from "@/providers/AuthProvider"; import { HelmetProvider } from "react-helmet-async"; import ErrorBoundary from "@/components/ErrorBoundary"; import { IconLoader2 } from "@tabler/icons-react"; +// Lazy Pages const Index = lazy(() => import("@/pages/Index")); const ResourcesHub = lazy(() => import("@/pages/ResourcesHub")); const Contact = lazy(() => import("@/pages/Contact")); @@ -25,6 +26,9 @@ const PlayerRenderer = lazy(() => import("@/pages/PlayerRenderer")); const Renderbot = lazy(() => import("@/pages/Renderbot")); const Account = lazy(() => import("@/pages/Account")); const Admin = lazy(() => import("@/pages/Admin")); +const BlogEditor = lazy(() => import("@/components/admin/BlogEditor")); +const ProfileEditor = lazy(() => import("@/components/profile/ProfileEditor")); + const FAQ = lazy(() => import("@/pages/FAQ")); const TOS = lazy(() => import("@/pages/TOS")); const Privacy = lazy(() => import("@/pages/Privacy")); @@ -36,8 +40,8 @@ const NotFound = lazy(() => import("@/pages/NotFound")); const Showcase = lazy(() => import("@/pages/Showcase")); const Changelogs = lazy(() => import("@/pages/Changelogs")); const Profile = lazy(() => import("@/pages/Profile")); - -const queryClient = new QueryClient(); +const Blogs = lazy(() => import("@/pages/Blogs")); +const BlogView = lazy(() => import("@/pages/BlogView")); const LoadingFallback = ({ message = "Loading..." }: { message?: string }) => (
@@ -48,6 +52,17 @@ const LoadingFallback = ({ message = "Loading..." }: { message?: string }) => ( const App = () => { const [queryClient] = useState(() => new QueryClient()); + + // Global Theme Initialization + useState(() => { + const theme = localStorage.getItem('theme') as 'light' | 'dark' || + (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); + if (theme === 'dark') { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }); return ( @@ -86,7 +101,22 @@ const App = () => { /> } /> } /> + + +
+ } /> } /> + + + + } /> + + + + } /> } /> } /> } /> @@ -101,6 +131,8 @@ const App = () => { } /> } /> } /> + } /> + } /> diff --git a/src/components/AudioPlayer.tsx b/src/components/AudioPlayer.tsx index 6895003..013c70d 100644 --- a/src/components/AudioPlayer.tsx +++ b/src/components/AudioPlayer.tsx @@ -1,105 +1,103 @@ - -import { useState, useRef, useEffect } from 'react'; -import { IconPlayerPlay, IconPlayerPause, IconVolume, IconVolumeOff, IconPlayerSkipBack, IconPlayerSkipForward } from '@tabler/icons-react'; +import { useState, useRef, useEffect, useCallback } from 'react'; +import WaveSurfer from 'wavesurfer.js'; +import { + IconPlayerPlay, + IconPlayerPause, + IconPlayerSkipBack, + IconPlayerSkipForward, + IconLoader2 +} from '@tabler/icons-react'; import { Button } from '@/components/ui/button'; -import { Slider } from '@/components/ui/slider'; import { cn } from '@/lib/utils'; interface AudioPlayerProps { src: string; className?: string; + isInView?: boolean; } -const AudioPlayer = ({ src, className }: AudioPlayerProps) => { +const AudioPlayer = ({ src, className, isInView = true }: AudioPlayerProps) => { const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(0); - const [volume, setVolume] = useState(0.75); - const [isMuted, setIsMuted] = useState(false); - const audioRef = useRef(null); - const previousVolume = useRef(volume); - - useEffect(() => { - const audio = audioRef.current; - if (!audio) return; - - const setAudioData = () => { - setDuration(audio.duration); - }; - - const setAudioTime = () => { - setCurrentTime(audio.currentTime); - }; - - const handleEnded = () => { - setIsPlaying(false); - setCurrentTime(0); - }; + const [isLoading, setIsLoading] = useState(true); + const [isReady, setIsReady] = useState(false); - // Add event listeners - audio.addEventListener('loadeddata', setAudioData); - audio.addEventListener('timeupdate', setAudioTime); - audio.addEventListener('ended', handleEnded); + const containerRef = useRef(null); + const wavesurfer = useRef(null); - // Initialize the audio - audio.load(); + useEffect(() => { + if (!containerRef.current) return; + + const ws = WaveSurfer.create({ + container: containerRef.current, + waveColor: 'rgba(139, 92, 246, 0.2)', // Soft cow-purple + progressColor: '#8b5cf6', // Solid cow-purple + cursorColor: '#8b5cf6', + cursorWidth: 2, + barWidth: 2, + barRadius: 4, + height: 60, + barGap: 3, + normalize: true, + hideScrollbar: true, + }); + + let isMounted = true; + wavesurfer.current = ws; + + setIsLoading(true); + ws.load(src).catch((err) => { + if (err.name === 'AbortError') return; + console.error('WaveSurfer load error:', err); + }); + + ws.on('ready', () => { + if (!isMounted) return; + setDuration(ws.getDuration()); + setIsLoading(false); + setIsReady(true); + }); + + ws.on('audioprocess', () => { + if (!isMounted) return; + setCurrentTime(ws.getCurrentTime()); + }); + + ws.on('play', () => isMounted && setIsPlaying(true)); + ws.on('pause', () => isMounted && setIsPlaying(false)); + ws.on('finish', () => isMounted && setIsPlaying(false)); return () => { - // Clean up - audio.removeEventListener('loadeddata', setAudioData); - audio.removeEventListener('timeupdate', setAudioTime); - audio.removeEventListener('ended', handleEnded); + isMounted = false; + ws.destroy(); }; }, [src]); + // Handle visibility useEffect(() => { - const audio = audioRef.current; - if (!audio) return; - - // Update volume - audio.volume = isMuted ? 0 : volume; - }, [volume, isMuted]); - - const togglePlay = () => { - const audio = audioRef.current; - if (!audio) return; - - if (isPlaying) { - audio.pause(); - } else { - audio.play(); + if (!isInView && isPlaying) { + wavesurfer.current?.pause(); } - setIsPlaying(!isPlaying); - }; - - const toggleMute = () => { - if (isMuted) { - setVolume(previousVolume.current); - } else { - previousVolume.current = volume; - setVolume(0); - } - setIsMuted(!isMuted); - }; - - const handleTimeChange = (value: number[]) => { - const audio = audioRef.current; - if (!audio) return; - - const newTime = value[0]; - audio.currentTime = newTime; - setCurrentTime(newTime); - }; - - const handleVolumeChange = (value: number[]) => { - const newVolume = value[0]; - setVolume(newVolume); - if (newVolume === 0) { - setIsMuted(true); - } else if (isMuted) { - setIsMuted(false); - } - }; + }, [isInView, isPlaying]); + + const togglePlay = useCallback((e?: React.MouseEvent) => { + e?.stopPropagation(); + if (!wavesurfer.current) return; + wavesurfer.current.playPause(); + }, []); + + const skipForward = useCallback((e?: React.MouseEvent) => { + e?.stopPropagation(); + if (!wavesurfer.current) return; + wavesurfer.current.setTime(Math.min(wavesurfer.current.getCurrentTime() + 5, duration)); + }, [duration]); + + const skipBackward = useCallback((e?: React.MouseEvent) => { + e?.stopPropagation(); + if (!wavesurfer.current) return; + wavesurfer.current.setTime(Math.max(wavesurfer.current.getCurrentTime() - 5, 0)); + }, []); const formatTime = (seconds: number) => { if (isNaN(seconds)) return '0:00'; @@ -108,90 +106,66 @@ const AudioPlayer = ({ src, className }: AudioPlayerProps) => { return `${mins}:${secs.toString().padStart(2, '0')}`; }; - const restart = () => { - if (audioRef.current) { - audioRef.current.currentTime = 0; - setCurrentTime(0); - if (!isPlaying) { - audioRef.current.play(); - setIsPlaying(true); - } - } - }; - - const skipForward = () => { - if (audioRef.current) { - const newTime = Math.min(audioRef.current.currentTime + 10, duration); - audioRef.current.currentTime = newTime; - setCurrentTime(newTime); - } - }; - return ( -
-