diff --git a/api/src/core/api.js b/api/src/core/api.js index 319c7a63..c7ce57b9 100644 --- a/api/src/core/api.js +++ b/api/src/core/api.js @@ -137,7 +137,10 @@ export function runAPI(express, app, __dirname) { return fail('ErrorNoLink'); } - request.dubLang = request.dubLang ? lang : false; + if (request.youtubeDubBrowserLang) { + request.youtubeDubLang = lang; + } + const normalizedRequest = normalizeRequest(request); if (!normalizedRequest) { return fail('ErrorCantProcess'); @@ -150,7 +153,7 @@ export function runAPI(express, app, __dirname) { try { const result = await match( - parsed.host, parsed.patternMatch, lang, normalizedRequest + parsed.host, parsed.patternMatch, normalizedRequest ); res.status(result.status).json(result.body); @@ -171,19 +174,16 @@ export function runAPI(express, app, __dirname) { const checkSafeLength = sig.length === 43 && sec.length === 43 && iv.length === 22; if (!checkQueries || !checkBaseLength || !checkSafeLength) { - return res.sendStatus(400); + return res.status(400).end(); } - // rate limit probe, will not return json after 8.0 if (req.query.p) { - return res.status(200).json({ - status: "continue" - }) + return res.status(200).end(); } const streamInfo = verifyStream(id, sig, exp, sec, iv); if (!streamInfo?.service) { - return res.sendStatus(streamInfo.status); + return res.status(streamInfo.status).end(); } return stream(res, streamInfo); }) diff --git a/api/src/processing/match-action.js b/api/src/processing/match-action.js index 80f63b41..6da7780b 100644 --- a/api/src/processing/match-action.js +++ b/api/src/processing/match-action.js @@ -5,7 +5,7 @@ import { createResponse } from "./request.js"; import createFilename from "./create-filename.js"; import { createStream } from "../stream/manage.js"; -export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disableMetadata, filenameStyle, toGif, requestIP }) { +export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disableMetadata, filenameStyle, twitterGif, requestIP }) { let action, responseType = "stream", defaultParams = { @@ -21,9 +21,9 @@ export default function({ r, host, audioFormat, isAudioOnly, isAudioMuted, disab if (r.isPhoto) action = "photo"; else if (r.picker) action = "picker" - else if (r.isGif && toGif) action = "gif"; - else if (isAudioMuted) action = "muteVideo"; + else if (r.isGif && twitterGif) action = "gif"; else if (isAudioOnly) action = "audio"; + else if (isAudioMuted) action = "muteVideo"; else if (r.isM3U8) action = "m3u8"; else action = "video"; diff --git a/api/src/processing/match.js b/api/src/processing/match.js index 89579524..e730b55b 100644 --- a/api/src/processing/match.js +++ b/api/src/processing/match.js @@ -29,7 +29,7 @@ import facebook from "./services/facebook.js"; let freebind; -export default async function(host, patternMatch, lang, obj) { +export default async function(host, patternMatch, obj) { const { url } = obj; assert(url instanceof URL); let dispatcher, requestIP; @@ -45,7 +45,8 @@ export default async function(host, patternMatch, lang, obj) { try { let r, - isAudioOnly = !!obj.isAudioOnly, + isAudioOnly = obj.downloadMode === "audio", + isAudioMuted = obj.downloadMode === "mute", disableMetadata = !!obj.disableMetadata; if (!testers[host]) { @@ -71,41 +72,47 @@ export default async function(host, patternMatch, lang, obj) { dispatcher }); break; + case "vk": r = await vk({ userId: patternMatch.userId, videoId: patternMatch.videoId, - quality: obj.vQuality + quality: obj.videoQuality }); break; + case "ok": r = await ok({ id: patternMatch.id, - quality: obj.vQuality + quality: obj.videoQuality }); break; + case "bilibili": r = await bilibili(patternMatch); break; + case "youtube": let fetchInfo = { id: patternMatch.id.slice(0, 11), - quality: obj.vQuality, - format: obj.vCodec, - isAudioOnly: isAudioOnly, - isAudioMuted: obj.isAudioMuted, - dubLang: obj.dubLang, + quality: obj.videoQuality, + format: obj.youtubeVideoCodec, + isAudioOnly, + isAudioMuted, + dubLang: obj.youtubeDubLang, dispatcher } - if (url.hostname === 'music.youtube.com' || isAudioOnly === true) { + if (url.hostname === "music.youtube.com" || isAudioOnly) { fetchInfo.quality = "max"; fetchInfo.format = "vp9"; - fetchInfo.isAudioOnly = true + fetchInfo.isAudioOnly = true; + fetchInfo.isAudioMuted = false; } r = await youtube(fetchInfo); break; + case "reddit": r = await reddit({ sub: patternMatch.sub, @@ -113,15 +120,17 @@ export default async function(host, patternMatch, lang, obj) { user: patternMatch.user }); break; + case "tiktok": r = await tiktok({ postId: patternMatch.postId, id: patternMatch.id, - fullAudio: obj.isTTFullAudio, - isAudioOnly: isAudioOnly, + fullAudio: obj.tiktokFullAudio, + isAudioOnly, h265: obj.tiktokH265 }); break; + case "tumblr": r = await tumblr({ id: patternMatch.id, @@ -129,90 +138,106 @@ export default async function(host, patternMatch, lang, obj) { url }); break; + case "vimeo": r = await vimeo({ id: patternMatch.id.slice(0, 11), password: patternMatch.password, - quality: obj.vQuality, - isAudioOnly: isAudioOnly + quality: obj.videoQuality, + isAudioOnly, }); break; + case "soundcloud": isAudioOnly = true; + isAudioMuted = false; r = await soundcloud({ url, author: patternMatch.author, song: patternMatch.song, - format: obj.aFormat, + format: obj.audioFormat, shortLink: patternMatch.shortLink || false, accessKey: patternMatch.accessKey || false }); break; + case "instagram": r = await instagram({ ...patternMatch, - quality: obj.vQuality, + quality: obj.videoQuality, dispatcher }) break; + case "vine": r = await vine({ id: patternMatch.id }); break; + case "pinterest": r = await pinterest({ id: patternMatch.id, shortLink: patternMatch.shortLink || false }); break; + case "streamable": r = await streamable({ id: patternMatch.id, - quality: obj.vQuality, - isAudioOnly: isAudioOnly, + quality: obj.videoQuality, + isAudioOnly, }); break; + case "twitch": r = await twitch({ clipId: patternMatch.clip || false, - quality: obj.vQuality, - isAudioOnly: obj.isAudioOnly + quality: obj.videoQuality, + isAudioOnly, }); break; + case "rutube": r = await rutube({ id: patternMatch.id, yappyId: patternMatch.yappyId, key: patternMatch.key, - quality: obj.vQuality, - isAudioOnly: isAudioOnly + quality: obj.videoQuality, + isAudioOnly, }); break; + case "dailymotion": r = await dailymotion(patternMatch); break; + case "snapchat": r = await snapchat(patternMatch); break; + case "loom": r = await loom({ id: patternMatch.id }); break; + case "facebook": r = await facebook({ ...patternMatch }); break; + default: return createResponse("error", { code: "ErrorUnsupported" }); } - if (r.isAudioOnly) isAudioOnly = true; - let isAudioMuted = isAudioOnly ? false : obj.isAudioMuted; + if (r.isAudioOnly) { + isAudioOnly = true; + isAudioMuted = false; + } if (r.error && r.critical) { return createResponse("critical", { @@ -230,12 +255,12 @@ export default async function(host, patternMatch, lang, obj) { return matchAction({ r, host, - audioFormat: obj.aFormat, + audioFormat: obj.audioFormat, isAudioOnly, isAudioMuted, disableMetadata, - filenameStyle: obj.filenamePattern, - toGif: obj.twitterGif, + filenameStyle: obj.filenameStyle, + twitterGif: obj.twitterGif, requestIP }) } catch { diff --git a/api/src/processing/request.js b/api/src/processing/request.js index 899fcc44..e90d17d2 100644 --- a/api/src/processing/request.js +++ b/api/src/processing/request.js @@ -4,21 +4,21 @@ import { normalizeURL } from "./url.js"; import { createStream } from "../stream/manage.js"; import { verifyLanguageCode } from "../misc/utils.js"; -const apiVar = { - allowed: { - vCodec: ["h264", "av1", "vp9"], - vQuality: ["max", "4320", "2160", "1440", "1080", "720", "480", "360", "240", "144"], - aFormat: ["best", "mp3", "ogg", "wav", "opus"], - filenamePattern: ["classic", "pretty", "basic", "nerdy"] +const apiRequest = { + option: { + audioFormat: ["best", "mp3", "ogg", "wav", "opus"], + downloadMode: ["auto", "audio", "mute"], + filenameStyle: ["classic", "pretty", "basic", "nerdy"], + videoQuality: ["max", "4320", "2160", "1440", "1080", "720", "480", "360", "240", "144"], + youtubeVideoCodec: ["h264", "av1", "vp9"], }, - booleanOnly: [ - "isAudioOnly", - "isTTFullAudio", - "isAudioMuted", - "dubLang", + boolean: [ "disableMetadata", + "tiktokFullAudio", + "tiktokH265", "twitterGif", - "tiktokH265" + "youtubeDubBrowserLang", + "youtubeDubLang" ] } @@ -116,16 +116,16 @@ export function createResponse(responseType, responseData) { export function normalizeRequest(request) { try { let template = { + audioFormat: "mp3", url: normalizeURL(decodeURIComponent(request.url)), - vCodec: "h264", - vQuality: "720", - aFormat: "mp3", - filenamePattern: "classic", - isAudioOnly: false, - isTTFullAudio: false, - isAudioMuted: false, + youtubeVideoCodec: "h264", + videoQuality: "720", + filenameStyle: "classic", + downloadMode: "auto", + tiktokFullAudio: false, disableMetadata: false, - dubLang: false, + youtubeDubBrowserLang: false, + youtubeDubLang: false, twitterGif: false, tiktokH265: false } @@ -142,16 +142,16 @@ export function normalizeRequest(request) { const item = request[key]; if (String(key) !== "url" && templateKeys.includes(key)) { - if (apiVar.booleanOnly.includes(key)) { + if (apiRequest.boolean.includes(key)) { template[key] = !!item; - } else if (apiVar.allowed[key] && apiVar.allowed[key].includes(item)) { + } else if (apiRequest.option[key] && apiRequest.option[key].includes(item)) { template[key] = String(item) } } } - if (template.dubLang) - template.dubLang = verifyLanguageCode(request.dubLang); + if (template.youtubeDubBrowserLang) + template.youtubeDubLang = verifyLanguageCode(request.youtubeDubLang); return template } catch {