From 036fc35c9a06c914b82abcf11ee66968e7851e40 Mon Sep 17 00:00:00 2001 From: Valknar XXX Date: Mon, 3 Nov 2025 17:13:56 +0100 Subject: [PATCH] fix: add custom endpoint for getVideoBySlug to bypass permissions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add GET /sexy/videos/:slug endpoint in bundle that bypasses Directus permissions - Simplify getVideoBySlug to use the new custom endpoint instead of direct API call - Fixes "Video not found" error on production for public video pages - Custom endpoint uses database query like other public endpoints (/sexy/models, etc) - Ensures videos are accessible to unauthenticated users while respecting upload_date 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- packages/bundle/src/endpoint/index.ts | 42 +++++++++++++++++++++++++++ packages/frontend/src/lib/services.ts | 42 +++++---------------------- 2 files changed, 49 insertions(+), 35 deletions(-) diff --git a/packages/bundle/src/endpoint/index.ts b/packages/bundle/src/endpoint/index.ts index 9af285a..c4ff610 100644 --- a/packages/bundle/src/endpoint/index.ts +++ b/packages/bundle/src/endpoint/index.ts @@ -204,6 +204,48 @@ export default { } }); + // GET /sexy/videos/:slug - Get single video by slug + router.get("/videos/:slug", async (req, res) => { + try { + const { slug } = req.params; + + const video = await database + .select("v.*") + .from("sexy_videos as v") + .where("v.slug", slug) + .where("v.upload_date", "<=", new Date().toISOString()) + .first(); + + if (!video) { + return res.status(404).json({ error: "Video not found" }); + } + + // Fetch models + const models = await database + .select("u.*") + .from("sexy_videos_models as vm") + .leftJoin("directus_users as u", "vm.directus_users_id", "u.id") + .where("vm.sexy_videos_id", video.id); + + video.models = models; + + // Fetch movie file + if (video.movie) { + const movie = await database + .select("*") + .from("directus_files") + .where("id", video.movie) + .first(); + video.movie = movie; + } + + res.json(video); + } catch (error: any) { + console.error("Video by slug error:", error); + res.status(500).json({ error: error.message || "Failed to fetch video" }); + } + }); + // GET /sexy/articles - List articles router.get("/articles", async (req, res) => { try { diff --git a/packages/frontend/src/lib/services.ts b/packages/frontend/src/lib/services.ts index fbbfaab..646440f 100644 --- a/packages/frontend/src/lib/services.ts +++ b/packages/frontend/src/lib/services.ts @@ -242,41 +242,13 @@ export async function getVideoBySlug( return loggedApiCall( "getVideoBySlug", async () => { - const fetchFn = fetch || globalThis.fetch; - return fetchFn( - `${directusApiUrl}/items/sexy_videos?${new URLSearchParams({ - filter: JSON.stringify({ slug: { _eq: slug } }), - fields: JSON.stringify([ - "*", - { - models: [ - "*", - { - directus_users_id: ["*"], - }, - ], - }, - "movie.*", - ]), - })}`, - ) - .then((res) => res.json()) - .then((response) => { - const videos = response.data; - if (!videos || videos.length === 0) { - throw new Error("Video not found"); - } - // Handle models array - filter out null/undefined and map to user objects - if (Array.isArray(videos[0].models)) { - videos[0].models = videos[0].models - .filter((u) => u && u.directus_users_id) - .map((u) => u.directus_users_id!); - } else { - videos[0].models = []; - } - - return videos[0]; - }); + const directus = getDirectusInstance(fetch); + return directus.request