|
@@ -485,6 +485,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
// 图片缓存相关属性
|
|
// 图片缓存相关属性
|
|
|
private imageCacheDir: string = ''; // 图片缓存目录
|
|
private imageCacheDir: string = ''; // 图片缓存目录
|
|
|
private lastImageCache: ImageCacheInfo | null = null; // 图片缓存优化
|
|
private lastImageCache: ImageCacheInfo | null = null; // 图片缓存优化
|
|
|
|
|
+ private lastFormUpdateTime: number = 0; // 上次卡片更新时间,用于防抖
|
|
|
private readonly CACHE_EXPIRY_DAYS: number = 7; // 缓存有效期:7天
|
|
private readonly CACHE_EXPIRY_DAYS: number = 7; // 缓存有效期:7天
|
|
|
private readonly MAX_CACHE_SIZE_MB: number = 50; // 最大缓存大小:50MB
|
|
private readonly MAX_CACHE_SIZE_MB: number = 50; // 最大缓存大小:50MB
|
|
|
private hasChecked: boolean=false;
|
|
private hasChecked: boolean=false;
|
|
@@ -1065,13 +1066,13 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
// 更新播放列表状态
|
|
// 更新播放列表状态
|
|
|
await this.updatePlaylistStateInModel();
|
|
await this.updatePlaylistStateInModel();
|
|
|
|
|
|
|
|
- // 优化:减少延迟,立即更新卡片状态,避免重复更新AVSession
|
|
|
|
|
- setTimeout(async () => {
|
|
|
|
|
|
|
+ // 优化:立即更新卡片状态,使用微任务调度避免阻塞
|
|
|
|
|
+ Promise.resolve().then(async () => {
|
|
|
try {
|
|
try {
|
|
|
// 确保播放列表状态是最新的
|
|
// 确保播放列表状态是最新的
|
|
|
this.updatePlaylistStateInModelSync();
|
|
this.updatePlaylistStateInModelSync();
|
|
|
|
|
|
|
|
- // 强制更新所有桌面卡片状态
|
|
|
|
|
|
|
+ // 强制更新所有桌面卡片状态(微任务优先级高于宏任务)
|
|
|
await this.updateAllForms(true);
|
|
await this.updateAllForms(true);
|
|
|
|
|
|
|
|
// 移除此处的AVSession更新,避免与onPrepared中的更新冲突
|
|
// 移除此处的AVSession更新,避免与onPrepared中的更新冲突
|
|
@@ -1081,7 +1082,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Failed to update widgets after track change: ${error}`);
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Failed to update widgets after track change: ${error}`);
|
|
|
}
|
|
}
|
|
|
- }, 50); // 减少延迟到50ms,提高响应速度
|
|
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
|
|
await this.handlePlaybackError(error as Error, PlayerErrorType.PLAYBACK_ERROR);
|
|
@@ -2052,6 +2053,9 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 缓存播放器是否已初始化配置,避免重复设置
|
|
|
|
|
+ private isPlayerConfigured: boolean = false;
|
|
|
|
|
+
|
|
|
private async setupPlayerForSong(song: VideoItem): Promise<void> {
|
|
private async setupPlayerForSong(song: VideoItem): Promise<void> {
|
|
|
const ijkPlayer = this.playerManager.getIjkPlayer();
|
|
const ijkPlayer = this.playerManager.getIjkPlayer();
|
|
|
if (!ijkPlayer) {
|
|
if (!ijkPlayer) {
|
|
@@ -2070,8 +2074,14 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
ijkPlayer.setAudioId('unifiedPlayer');
|
|
ijkPlayer.setAudioId('unifiedPlayer');
|
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Reset audio mode for ${song.name}`);
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Reset audio mode for ${song.name}`);
|
|
|
|
|
|
|
|
- // 重新设置配置
|
|
|
|
|
- this.playerManager.setupIjkPlayerOptions();
|
|
|
|
|
|
|
+ // 优化:只在首次或配置变更时重新设置所有选项
|
|
|
|
|
+ if (!this.isPlayerConfigured) {
|
|
|
|
|
+ this.playerManager.setupIjkPlayerOptions();
|
|
|
|
|
+ this.isPlayerConfigured = true;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 快速重置关键配置项,避免完整重新配置
|
|
|
|
|
+ this.setupEssentialPlayerOptions();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
// 设置音量(针对dsf格式特殊处理)
|
|
// 设置音量(针对dsf格式特殊处理)
|
|
|
const volume = this.stateModel.getState().volume;
|
|
const volume = this.stateModel.getState().volume;
|
|
@@ -2085,16 +2095,19 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
ijkPlayer.setDataSource(song.filePath);
|
|
ijkPlayer.setDataSource(song.filePath);
|
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Set data source to ${song.filePath}`);
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService: Set data source to ${song.filePath}`);
|
|
|
|
|
|
|
|
- // 设置HTTP请求头
|
|
|
|
|
- const headers = new Map([
|
|
|
|
|
- ["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
|
|
|
|
|
- ["referer", "https://www.bilibili.com"]
|
|
|
|
|
- ]);
|
|
|
|
|
- ijkPlayer.setDataSourceHeader(headers);
|
|
|
|
|
|
|
+ // 优化:异步设置HTTP请求头和播放速度,不阻塞主流程
|
|
|
|
|
+ Promise.resolve().then(() => {
|
|
|
|
|
+ // 设置HTTP请求头
|
|
|
|
|
+ const headers = new Map([
|
|
|
|
|
+ ["user_agent", "Mozilla/5.0 BiliDroid/7.30.0 (bbcallen@gmail.com)"],
|
|
|
|
|
+ ["referer", "https://www.bilibili.com"]
|
|
|
|
|
+ ]);
|
|
|
|
|
+ ijkPlayer.setDataSourceHeader(headers);
|
|
|
|
|
|
|
|
- // 设置播放速度
|
|
|
|
|
- const speed = this.stateModel.getState().speed;
|
|
|
|
|
- this.playerManager.setPlaybackSpeed(speed.toString() + 'f');
|
|
|
|
|
|
|
+ // 设置播放速度
|
|
|
|
|
+ const speed = this.stateModel.getState().speed;
|
|
|
|
|
+ this.playerManager.setPlaybackSpeed(speed.toString() + 'f');
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
// 设置消息监听器(重要:用于处理播放器内部事件)
|
|
// 设置消息监听器(重要:用于处理播放器内部事件)
|
|
|
ijkPlayer.setMessageListener();
|
|
ijkPlayer.setMessageListener();
|
|
@@ -2103,6 +2116,19 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
console.log("Heanup2 UnifiedPlayerService: 播放器重新设置完成,准备开始新的播放");
|
|
console.log("Heanup2 UnifiedPlayerService: 播放器重新设置完成,准备开始新的播放");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 快速设置关键播放器选项,避免完整重新配置的性能开销
|
|
|
|
|
+ */
|
|
|
|
|
+ private setupEssentialPlayerOptions(): void {
|
|
|
|
|
+ const ijkPlayer = this.playerManager.getIjkPlayer();
|
|
|
|
|
+ if (!ijkPlayer) return;
|
|
|
|
|
+
|
|
|
|
|
+ // 仅设置切换歌曲时必须重置的关键选项
|
|
|
|
|
+ ijkPlayer.native_setup(); // 音频模式初始化
|
|
|
|
|
+ ijkPlayer.setOption(IjkMediaPlayer.OPT_CATEGORY_PLAYER, "start-on-prepared", "0");
|
|
|
|
|
+ ijkPlayer.setScreenOnWhilePlaying(true);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private setupProgressTimer(): void {
|
|
private setupProgressTimer(): void {
|
|
|
this.progressTimer = setInterval(() => {
|
|
this.progressTimer = setInterval(() => {
|
|
|
this.updateProgress();
|
|
this.updateProgress();
|
|
@@ -2726,7 +2752,7 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 更新状态模型中的播放列表状态(同步版本)
|
|
|
|
|
|
|
+ * 更新状态模型中的播放列表状态(同步版本)- 优化防抖
|
|
|
*/
|
|
*/
|
|
|
private updatePlaylistStateInModelSync(): void {
|
|
private updatePlaylistStateInModelSync(): void {
|
|
|
try {
|
|
try {
|
|
@@ -2737,10 +2763,19 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
const hasNext = this.playlistModel.hasNext(playMode);
|
|
const hasNext = this.playlistModel.hasNext(playMode);
|
|
|
const hasPrevious = this.playlistModel.hasPreviousSync(playMode);
|
|
const hasPrevious = this.playlistModel.hasPreviousSync(playMode);
|
|
|
|
|
|
|
|
- this.stateModel.updatePlaylistState(hasNext, hasPrevious, totalCount);
|
|
|
|
|
-
|
|
|
|
|
- LogUtils.getInstance()
|
|
|
|
|
- .LOGI(`Heanup UnifiedPlayerService: Playlist state updated sync - hasNext=${hasNext}, hasPrevious=${hasPrevious}, totalCount=${totalCount}, playMode=${playMode}`);
|
|
|
|
|
|
|
+ // 检查状态是否真的发生了变化,避免频繁的无效更新
|
|
|
|
|
+ const currentState = this.stateModel.getState();
|
|
|
|
|
+ const stateChanged = (
|
|
|
|
|
+ currentState.hasNext !== hasNext ||
|
|
|
|
|
+ currentState.hasPrevious !== hasPrevious ||
|
|
|
|
|
+ currentState.totalCount !== totalCount
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ if (stateChanged) {
|
|
|
|
|
+ this.stateModel.updatePlaylistState(hasNext, hasPrevious, totalCount);
|
|
|
|
|
+ LogUtils.getInstance()
|
|
|
|
|
+ .LOGI(`Heanup UnifiedPlayerService: Playlist state updated sync - hasNext=${hasNext}, hasPrevious=${hasPrevious}, totalCount=${totalCount}, playMode=${playMode}`);
|
|
|
|
|
+ }
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService updatePlaylistStateInModelSync error: ${error}`);
|
|
LogUtils.getInstance().LOGI(`Heanup UnifiedPlayerService updatePlaylistStateInModelSync error: ${error}`);
|
|
|
}
|
|
}
|
|
@@ -3003,11 +3038,20 @@ export class UnifiedPlayerService implements IPlayerService, PlaylistSyncListene
|
|
|
* 将VideoItem和PlayerState数据传入桌面卡片,控制卡片的显示
|
|
* 将VideoItem和PlayerState数据传入桌面卡片,控制卡片的显示
|
|
|
*/
|
|
*/
|
|
|
async updateAllForms(forceUpdate: boolean = false) {
|
|
async updateAllForms(forceUpdate: boolean = false) {
|
|
|
|
|
+ // 增强防抖保护,特别是在APP前台运行时
|
|
|
|
|
+ const now = Date.now();
|
|
|
|
|
+ if (!forceUpdate && this.lastFormUpdateTime && (now - this.lastFormUpdateTime < 200)) {
|
|
|
|
|
+ LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: Skipping due to debounce protection (200ms)');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 防抖和重入保护,防止短时间内重复执行更新
|
|
// 防抖和重入保护,防止短时间内重复执行更新
|
|
|
if (this.isUpdatingForms && !forceUpdate) {
|
|
if (this.isUpdatingForms && !forceUpdate) {
|
|
|
LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: Update already in progress, skipping.');
|
|
LogUtils.getInstance().LOGI('UnifiedPlayerService updateAllForms: Update already in progress, skipping.');
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ this.lastFormUpdateTime = now;
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
this.isUpdatingForms = true;
|
|
this.isUpdatingForms = true;
|