|
|
@@ -123,6 +123,7 @@ import { showCreatePlaylistDialog } from '../dialog/PlaylistDialog';
|
|
|
import { convertPlaylistSongsToVideoItems, emptyView,updateAllSongsSortOrder } from '../pages/PlaylistDetailPage';
|
|
|
import { Playlist, PlaylistSong } from '../viewmodel/Playlist';
|
|
|
import { Song } from '../viewmodel/Song';
|
|
|
+import { WebDavAccount } from '../viewmodel/WebDavAccount';
|
|
|
import { SongType } from '../common/enums/SongType';
|
|
|
import { RemoteDriveManager, WebDavAuthInfo as WebDavManagerAuthInfo,
|
|
|
buildHttpHeadersWithWebDav,
|
|
|
@@ -869,8 +870,64 @@ export struct LocalMusic {
|
|
|
let eventSetting: emitter.InnerEvent = { eventId: EventConstants.EVENT_SETTING_UPDATE }
|
|
|
// 监听广播事件(通用设置配置更新)
|
|
|
emitter.on(eventSetting, (eventData: emitter.EventData) => {
|
|
|
- this.doChangeSetting()
|
|
|
+ this.initSetting()
|
|
|
+ });
|
|
|
+
|
|
|
+ // 监听 WebDAV 元数据更新事件
|
|
|
+ let eventWebDavMetadata: emitter.InnerEvent = { eventId: EventConstants.EVENT_WEBDAV_METADATA_UPDATED }
|
|
|
+ emitter.on(eventWebDavMetadata, (eventData: emitter.EventData) => {
|
|
|
+ const payloads = eventData?.data as WebDavMetadataUpdatePayload[] | undefined;
|
|
|
+ if (!payloads || payloads.length === 0) {
|
|
|
+ Logger.info(TAG, 'LocalMusic: WebDav metadata event received but payload empty');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Logger.info(TAG, `LocalMusic: WebDav metadata event payload count: ${payloads.length}`);
|
|
|
+
|
|
|
+ // 处理每个元数据更新
|
|
|
+ for (let i = 0; i < payloads.length; i++) {
|
|
|
+ const payload = payloads[i];
|
|
|
+ if (!payload || !payload.filePath) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重要:只更新当前正在播放的歌曲
|
|
|
+ // 如果 filePath 不匹配,说明是其他歌曲的元数据更新,忽略不做处理
|
|
|
+ if (this.currentSong && this.currentSong.filePath === payload.filePath) {
|
|
|
+ Logger.info(TAG, `LocalMusic: 更新当前播放歌曲的元数据: ${payload.filePath}`);
|
|
|
+
|
|
|
+ if (payload.name && payload.name.length > 0) {
|
|
|
+ this.name = payload.name;
|
|
|
+ if (this.currentSong) {
|
|
|
+ this.currentSong.name = payload.name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (payload.artist && payload.artist.length > 0) {
|
|
|
+ this.artist = payload.artist;
|
|
|
+ if (this.currentSong) {
|
|
|
+ this.currentSong.artist = payload.artist;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (payload.pixelMapPath && payload.pixelMapPath.length > 0) {
|
|
|
+ this.cover = payload.pixelMapPath;
|
|
|
+ if (this.currentSong) {
|
|
|
+ this.currentSong.pixelMapPath = payload.pixelMapPath;
|
|
|
+ }
|
|
|
+ Logger.info(TAG, `LocalMusic: 封面已更新: ${payload.pixelMapPath}`);
|
|
|
+ }
|
|
|
|
|
|
+ // 同步更新 AppStorage
|
|
|
+ AppStorage.setOrCreate('currentSong', this.currentSong);
|
|
|
+ } else {
|
|
|
+ Logger.info(TAG, `LocalMusic: 跳过非当前播放歌曲的元数据更新: ${payload.filePath}, 当前: ${this.currentSong?.filePath}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 监听广播事件(通用设置配置更新)
|
|
|
+ emitter.on(eventSetting, (eventData: emitter.EventData) => {
|
|
|
+ this.doChangeSetting()
|
|
|
});
|
|
|
|
|
|
let event: Callback<InterruptEvent> = (event) => {
|
|
|
@@ -1787,6 +1844,7 @@ export struct LocalMusic {
|
|
|
emitter.off(EventConstants.EVENT_SCAN_UPDATE);
|
|
|
emitter.off(EventConstants.EVENT_SWIPE_BACK_UPDATE);
|
|
|
emitter.off(EventConstants.EVENT_SETTING_UPDATE);
|
|
|
+ emitter.off(EventConstants.EVENT_WEBDAV_METADATA_UPDATED);
|
|
|
this.mDestroyPage = true;
|
|
|
this.mIjkMediaPlayer.setScreenOnWhilePlaying(false);
|
|
|
if (this.CONTROL_PlayStatus != PlayStatus.INIT) {
|
|
|
@@ -3030,9 +3088,11 @@ export struct LocalMusic {
|
|
|
Column() {
|
|
|
emptyView(this.themeColor)
|
|
|
}
|
|
|
+ .padding({ right:25 })
|
|
|
.onClick(()=>{
|
|
|
this.asyncCurrentPathOnlyFile()
|
|
|
})
|
|
|
+ .alignItems(HorizontalAlign.Center)
|
|
|
.position({ top: 200 })
|
|
|
.justifyContent(FlexAlign.Center)
|
|
|
.opacity(this.isZero ? 1 : 0)
|
|
|
@@ -15064,6 +15124,8 @@ export struct LocalMusic {
|
|
|
private playedIndices: Set<number> = new Set();
|
|
|
// 存储已播放的本地歌曲路径(随机播放去重用)
|
|
|
private playedLocalFilePaths: Set<string> = new Set();
|
|
|
+ // 随机播放模式下的播放历史栈(记录实际播放顺序,用于"上一首"功能)
|
|
|
+ private randomPlayHistory: VideoItem[] = [];
|
|
|
|
|
|
//随机播放
|
|
|
private async randomPlay() {
|
|
|
@@ -15071,6 +15133,14 @@ export struct LocalMusic {
|
|
|
// return;
|
|
|
// }
|
|
|
if (this.currentSong) {
|
|
|
+ // 将当前歌加入到随机播放历史栈(在切换到新歌之前)
|
|
|
+ this.randomPlayHistory.unshift(this.currentSong);
|
|
|
+ // 限制历史栈大小,避免无限增长
|
|
|
+ if (this.randomPlayHistory.length > 50) {
|
|
|
+ this.randomPlayHistory = this.randomPlayHistory.slice(0, 50);
|
|
|
+ }
|
|
|
+ Logger.info(TAG, `randomPlay: 将当前歌加入历史栈, 栈大小: ${this.randomPlayHistory.length}`);
|
|
|
+
|
|
|
const isCurrentRemote = isRemoteCloudType(this.currentSong.type);
|
|
|
const currentFilePath = this.currentSong.filePath;
|
|
|
if (isCurrentRemote) {
|
|
|
@@ -15080,6 +15150,33 @@ export struct LocalMusic {
|
|
|
};
|
|
|
const randomRemoteSong = await this.table.queryRandomSong(remoteOptions);
|
|
|
if (randomRemoteSong) {
|
|
|
+ // 验证并修正webdav_account_id
|
|
|
+ if (randomRemoteSong.webdav_account_id) {
|
|
|
+ const manager = RemoteDriveManager.getInstance();
|
|
|
+ const account = await manager.getWebDavAccountById(randomRemoteSong.webdav_account_id);
|
|
|
+ if (!account) {
|
|
|
+ Logger.warn(TAG, `随机播放的歌曲账号ID无效: ${randomRemoteSong.webdav_account_id}, 尝试查找同类型账号`);
|
|
|
+ // 获取所有账号,查找相同类型的账号
|
|
|
+ const allAccounts = manager.getAllWebDavAccounts();
|
|
|
+ let foundAccount: WebDavAccount | null = null;
|
|
|
+ for (let i = 0; i < allAccounts.length; i++) {
|
|
|
+ if (allAccounts[i].webType === randomRemoteSong.type) {
|
|
|
+ foundAccount = allAccounts[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (foundAccount && foundAccount.id) {
|
|
|
+ Logger.info(TAG, `找到同类型账号,更新webdav_account_id: ${randomRemoteSong.webdav_account_id} -> ${foundAccount.id}`);
|
|
|
+ randomRemoteSong.webdav_account_id = foundAccount.id.toString();
|
|
|
+ // 更新数据库记录
|
|
|
+ await this.table.updateWebDavAccountId(randomRemoteSong.filePath, foundAccount.id.toString());
|
|
|
+ } else {
|
|
|
+ Logger.error(TAG, `无法找到类型为${randomRemoteSong.type}的账号,跳过此歌曲`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
let nextIndex = this.songList.findIndex(song => song.filePath === randomRemoteSong.filePath);
|
|
|
if (nextIndex < 0) {
|
|
|
this.songList = [...this.songList, randomRemoteSong];
|
|
|
@@ -15269,6 +15366,39 @@ export struct LocalMusic {
|
|
|
this.currentSong = this.songList[this.curIndex];
|
|
|
Logger.info('heanup playPrevious', `直接使用歌曲列表中的信息: ${this.currentSong.name}, type: ${this.currentSong.type}`);
|
|
|
|
|
|
+ // 验证并修正webdav_account_id(针对远程类型歌曲)
|
|
|
+ if (isRemoteCloudType(this.currentSong.type) && this.currentSong.webdav_account_id) {
|
|
|
+ const manager = RemoteDriveManager.getInstance();
|
|
|
+ const account = await manager.getWebDavAccountById(this.currentSong.webdav_account_id);
|
|
|
+ if (!account) {
|
|
|
+ Logger.warn(TAG, `playPrevious: 歌曲账号ID无效: ${this.currentSong.webdav_account_id}, 尝试查找同类型账号`);
|
|
|
+ // 获取所有账号,查找相同类型的账号
|
|
|
+ const allAccounts = manager.getAllWebDavAccounts();
|
|
|
+ let foundAccount: WebDavAccount | null = null;
|
|
|
+ for (let i = 0; i < allAccounts.length; i++) {
|
|
|
+ if (allAccounts[i].webType === this.currentSong.type) {
|
|
|
+ foundAccount = allAccounts[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (foundAccount && foundAccount.id) {
|
|
|
+ Logger.info(TAG, `playPrevious: 找到同类型账号,更新webdav_account_id: ${this.currentSong.webdav_account_id} -> ${foundAccount.id}`);
|
|
|
+ this.currentSong.webdav_account_id = foundAccount.id.toString();
|
|
|
+ // 更新数据库记录
|
|
|
+ await this.table.updateWebDavAccountId(this.currentSong.filePath, foundAccount.id.toString());
|
|
|
+ } else {
|
|
|
+ Logger.error(TAG, `playPrevious: 无法找到类型为${this.currentSong.type}的账号,跳过此歌曲`);
|
|
|
+ // 跳过无效账号的歌曲,继续查找上一首
|
|
|
+ if (this.curIndex == 0) {
|
|
|
+ this.curIndex = this.songList.length - 1;
|
|
|
+ } else {
|
|
|
+ this.curIndex--;
|
|
|
+ }
|
|
|
+ this.currentSong = this.songList[this.curIndex];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 设置videoUrl,WebDAV歌曲会通过webdav_account_id构建完整URL
|
|
|
this.videoUrl = await setVideoUrlForSong(this.currentSong, {
|
|
|
context: this.context,
|
|
|
@@ -15306,51 +15436,67 @@ export struct LocalMusic {
|
|
|
this.changeImageAnimation()
|
|
|
}
|
|
|
|
|
|
- //随机播放模式下点击上一首: 上一首应该应该播放历史记录的第二首
|
|
|
+ //随机播放模式下点击上一首: 播放刚刚播放过的那一首
|
|
|
private async randomModePlayFromHistory() {
|
|
|
- if (this.historyList.length >= 2) {
|
|
|
- // 播放历史记录的第二首
|
|
|
- const prevSong = this.historyList[1];
|
|
|
+ if (this.randomPlayHistory.length >= 1) {
|
|
|
+ // 播放历史栈的第一首(刚刚播放过的)
|
|
|
+ const prevSong = this.randomPlayHistory[0];
|
|
|
+ Logger.info('heanup randomModePlayFromHistory', `从随机播放历史栈获取歌曲: ${prevSong.name}, type: ${prevSong.type}, 栈大小: ${this.randomPlayHistory.length}`);
|
|
|
+
|
|
|
+ // 从栈中移除这首歌(因为即将播放它,它应该成为当前歌,而不是历史)
|
|
|
+ this.randomPlayHistory.shift();
|
|
|
+
|
|
|
this.curIndex = this.songList.findIndex(song => song.filePath === prevSong.filePath);
|
|
|
this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
this.stop();
|
|
|
|
|
|
- // 直接使用历史记录中的歌曲信息,历史记录中的数据应该是完整的
|
|
|
+ // 验证并修正webdav_account_id(针对远程类型歌曲)
|
|
|
+ if (isRemoteCloudType(prevSong.type) && prevSong.webdav_account_id) {
|
|
|
+ const manager = RemoteDriveManager.getInstance();
|
|
|
+ const account = await manager.getWebDavAccountById(prevSong.webdav_account_id);
|
|
|
+ if (!account) {
|
|
|
+ Logger.warn(TAG, `randomModePlayFromHistory: 歌曲账号ID无效: ${prevSong.webdav_account_id}, 尝试查找同类型账号`);
|
|
|
+ const allAccounts = manager.getAllWebDavAccounts();
|
|
|
+ let foundAccount: WebDavAccount | null = null;
|
|
|
+ for (let i = 0; i < allAccounts.length; i++) {
|
|
|
+ if (allAccounts[i].webType === prevSong.type) {
|
|
|
+ foundAccount = allAccounts[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (foundAccount && foundAccount.id) {
|
|
|
+ Logger.info(TAG, `randomModePlayFromHistory: 找到同类型账号,更新webdav_account_id: ${prevSong.webdav_account_id} -> ${foundAccount.id}`);
|
|
|
+ prevSong.webdav_account_id = foundAccount.id.toString();
|
|
|
+ await this.table.updateWebDavAccountId(prevSong.filePath, foundAccount.id.toString());
|
|
|
+ } else {
|
|
|
+ Logger.error(TAG, `randomModePlayFromHistory: 无法找到类型为${prevSong.type}的账号`);
|
|
|
+ // 无法播放这首歌,继续尝试下一首历史记录
|
|
|
+ if (this.randomPlayHistory.length >= 1) {
|
|
|
+ this.randomModePlayFromHistory();
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+ // 历史记录为空,无法继续
|
|
|
+ ToastUtil.showToast('没有更多历史记录');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
this.currentSong = prevSong;
|
|
|
- Logger.info('heanup randomModePlayFromHistory', `直接使用历史歌曲信息: ${prevSong.name}, type: ${prevSong.type}`);
|
|
|
|
|
|
// 设置videoUrl,WebDAV歌曲会通过webdav_account_id构建完整URL
|
|
|
this.videoUrl = await setVideoUrlForSong(this.currentSong, {
|
|
|
context: this.context,
|
|
|
autoParseMusicName: this.autoParseMusicName
|
|
|
});
|
|
|
- this.cover = prevSong.pixelMapPath
|
|
|
- this.artist = prevSong.artist
|
|
|
- this.name = prevSong.name;
|
|
|
- console.info('onecold startPlayOrResumePlay 11434')
|
|
|
+ this.cover = this.currentSong.pixelMapPath
|
|
|
+ this.artist = this.currentSong.artist
|
|
|
+ this.name = this.currentSong.name;
|
|
|
+ console.info('onecold startPlayOrResumePlay randomModePlayFromHistory')
|
|
|
this.startPlayOrResumePlay();
|
|
|
} else {
|
|
|
- // 如果历史记录不足两首,可根据需求处理,这里简单按普通逻辑处理
|
|
|
- if (this.curIndex === 0) {
|
|
|
- this.curIndex = this.songList.length - 1;
|
|
|
- } else {
|
|
|
- this.curIndex--;
|
|
|
- }
|
|
|
- this.CONTROL_PlayStatus = PlayStatus.INIT;
|
|
|
- this.stop();
|
|
|
-
|
|
|
- // 直接使用歌曲列表中的歌曲信息,songList中的数据已经是完整的
|
|
|
- this.currentSong = this.songList[this.curIndex];
|
|
|
- Logger.info('heanup randomModePlayFromHistory', `直接使用歌曲列表中的信息: ${this.currentSong.name}, type: ${this.currentSong.type}`);
|
|
|
-
|
|
|
- // 设置videoUrl,WebDAV歌曲会通过webdav_account_id构建完整URL
|
|
|
- this.videoUrl = await setVideoUrlForSong(this.currentSong, {
|
|
|
- context: this.context,
|
|
|
- autoParseMusicName: this.autoParseMusicName
|
|
|
- });
|
|
|
- this.artist = this.songList[this.curIndex].artist
|
|
|
- this.name = this.songList[this.curIndex].name;
|
|
|
- this.changeImageAnimation()
|
|
|
+ ToastUtil.showToast('随机播放模式暂无历史记录');
|
|
|
}
|
|
|
}
|
|
|
|