From 778d4d7a8daa995f9580bd80a165f7d9aaabf972 Mon Sep 17 00:00:00 2001 From: tcdw Date: Wed, 8 Jan 2025 23:51:07 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E6=89=AB=E7=A0=81=E6=97=B6?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E8=AF=86=E5=88=AB=E6=96=B0=E7=89=88=E5=90=88?= =?UTF-8?q?=E9=9B=86/=E5=88=97=E8=A1=A8=E8=AF=A6=E6=83=85=20URL=20?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E6=94=B9=E8=BF=9B=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E5=90=88=E9=9B=86=E7=9A=84=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 7 ++++ api/bilisound.ts | 99 ++++++++++++++++++++++++++++++++++++++++++-- constants/network.ts | 2 +- package.json | 2 +- utils/format.ts | 56 +++++++++++++++++-------- 5 files changed, 143 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b11312b..128f78e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ ## [Unreleased] +## [1.8.5] - 2025-01-08 + +### 修正内容 + +- 修正扫码时无法识别新版合集/列表详情 URL 的问题 +- 改进获取合集的方式 + ## [1.8.4] - 2025-01-05 ### 修正内容 diff --git a/api/bilisound.ts b/api/bilisound.ts index 417c291..a32bd6b 100644 --- a/api/bilisound.ts +++ b/api/bilisound.ts @@ -75,7 +75,10 @@ export async function parseB23(id: string) { export async function getBilisoundMetadata(data: { id: string }): Promise> { if (Platform.OS === "web") { const response = await fetch(BILISOUND_API_PREFIX + `/internal/metadata?id=${data.id}`); - return response.json(); + const outData = await response.json(); + if (outData.code !== 200) { + throw new Error(outData.msg); + } } const { id } = data; @@ -97,7 +100,7 @@ export async function getBilisoundMetadata(data: { id: string }): Promise { if (Platform.OS === "web") { - throw new Error("getBilisoundResourceUrl 在 web 端未实现"); + return { + url: BILISOUND_API_PREFIX + `/internal/resource?id=${data.id}&episode=${data.episode}`, + isAudio: true, + }; } const { id, episode } = data; @@ -266,7 +272,79 @@ export interface GetEpisodeUserResponse { export type UserListMode = "season" | "series" | "favourite"; -export async function getUserList(mode: UserListMode, userId: Numberish, listId: Numberish, page = 1) { +/** + * 尝试一次性获取完整合集列表 + * @param userId + * @param listId + */ +async function tryGetFullSection(userId: Numberish, listId: Numberish): Promise { + log.info("尝试一次获取完整合集"); + log.debug(`userId: ${userId}, listId: ${listId}`); + + const { data } = await getUserSeason(userId, listId, 1); + if (data.page.total <= data.page.page_size) { + log.warn("一次获取完整合集取消:视频总数小于单页展示数量,无需进行此操作"); + return null; + } + + const name = data.meta.name; + const description = data.meta.description; + const cover = data.meta.cover; + const firstVideoId = data.archives[0]?.bvid; + if (!firstVideoId) { + log.warn("一次获取完整合集失败:列表中没有找到第一个视频 ID"); + return null; + } + + const firstVideoResponse = await getVideo({ id: firstVideoId }); + if (firstVideoResponse.type !== "regular") { + log.warn("一次获取完整合集失败:非常规视频"); + return null; + } + + const sections = firstVideoResponse.initialState.sectionsInfo?.sections ?? []; + const episodes = sections.flatMap(section => section.episodes ?? []); + if (episodes.length <= 0) { + log.warn("一次获取完整合集失败:列表中没有找到视频"); + return null; + } + + const rows = episodes.map(e => ({ + bvid: e.bvid, + title: e.title, + cover: e.arc.pic, + duration: e.arc.duration, + })); + + log.debug(`一次获取完整合集成功:${rows.length} 条记录`); + return { + pageSize: rows.length, + pageNum: 1, + total: rows.length, + rows, + meta: { + name, + description, + cover, + userId, + seasonId: listId, + }, + }; +} + +/** + * 获取用户列表(合集/列表) + * @param mode + * @param userId + * @param listId + * @param page + */ +export async function getUserList( + mode: UserListMode, + userId: Numberish, + listId: Numberish, + page = 1, +): Promise { if (Platform.OS === "web") { const res = await fetch( `${BILISOUND_API_PREFIX}/internal/user-list?mode=${mode}&userId=${userId}&listId=${listId}&page=${page}`, @@ -282,6 +360,12 @@ export async function getUserList(mode: UserListMode, userId: Numberish, listId: let description = ""; let cover = ""; if (mode === "season") { + // 首先尝试从任意一个视频详情页面抓取完整的合集列表 + const fullResult = await tryGetFullSection(userId, listId); + if (fullResult) { + return fullResult; + } + response = await getUserSeason(userId, listId, page); const data = response.data; pageSize = data.page.page_size; @@ -321,6 +405,13 @@ export async function getUserList(mode: UserListMode, userId: Numberish, listId: }; } +/** + * 一次性拉取完整用户列表(合集/列表) + * @param mode + * @param userId + * @param listId + * @param progressCallback + */ export async function getUserListFull( mode: UserListMode, userId: Numberish, diff --git a/constants/network.ts b/constants/network.ts index 7f73f8e..742e9c5 100644 --- a/constants/network.ts +++ b/constants/network.ts @@ -1,7 +1,7 @@ import { VERSION } from "~/constants/releasing"; export const USER_AGENT_BILIBILI = - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"; + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"; export const USER_AGENT_BILISOUND = `Bilisound/${VERSION}`; diff --git a/package.json b/package.json index a7de629..49eb24e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bilisound-client-mobile", "main": "expo-router/entry", - "version": "1.8.4", + "version": "1.8.5", "scripts": { "start": "cross-env DARK_MODE=media expo start -c --dev-client", "android": "cross-env DARK_MODE=media expo run:android", diff --git a/utils/format.ts b/utils/format.ts index fa0b100..09d25cc 100644 --- a/utils/format.ts +++ b/utils/format.ts @@ -8,6 +8,7 @@ import log from "~/utils/logger"; export const B23_REGEX = /https?:\/\/b23\.tv\/([a-zA-Z0-9]+)/; export const USER_LIST_URL_REGEX = /^\/(\d+)\/channel\/(seriesdetail|collectiondetail)$/; +export const USER_LIST_URL_REGEX_2 = /^\/(\d+)\/lists\/(\d+)/; export interface UserListParseResult { type: "userList"; @@ -29,6 +30,8 @@ export interface UserListParseResult { * - `https://b23.tv/k37TjOT`(需要调接口解析) * - `https://space.bilibili.com/701522855/channel/seriesdetail?sid=747414` * - `https://space.bilibili.com/1741301/channel/collectiondetail?sid=49333` + * - `https://space.bilibili.com/9283084/lists/537652?type=series` + * - `https://space.bilibili.com/1464161420/lists/2654915?type=season` * @param input */ export async function resolveVideo(input: string): Promise { @@ -51,26 +54,45 @@ export async function resolveVideo(input: string): Promise