|
|
@@ -116,6 +116,7 @@ import { ServerLogUtil } from '../common/util/ServerLogUtil';
|
|
|
import { lyricService, SongData } from '../common/service/LyricService';
|
|
|
import { shouldResolveRemoteLyricOnPlay, tryResolveRemotePlaybackLyric } from '../common/util/RemotePlaybackLyricUtil';
|
|
|
import { resolvePlayerDismissMorphTarget } from '../common/util/PlayerDismissHelper';
|
|
|
+import { isBaiduStreamingPlaybackUrl, resolveSeekGuardDecision } from '../common/util/PlaybackSeekGuard';
|
|
|
import {
|
|
|
cloneVideoItem,
|
|
|
preloadNextSongIfNeeded,
|
|
|
@@ -17395,6 +17396,39 @@ export struct LocalMusic {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ private shouldShowSeekBlockedToast(source: string): boolean {
|
|
|
+ return source === 'top-progress-slider' ||
|
|
|
+ source === 'landscape-progress-slider' ||
|
|
|
+ source === 'fast-forward-button' ||
|
|
|
+ source === 'rewind-button' ||
|
|
|
+ source === 'session-fast-forward' ||
|
|
|
+ source === 'session-rewind' ||
|
|
|
+ source === 'session-seek';
|
|
|
+ }
|
|
|
+
|
|
|
+ private handleBlockedSeek(seekPos: number, source: string): boolean {
|
|
|
+ const decision = resolveSeekGuardDecision(this.videoUrl, seekPos, this.currentSong?.type);
|
|
|
+ if (decision.allow) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ Logger.warn(
|
|
|
+ TAG,
|
|
|
+ `[seek] blocked source=${source}, target=${seekPos}, reason=${decision.reason}, ` +
|
|
|
+ `url=${this.sanitizePlaybackUrl(this.videoUrl)}`
|
|
|
+ );
|
|
|
+ if (this.shouldShowSeekBlockedToast(source) && StrUtil.isNotEmpty(decision.toastMessage)) {
|
|
|
+ ToastUtil.showToast(decision.toastMessage);
|
|
|
+ }
|
|
|
+ if (this.waitInitialSeekBeforeStart) {
|
|
|
+ this.finishInitialSeekWait(`blocked-${decision.reason}`, true);
|
|
|
+ } else {
|
|
|
+ this.hideLoadIng();
|
|
|
+ }
|
|
|
+ this.isSeekTo = false;
|
|
|
+ this.logSeekTrace(`seek-blocked-${decision.reason}`, undefined, undefined, true);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
private stringForTime(timeMs: number): string {
|
|
|
let totalSeconds: number | string = (timeMs / 1000);
|
|
|
let newSeconds: number | string = totalSeconds % 60;
|
|
|
@@ -17726,7 +17760,7 @@ export struct LocalMusic {
|
|
|
|
|
|
|
|
|
let that = this;
|
|
|
- const isBaiduStreamingPlaybackUrl = this.isBaiduStreamingUrl(url);
|
|
|
+ const isBaiduStreamingPlayback = isBaiduStreamingPlaybackUrl(url);
|
|
|
if (this.waitInitialSeekBeforeStart) {
|
|
|
that.showLoadIng();
|
|
|
} else {
|
|
|
@@ -17833,7 +17867,7 @@ export struct LocalMusic {
|
|
|
this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "reconnect", "3"); // 重连3次
|
|
|
|
|
|
console.log(`heanup WebDAV IjkPlayer选项设置完成`);
|
|
|
- } else if ((this.currentSong && isBaiduType(this.currentSong.type)) || isBaiduStreamingPlaybackUrl) {
|
|
|
+ } else if ((this.currentSong && isBaiduType(this.currentSong.type)) || isBaiduStreamingPlayback) {
|
|
|
console.log(`heanup 为百度网盘播放设置IjkPlayer选项`);
|
|
|
this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "timeout", "15000000");
|
|
|
this.mIjkMediaPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_FORMAT, "connect_timeout", "15000000");
|
|
|
@@ -19026,7 +19060,7 @@ export struct LocalMusic {
|
|
|
}
|
|
|
Logger.info('heanup sessionFastForwardCallback', `快进: ${time}秒, 目标位置: ${seeTime}ms`);
|
|
|
this.setSeekToActionProgress(seeTime);
|
|
|
- await this.seekTo(seeTime + "");
|
|
|
+ await this.seekTo(seeTime + "", 'session-fast-forward');
|
|
|
};
|
|
|
private getActiveDuration(): number {
|
|
|
if (this.currentSong && isCueSplitItem(this.currentSong)) {
|
|
|
@@ -19045,14 +19079,6 @@ export struct LocalMusic {
|
|
|
return duration;
|
|
|
}
|
|
|
|
|
|
- private isBaiduStreamingUrl(url: string): boolean {
|
|
|
- if (StrUtil.isEmpty(url)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- const lowerUrl = url.toLowerCase();
|
|
|
- return lowerUrl.includes('pan.baidu.com/rest/2.0/xpan/file') && lowerUrl.includes('method=streaming');
|
|
|
- }
|
|
|
-
|
|
|
@Builder
|
|
|
InlineSpectrumView() {
|
|
|
SpectrumView({
|
|
|
@@ -19186,13 +19212,13 @@ export struct LocalMusic {
|
|
|
}
|
|
|
Logger.info('heanup sessionRewindCallback', `快退: ${time}秒, 目标位置: ${seeTime}ms`);
|
|
|
this.setSeekToActionProgress(seeTime);
|
|
|
- await this.seekTo(seeTime + "");
|
|
|
+ await this.seekTo(seeTime + "", 'session-rewind');
|
|
|
};
|
|
|
private sessionSeekCallback = async (seekTime: number) => {
|
|
|
Logger.info('heanup sessionSeekCallback', `收到seek请求: ${seekTime}ms, 投播模式: ${this.isCastPlaying}`);
|
|
|
|
|
|
// 投播模式直接调用seekTo,它会自动处理投播控制器的seek命令
|
|
|
- await this.seekTo(seekTime + "");
|
|
|
+ await this.seekTo(seekTime + "", 'session-seek');
|
|
|
};
|
|
|
|
|
|
private async getFileSize(filePath: string): Promise<number> {
|
|
|
@@ -19444,6 +19470,9 @@ export struct LocalMusic {
|
|
|
if (source !== 'internal') {
|
|
|
this.beginSeekTrace(source, seekPos);
|
|
|
}
|
|
|
+ if (this.handleBlockedSeek(seekPos, source)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
this.isSeekTo = true
|
|
|
try {
|
|
|
if (isRemoteSong || source !== 'internal' || this.isSeekTraceActive()) {
|
|
|
@@ -19513,7 +19542,7 @@ export struct LocalMusic {
|
|
|
if (value < 0) {
|
|
|
value = 0;
|
|
|
}
|
|
|
- await this.seekTo(value + "");
|
|
|
+ await this.seekTo(value + "", 'rewind-button');
|
|
|
}
|
|
|
|
|
|
//快进10s,可再设置设置默认几秒
|
|
|
@@ -19537,7 +19566,7 @@ export struct LocalMusic {
|
|
|
if (this.duration > 0 && value > this.duration) {
|
|
|
value = this.duration;
|
|
|
}
|
|
|
- await this.seekTo(value + "");
|
|
|
+ await this.seekTo(value + "", 'fast-forward-button');
|
|
|
}
|
|
|
|
|
|
//下一个
|