From 64a7b1dd6235a8f58f5aa51983dfaa0bf73de070 Mon Sep 17 00:00:00 2001 From: wukko Date: Mon, 11 Aug 2025 17:58:40 +0600 Subject: [PATCH] api/bilibili: add support for video parts/episodes different videos share the same id, kind of weird --- api/src/processing/service-config.js | 1 + api/src/processing/service-patterns.js | 6 ++++-- api/src/processing/services/bilibili.js | 23 +++++++++++++++++------ api/src/processing/url.js | 1 + api/src/util/tests/bilibili.json | 9 +++++++++ 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/api/src/processing/service-config.js b/api/src/processing/service-config.js index 55946026..0a35838b 100644 --- a/api/src/processing/service-config.js +++ b/api/src/processing/service-config.js @@ -7,6 +7,7 @@ export const services = { bilibili: { patterns: [ "video/:comId", + "video/:comId?p=:partId", "_shortLink/:comShortLink", "_tv/:lang/video/:tvId", "_tv/video/:tvId" diff --git a/api/src/processing/service-patterns.js b/api/src/processing/service-patterns.js index 4ae138c2..09ea164d 100644 --- a/api/src/processing/service-patterns.js +++ b/api/src/processing/service-patterns.js @@ -1,7 +1,9 @@ export const testers = { "bilibili": pattern => - pattern.comId?.length <= 12 || pattern.comShortLink?.length <= 16 - || pattern.tvId?.length <= 24, + (pattern.comId?.length <= 12 && pattern.partId?.length <= 3) || + (pattern.comId?.length <= 12 && !pattern.partId) || + pattern.comShortLink?.length <= 16 || + pattern.tvId?.length <= 24, "dailymotion": pattern => pattern.id?.length <= 32, diff --git a/api/src/processing/services/bilibili.js b/api/src/processing/services/bilibili.js index a77ce10c..297c5f9f 100644 --- a/api/src/processing/services/bilibili.js +++ b/api/src/processing/services/bilibili.js @@ -17,8 +17,14 @@ function extractBestQuality(dashData) { return [ bestVideo, bestAudio ]; } -async function com_download(id) { - const html = await fetch(`https://bilibili.com/video/${id}`, { +async function com_download(id, partId) { + const url = new URL(`https://bilibili.com/video/${id}`); + + if (partId) { + url.searchParams.set('p', partId); + } + + const html = await fetch(url, { headers: { "user-agent": genericUserAgent } @@ -47,10 +53,15 @@ async function com_download(id) { return { error: "fetch.empty" }; } + let filenameBase = `bilibili_${id}`; + if (partId) { + filenameBase += `_${partId}`; + } + return { urls: [video.baseUrl, audio.baseUrl], - audioFilename: `bilibili_${id}_audio`, - filename: `bilibili_${id}_${video.width}x${video.height}.mp4`, + audioFilename: `${filenameBase}_audio`, + filename: `${filenameBase}_${video.width}x${video.height}.mp4`, }; } @@ -89,14 +100,14 @@ async function tv_download(id) { }; } -export default async function({ comId, tvId, comShortLink }) { +export default async function({ comId, tvId, comShortLink, partId }) { if (comShortLink) { const patternMatch = await resolveRedirectingURL(`https://b23.tv/${comShortLink}`); comId = patternMatch?.comId; } if (comId) { - return com_download(comId); + return com_download(comId, partId); } else if (tvId) { return tv_download(tvId); } diff --git a/api/src/processing/url.js b/api/src/processing/url.js index 5f93f1d0..9ac8a3ee 100644 --- a/api/src/processing/url.js +++ b/api/src/processing/url.js @@ -147,6 +147,7 @@ function cleanURL(url) { limitQuery('v'); } break; + case "bilibili": case "rutube": if (url.searchParams.get('p')) { limitQuery('p'); diff --git a/api/src/util/tests/bilibili.json b/api/src/util/tests/bilibili.json index c6720295..88b42cdf 100644 --- a/api/src/util/tests/bilibili.json +++ b/api/src/util/tests/bilibili.json @@ -56,5 +56,14 @@ "code": 200, "status": "tunnel" } + }, + { + "name": "bilibili.com link with part id", + "url": "https://www.bilibili.com/video/BV1uo4y1K72s?spm_id_from=333.788.videopod.episodes&p=6", + "params": {}, + "expected": { + "code": 200, + "status": "tunnel" + } } ]