mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
fix(bilibili): 修复了B站分P视频播放时只能播放第一P,且时长显示为视频总时长
在网页端播放多P视频时弹出界面选择需要播放的P数,ts里!play播放则只播放第一P
This commit is contained in:
1 parent
2ea02f54d9
commit
3c0e8df763
9 files changed
+795
-16
No files matched your search
@@ -1538,3 +1538,55 @@ describe("BotInstance live-queue persistence (#119)", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("BotInstance Bilibili multi-P resolution", () => {
|
||||
it("resolves multi-P search result to P1 with accurate duration and name", async () => {
|
||||
const multiPSongDetail = {
|
||||
id: "BV1multiP?p=1",
|
||||
name: "测试视频 - P1 分P1",
|
||||
artist: "UP主",
|
||||
album: "",
|
||||
duration: 100, // P1 duration
|
||||
coverUrl: "",
|
||||
platform: "bilibili" as const,
|
||||
};
|
||||
const mockBili = {
|
||||
platform: "bilibili" as const,
|
||||
search: vi.fn().mockResolvedValue({
|
||||
songs: [{
|
||||
id: "BV1multiP",
|
||||
name: "测试视频",
|
||||
artist: "UP主",
|
||||
album: "",
|
||||
duration: 300, // total duration in search
|
||||
coverUrl: "",
|
||||
platform: "bilibili",
|
||||
}],
|
||||
albums: [],
|
||||
playlists: [],
|
||||
}),
|
||||
getSongDetail: vi.fn().mockResolvedValue(multiPSongDetail),
|
||||
getSongUrl: vi.fn().mockResolvedValue({ url: "http://audio.test" }),
|
||||
};
|
||||
|
||||
const ctx = {
|
||||
config: { commandPrefix: "!" },
|
||||
lastSearchResults: [] as any[],
|
||||
getProvider: () => mockBili,
|
||||
getProviderFor: () => mockBili,
|
||||
};
|
||||
|
||||
const res = await (BotInstance.prototype as any).resolvePlayQuery.call(ctx, {
|
||||
name: "play",
|
||||
args: "测试视频",
|
||||
rawArgs: ["测试视频"],
|
||||
flags: new Set(),
|
||||
});
|
||||
|
||||
expect(res.song).toBeDefined();
|
||||
expect(res.song.id).toBe("BV1multiP?p=1");
|
||||
expect(res.song.name).toBe("测试视频 - P1 分P1");
|
||||
expect(res.song.duration).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
+20
-2
@@ -968,6 +968,14 @@ export class BotInstance extends EventEmitter {
|
||||
this.voteSkipUsers.clear();
|
||||
const provider = this.getProviderFor(song.platform);
|
||||
try {
|
||||
if (song.platform === "bilibili" && (!song.id.includes("?p=") || song.duration === 0)) {
|
||||
const detail = await provider.getSongDetail(song.id);
|
||||
if (detail) {
|
||||
song.duration = detail.duration;
|
||||
song.name = detail.name;
|
||||
song.id = detail.id;
|
||||
}
|
||||
}
|
||||
const result = await provider.getSongUrl(song.id);
|
||||
if (!result?.url) {
|
||||
this.logger.warn({ songId: song.id, name: song.name }, "No URL available, skipping");
|
||||
@@ -1134,7 +1142,12 @@ export class BotInstance extends EventEmitter {
|
||||
return { error: `No recent search. Use ${p}search <name> first.` };
|
||||
if (sel > this.lastSearchResults.length)
|
||||
return { error: `Invalid selection #${sel}. ${p}search returned ${this.lastSearchResults.length} results.` };
|
||||
return { song: this.lastSearchResults[sel - 1] };
|
||||
let song = this.lastSearchResults[sel - 1];
|
||||
if (song.platform === "bilibili") {
|
||||
const detail = await this.getProviderFor("bilibili").getSongDetail(song.id);
|
||||
if (detail) song = { ...detail, platform: "bilibili" };
|
||||
}
|
||||
return { song };
|
||||
}
|
||||
|
||||
// 2) id/URL — fetch that exact song.
|
||||
@@ -1151,7 +1164,12 @@ export class BotInstance extends EventEmitter {
|
||||
const provider = this.getProvider(cmd.flags);
|
||||
const result = await provider.search(args, 1);
|
||||
if (result.songs.length === 0) return { error: `No results found for: ${args}` };
|
||||
return { song: { ...result.songs[0], platform: provider.platform } };
|
||||
let song = result.songs[0];
|
||||
if (provider.platform === "bilibili") {
|
||||
const detail = await provider.getSongDetail(song.id);
|
||||
if (detail) song = detail;
|
||||
}
|
||||
return { song: { ...song, platform: provider.platform } };
|
||||
}
|
||||
|
||||
private async cmdSearch(cmd: ParsedCommand): Promise<string> {
|
||||
|
||||
Reference in new issue
Block a user