mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat: resolve trial-only playback via trialDuration/effectiveDuration
VIP songs for non-VIP accounts return a ~30s trial fragment. The player used the full duration for isNearEnd, so the trial end didn't trigger auto-advance (~60s stall), and currentSong.duration stayed full, leaving the UI progress stuck.
- provider.ts: SongUrlResult {url, trialDuration?}; getSongUrl signature
- netease.ts: parseNeteaseTrial (freeTrialInfo start/end in seconds) + getSongUrl
- qq.ts: parseQqTrial (isTryout/tryEnd) + getSongUrl
- bilibili/youtube: getSongUrl returns {url}
- instance.ts: resolveAndPlay uses effectiveDuration = trialDuration ?? duration -> nearEnd at trial end -> native auto-advance; BotStatus.effectiveDuration
- VIP account: freeTrialInfo absent -> full duration -> full playback (no toggle)
Backward compatible (optional fields; getSongUrl has a single caller, updated).
Tests: parseTrial assertions (seconds/alias/ms-fallback). 14 pass.
This commit is contained in:
1 parent
7b2bd0ea6a
commit
fbb127a86d
8 files changed
+90
-16
No files matched your search
+11
-4
@@ -49,6 +49,8 @@ export interface BotStatus {
|
||||
volume: number;
|
||||
playMode: PlayMode;
|
||||
elapsed: number; // ground truth elapsed seconds from frame count
|
||||
/** 当前曲实际播放时长(秒)。试听片段=试听秒数;完整曲=duration。缺失时前端回退 currentSong.duration。 */
|
||||
effectiveDuration?: number;
|
||||
}
|
||||
|
||||
export class BotInstance extends EventEmitter {
|
||||
@@ -78,6 +80,8 @@ export class BotInstance extends EventEmitter {
|
||||
private fmProvider: MusicProvider | null = null;
|
||||
/** Results of the most recent !search, for "#N" selection (issue #90). */
|
||||
private lastSearchResults: Song[] = [];
|
||||
/** 当前曲实际播放时长(试听片段秒数或完整 duration);resolveAndPlay 赋值。 */
|
||||
private effectiveDuration: number | undefined;
|
||||
|
||||
constructor(options: BotInstanceOptions) {
|
||||
super();
|
||||
@@ -460,8 +464,8 @@ export class BotInstance extends EventEmitter {
|
||||
this.voteSkipUsers.clear();
|
||||
const provider = this.getProviderFor(song.platform);
|
||||
try {
|
||||
const url = await provider.getSongUrl(song.id);
|
||||
if (!url) {
|
||||
const result = await provider.getSongUrl(song.id);
|
||||
if (!result?.url) {
|
||||
this.logger.warn({ songId: song.id, name: song.name }, "No URL available, skipping");
|
||||
return false;
|
||||
}
|
||||
@@ -477,8 +481,10 @@ export class BotInstance extends EventEmitter {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
song.url = url;
|
||||
this.player.play(url, 0, song.duration);
|
||||
song.url = result.url;
|
||||
// 试听片段用试听时长(让 player nearEnd 正确触发自动切歌);完整曲回退 song.duration
|
||||
this.effectiveDuration = result.trialDuration ?? song.duration;
|
||||
this.player.play(result.url, 0, this.effectiveDuration);
|
||||
// Fresh playback (re)start — clear auto-pause so a later occupancy
|
||||
// change won't try to "resume" a track the user already restarted.
|
||||
this.autoPaused = false;
|
||||
@@ -1063,6 +1069,7 @@ export class BotInstance extends EventEmitter {
|
||||
volume: this.player.getVolume(),
|
||||
playMode: this.queue.getMode(),
|
||||
elapsed: this.player.getElapsed(),
|
||||
effectiveDuration: this.effectiveDuration,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user