Skip to content

Commit

Permalink
修正扫码时无法识别新版合集/列表详情 URL 的问题,改进获取合集的方式
Browse files Browse the repository at this point in the history
  • Loading branch information
tcdw committed Jan 8, 2025
1 parent 1c288e0 commit 778d4d7
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 23 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

## [Unreleased]

## [1.8.5] - 2025-01-08

### 修正内容

- 修正扫码时无法识别新版合集/列表详情 URL 的问题
- 改进获取合集的方式

## [1.8.4] - 2025-01-05

### 修正内容
Expand Down
99 changes: 95 additions & 4 deletions api/bilisound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ export async function parseB23(id: string) {
export async function getBilisoundMetadata(data: { id: string }): Promise<Wrap<GetBilisoundMetadataResponse>> {
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;
Expand All @@ -97,7 +100,7 @@ export async function getBilisoundMetadata(data: { id: string }): Promise<Wrap<G
}

// 没有分 P 的视频,将第一个视频的标题替换成投稿标题
if (pages.length === 1) {
if (pages.length === 1 && pages[0].part.trim().length <= 0) {
pages[0].part = videoData.title;
}

Expand Down Expand Up @@ -163,7 +166,10 @@ export async function getBilisoundResourceUrl(data: {
filterResourceURL?: boolean;
}): Promise<{ url: string; isAudio: boolean }> {
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;
Expand Down Expand Up @@ -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<GetEpisodeUserResponse | null> {
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<GetEpisodeUserResponse> {
if (Platform.OS === "web") {
const res = await fetch(
`${BILISOUND_API_PREFIX}/internal/user-list?mode=${mode}&userId=${userId}&listId=${listId}&page=${page}`,
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion constants/network.ts
Original file line number Diff line number Diff line change
@@ -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}`;

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
56 changes: 39 additions & 17 deletions utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<string | UserListParseResult> {
Expand All @@ -51,26 +54,45 @@ export async function resolveVideo(input: string): Promise<string | UserListPars
// 可能是链接
const url = new URL(input);

// 两种列表视频链接
if (url.hostname === "space.bilibili.com") {
// 两种列表视频链接
const match = USER_LIST_URL_REGEX.exec(url.pathname);
if (!match) {
throw new Error("不是合法的视频列表 ID");
if (match) {
if (match[2] === "seriesdetail") {
return {
type: "userList",
mode: "series",
userId: match[1],
listId: url.searchParams.get("sid") ?? "",
};
} else {
return {
type: "userList",
mode: "season",
userId: match[1],
listId: url.searchParams.get("sid") ?? "",
};
}
}
if (match[2] === "seriesdetail") {
return {
type: "userList",
mode: "series",
userId: match[1],
listId: url.searchParams.get("sid") ?? "",
};
} else {
return {
type: "userList",
mode: "season",
userId: match[1],
listId: url.searchParams.get("sid") ?? "",
};

// 两种列表视频链接・新版
const match2 = USER_LIST_URL_REGEX_2.exec(url.pathname);
if (match2) {
if (url.searchParams.get("type") === "series") {
return {
type: "userList",
mode: "series",
userId: match2[1],
listId: match2[2],
};
} else {
return {
type: "userList",
mode: "season",
userId: match2[1],
listId: match2[2],
};
}
}
}

Expand Down

0 comments on commit 778d4d7

Please sign in to comment.