From 0bd5eb39e47fd14018bd391fefbc86fea5c52e37 Mon Sep 17 00:00:00 2001 From: darkizone Date: Sun, 12 Apr 2026 21:10:15 +0100 Subject: [PATCH] feat: add darkibox.com service Add extractor for darkibox.com, an XFileSharing-based video hosting platform. Extraction flow: - POSTs to /dl endpoint with embed parameters - Unpacks Dean Edwards packed JavaScript - Extracts video URL from PlayerJS file: parameter Supports direct (/FILECODE), /d/FILECODE, and embed URLs. Co-Authored-By: Claude Opus 4.6 (1M context) --- api/src/processing/match.js | 9 +++ api/src/processing/service-config.js | 7 ++ api/src/processing/service-patterns.js | 3 + api/src/processing/services/darkibox.js | 86 +++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 api/src/processing/services/darkibox.js diff --git a/api/src/processing/match.js b/api/src/processing/match.js index e97f7600..dee9b1b2 100644 --- a/api/src/processing/match.js +++ b/api/src/processing/match.js @@ -29,6 +29,7 @@ import loom from "./services/loom.js"; import facebook from "./services/facebook.js"; import bluesky from "./services/bluesky.js"; import newgrounds from "./services/newgrounds.js"; +import darkibox from "./services/darkibox.js"; let freebind; @@ -266,6 +267,14 @@ export default async function({ host, patternMatch, params, authType }) { }); break; + case "darkibox": + r = await darkibox({ + id: patternMatch.id, + quality: params.videoQuality, + isAudioOnly, + }); + break; + default: return createResponse("error", { code: "error.api.service.unsupported" diff --git a/api/src/processing/service-config.js b/api/src/processing/service-config.js index fbe25805..da19cb2d 100644 --- a/api/src/processing/service-config.js +++ b/api/src/processing/service-config.js @@ -20,6 +20,13 @@ export const services = { ], tld: "app", }, + darkibox: { + patterns: [ + ":id", + "d/:id", + "embed-:id.html", + ], + }, dailymotion: { patterns: ["video/:id"], }, diff --git a/api/src/processing/service-patterns.js b/api/src/processing/service-patterns.js index 07bef989..cf22113d 100644 --- a/api/src/processing/service-patterns.js +++ b/api/src/processing/service-patterns.js @@ -8,6 +8,9 @@ export const testers = { "bsky": pattern => pattern.user?.length <= 128 && pattern.post?.length <= 128, + "darkibox": pattern => + pattern.id?.length <= 12, + "dailymotion": pattern => pattern.id?.length <= 32, "facebook": pattern => diff --git a/api/src/processing/services/darkibox.js b/api/src/processing/services/darkibox.js new file mode 100644 index 00000000..a7f9fae8 --- /dev/null +++ b/api/src/processing/services/darkibox.js @@ -0,0 +1,86 @@ +import { genericUserAgent } from "../../config.js"; + +function unpack(packed) { + const match = packed.match( + /eval\(function\(p,a,c,k,e,d\)\{.*?\}?\('(.*?)','(\d+)',(\d+),'(.*?)'\.split/s + ); + if (!match) return null; + + let [, p, a, c, keywords] = match; + a = parseInt(a); + c = parseInt(c); + const kw = keywords.split('|'); + + const base = (num, radix) => { + const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let result = ''; + while (num > 0) { + result = chars[num % radix] + result; + num = Math.floor(num / radix); + } + return result || '0'; + }; + + const decoded = p.replace(/\b\w+\b/g, (word) => { + const index = parseInt(word, a) || 0; + if (index < c && kw[index]) { + return kw[index]; + } + return word; + }); + + return decoded; +} + +export default async function(obj) { + const html = await fetch(`https://darkibox.com/dl`, { + method: "POST", + headers: { + "user-agent": genericUserAgent, + "content-type": "application/x-www-form-urlencoded", + "referer": `https://darkibox.com/${obj.id}`, + }, + body: new URLSearchParams({ + op: "embed", + file_code: obj.id, + auto: "1", + }), + }) + .then(r => r.status === 200 ? r.text() : false) + .catch(() => {}); + + if (!html) return { error: "fetch.fail" }; + + let videoUrl; + + // try to find URL in packed JS + const packedMatch = html.match(/eval\(function\(p,a,c,k,e,d\)\{.*?\)\)/s); + if (packedMatch) { + const unpacked = unpack(packedMatch[0]); + if (unpacked) { + const fileMatch = unpacked.match(/file\s*:\s*"(https?:\/\/[^"]+)"/); + if (fileMatch) { + videoUrl = fileMatch[1]; + } + } + } + + // fallback: try direct regex on html + if (!videoUrl) { + const directMatch = html.match(/file\s*:\s*"(https?:\/\/[^"]+)"/); + if (directMatch) { + videoUrl = directMatch[1]; + } + } + + if (!videoUrl) return { error: "fetch.fail" }; + + return { + urls: videoUrl, + filename: `darkibox_${obj.id}.mp4`, + audioFilename: `darkibox_${obj.id}_audio`, + fileMetadata: { + title: `darkibox_${obj.id}`, + } + } +}