|
@@ -32,6 +32,13 @@ interface PlaylistEventData {
|
|
|
// 移除webDavAuthInfo,现在直接使用videoItems中的webdav_account_id
|
|
// 移除webDavAuthInfo,现在直接使用videoItems中的webdav_account_id
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+interface WebDavMetadataUpdatePayload {
|
|
|
|
|
+ filePath: string;
|
|
|
|
|
+ pixelMapPath?: string;
|
|
|
|
|
+ name?: string;
|
|
|
|
|
+ artist?: string;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const TAG = 'heanup WebDavMainPage';
|
|
const TAG = 'heanup WebDavMainPage';
|
|
|
|
|
|
|
|
// WebDAV歌曲数据全局内存存储
|
|
// WebDAV歌曲数据全局内存存储
|
|
@@ -92,6 +99,8 @@ export struct WebDavMainPage {
|
|
|
@State isShowFileName: boolean = false//是否显示文件名
|
|
@State isShowFileName: boolean = false//是否显示文件名
|
|
|
@State isLongNameRoLL: boolean = true//长歌名滚动
|
|
@State isLongNameRoLL: boolean = true//长歌名滚动
|
|
|
@State sortType: number = 0 //默认排序方式
|
|
@State sortType: number = 0 //默认排序方式
|
|
|
|
|
+ @State listRefreshKey: number = 0 // 列表刷新标识
|
|
|
|
|
+ private readonly metadataUpdateEvent: emitter.InnerEvent = { eventId: EventConstants.EVENT_WEBDAV_METADATA_UPDATED };
|
|
|
|
|
|
|
|
async onSwitchAccount(){
|
|
async onSwitchAccount(){
|
|
|
console.log('onecold 切换账户:', this.selectedAccount.name);
|
|
console.log('onecold 切换账户:', this.selectedAccount.name);
|
|
@@ -199,6 +208,7 @@ export struct WebDavMainPage {
|
|
|
|
|
|
|
|
// 订阅WebDAV状态变化
|
|
// 订阅WebDAV状态变化
|
|
|
this.webdavManager.subscribe(this.eventHandler);
|
|
this.webdavManager.subscribe(this.eventHandler);
|
|
|
|
|
+ this.subscribeWebDavMetadataUpdates();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 获取顶部安全区高度
|
|
// 获取顶部安全区高度
|
|
@@ -217,6 +227,7 @@ export struct WebDavMainPage {
|
|
|
aboutToDisappear(): void {
|
|
aboutToDisappear(): void {
|
|
|
// 取消订阅
|
|
// 取消订阅
|
|
|
this.webdavManager.unsubscribe(this.eventHandler);
|
|
this.webdavManager.unsubscribe(this.eventHandler);
|
|
|
|
|
+ emitter.off(EventConstants.EVENT_WEBDAV_METADATA_UPDATED);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 处理WebDAV事件
|
|
// 处理WebDAV事件
|
|
@@ -249,6 +260,141 @@ export struct WebDavMainPage {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ private subscribeWebDavMetadataUpdates(): void {
|
|
|
|
|
+ emitter.on(this.metadataUpdateEvent, (eventData: emitter.EventData) => {
|
|
|
|
|
+ const payloads = eventData?.data as WebDavMetadataUpdatePayload[] | undefined;
|
|
|
|
|
+ if (!payloads || payloads.length === 0) {
|
|
|
|
|
+ Logger.info(TAG, 'WebDav metadata event received but payload empty');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Logger.info(TAG, `WebDav metadata event payload count: ${payloads.length}`);
|
|
|
|
|
+ this.handleWebDavMetadataUpdates(payloads);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private handleWebDavMetadataUpdates(payloads: WebDavMetadataUpdatePayload[]): void {
|
|
|
|
|
+ if (!payloads || payloads.length === 0) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ Logger.info(TAG, 'handleWebDavMetadataUpdates start');
|
|
|
|
|
+ let hasChanges = false;
|
|
|
|
|
+ for (let i = 0; i < payloads.length; i++) {
|
|
|
|
|
+ const payload = payloads[i];
|
|
|
|
|
+ if (!payload || !payload.filePath) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ Logger.info(TAG, `WebDav metadata detail path=${payload.pixelMapPath ?? 'null'}`);
|
|
|
|
|
+ const songUpdated = this.updateSongMetadata(payload);
|
|
|
|
|
+ if (songUpdated) {
|
|
|
|
|
+ hasChanges = true;
|
|
|
|
|
+ Logger.info(TAG, `metadata updated for ${payload.filePath}`);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!hasChanges) {
|
|
|
|
|
+ Logger.info(TAG, 'handleWebDavMetadataUpdates no changes detected');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const clonedSongs: VideoItem[] = [];
|
|
|
|
|
+ for (let i = 0; i < this.songs.length; i++) {
|
|
|
|
|
+ clonedSongs.push(this.cloneSong(this.songs[i]));
|
|
|
|
|
+ }
|
|
|
|
|
+ this.songs = clonedSongs;
|
|
|
|
|
+ this.dataSource.pushArrayData(clonedSongs);
|
|
|
|
|
+ this.listRefreshKey++;
|
|
|
|
|
+ Logger.info(TAG, 'handleWebDavMetadataUpdates trigger refresh');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private updateSongMetadata(payload: WebDavMetadataUpdatePayload): boolean {
|
|
|
|
|
+ if (!payload.filePath) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ const targetIndex = this.findSongIndex(payload.filePath);
|
|
|
|
|
+ if (targetIndex < 0) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ const targetSong = this.songs[targetIndex];
|
|
|
|
|
+ let mutated = false;
|
|
|
|
|
+ if (payload.pixelMapPath && payload.pixelMapPath.length > 0) {
|
|
|
|
|
+ targetSong.pixelMapPath = payload.pixelMapPath;
|
|
|
|
|
+ mutated = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload.name && payload.name.length > 0) {
|
|
|
|
|
+ targetSong.name = payload.name;
|
|
|
|
|
+ mutated = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (payload.artist && payload.artist.length > 0) {
|
|
|
|
|
+ targetSong.artist = payload.artist;
|
|
|
|
|
+ mutated = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ return mutated;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private findSongIndex(filePath: string): number {
|
|
|
|
|
+ for (let i = 0; i < this.songs.length; i++) {
|
|
|
|
|
+ if (this.songs[i].filePath === filePath) {
|
|
|
|
|
+ return i;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private cloneSong(item: VideoItem): VideoItem {
|
|
|
|
|
+ const clone = new VideoItem(
|
|
|
|
|
+ item.name,
|
|
|
|
|
+ item.id,
|
|
|
|
|
+ item.filePath,
|
|
|
|
|
+ item.type,
|
|
|
|
|
+ item.videoSize,
|
|
|
|
|
+ item.cTime,
|
|
|
|
|
+ item.pixelMap,
|
|
|
|
|
+ item.size,
|
|
|
|
|
+ item.pixelMapPath,
|
|
|
|
|
+ item.artist,
|
|
|
|
|
+ item.album,
|
|
|
|
|
+ item.fileName,
|
|
|
|
|
+ item.lastPlayed
|
|
|
|
|
+ );
|
|
|
|
|
+ clone.duration = item.duration;
|
|
|
|
|
+ clone.mimeType = item.mimeType;
|
|
|
|
|
+ clone.trackCount = item.trackCount;
|
|
|
|
|
+ clone.sampleRate = item.sampleRate;
|
|
|
|
|
+ clone.size = item.size;
|
|
|
|
|
+ clone.webdav_account_id = item.webdav_account_id;
|
|
|
|
|
+ clone.remote_rel_path = item.remote_rel_path;
|
|
|
|
|
+ clone.artist = item.artist;
|
|
|
|
|
+ clone.album = item.album;
|
|
|
|
|
+ clone.lyricContent = item.lyricContent;
|
|
|
|
|
+ clone.pixelMapPath = item.pixelMapPath;
|
|
|
|
|
+ clone.pixelMap = item.pixelMap;
|
|
|
|
|
+ clone.cTime = item.cTime;
|
|
|
|
|
+ clone.fileName = item.fileName;
|
|
|
|
|
+ clone.md5Str = item.md5Str;
|
|
|
|
|
+ clone.bit_rate = item.bit_rate;
|
|
|
|
|
+ clone.probe_score = item.probe_score;
|
|
|
|
|
+ clone.year = item.year;
|
|
|
|
|
+ clone.nb_streams = item.nb_streams;
|
|
|
|
|
+ clone.nb_programs = item.nb_programs;
|
|
|
|
|
+ clone.genre = item.genre;
|
|
|
|
|
+ clone.track = item.track;
|
|
|
|
|
+ clone.disc = item.disc;
|
|
|
|
|
+ clone.channels = item.channels;
|
|
|
|
|
+ clone.channel_layout = item.channel_layout;
|
|
|
|
|
+ clone.start_time = item.start_time;
|
|
|
|
|
+ clone.ALBUMARTIST = item.ALBUMARTIST;
|
|
|
|
|
+ clone.COMPOSER = item.COMPOSER;
|
|
|
|
|
+ clone.COMMENT = item.COMMENT;
|
|
|
|
|
+ clone.LYRICIST = item.LYRICIST;
|
|
|
|
|
+ clone.pyStr = item.pyStr;
|
|
|
|
|
+ clone.extra_json = item.extra_json;
|
|
|
|
|
+ clone.parentPath = item.parentPath;
|
|
|
|
|
+ clone.isFav = item.isFav;
|
|
|
|
|
+ clone.playCount = item.playCount;
|
|
|
|
|
+ clone.lastPlayed = item.lastPlayed;
|
|
|
|
|
+ clone.videoSize = item.videoSize;
|
|
|
|
|
+ clone.isFav = item.isFav;
|
|
|
|
|
+ return clone;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 加载账户列表
|
|
// 加载账户列表
|
|
|
private loadAccounts(): void {
|
|
private loadAccounts(): void {
|
|
|
this.accounts = this.webdavManager.getAllWebDavAccounts();
|
|
this.accounts = this.webdavManager.getAllWebDavAccounts();
|
|
@@ -951,7 +1097,7 @@ export struct WebDavMainPage {
|
|
|
.transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 1.2, y: 1.2 }).animation({ duration: 600 }),
|
|
.transition(TransitionEffect.asymmetric(TransitionEffect.scale({ x: 1.2, y: 1.2 }).animation({ duration: 600 }),
|
|
|
TransitionEffect.scale({ x: 0, y: 0 })))
|
|
TransitionEffect.scale({ x: 0, y: 0 })))
|
|
|
.clickEffect({ level: ClickEffectLevel.MIDDLE })
|
|
.clickEffect({ level: ClickEffectLevel.MIDDLE })
|
|
|
- }, (item: VideoItem) => item.filePath)
|
|
|
|
|
|
|
+ }, (item: VideoItem) => item.filePath + '_' + this.listRefreshKey)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.contentStartOffset(this.topSafeHeight + 80)
|
|
.contentStartOffset(this.topSafeHeight + 80)
|