|
|
@@ -20,7 +20,8 @@ import { EventConstants } from '../common/constants/EventConstants';
|
|
|
import { emitter } from '@kit.BasicServicesKit';
|
|
|
import { setNavidromePlaylist } from '../common/util/NavidromePlaylistStore';
|
|
|
import { navidromeApi } from '../common/network/NavidromeApi';
|
|
|
-
|
|
|
+import { ServerLogUtil } from '../common/util/ServerLogUtil';
|
|
|
+import { RemoteCacheType, resolveCacheFilePath } from '../common/network/RemoteSongCache';
|
|
|
const NAVIDROME_PLAYLIST_ID = 'navidrome-playlist';
|
|
|
|
|
|
interface PlaylistEventData {
|
|
|
@@ -123,6 +124,13 @@ export struct NavidromePage {
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 记录日志开关状态
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `日志状态: ${ServerLogUtil.getLogUploadStatus()}`);
|
|
|
+
|
|
|
+ // 记录账号信息和缓存路径
|
|
|
+ await this.logAccountCacheInfo(account);
|
|
|
+
|
|
|
await this.loadNavidromeLibrary(account);
|
|
|
this.doSortType(this.sortType)
|
|
|
}
|
|
|
@@ -152,31 +160,55 @@ export struct NavidromePage {
|
|
|
const ticket = ++this.loadTicket;
|
|
|
this.loading = true;
|
|
|
this.coverUrlCache.clear();
|
|
|
+
|
|
|
+ // 记录开始加载的信息
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', '开始加载 Navidrome 数据库');
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `服务器: ${ServerLogUtil.sanitizeAccount(account)}`);
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `封面URL缓存已清理,当前缓存数量: ${this.coverUrlCache.size}`);
|
|
|
+
|
|
|
try {
|
|
|
const requestTasks: Promise<object>[] = [
|
|
|
navidromeRestApi.fetchAllSongs(account),
|
|
|
navidromeRestApi.fetchArtists(account),
|
|
|
navidromeRestApi.fetchAlbums(account)
|
|
|
];
|
|
|
+
|
|
|
+ void ServerLogUtil.debug('NavidromeLoad', '并发请求歌曲、艺术家、专辑数据');
|
|
|
const responses = await Promise.all(requestTasks);
|
|
|
const songs = responses[0] as NavidromeRestSong[];
|
|
|
const artistList = responses[1] as NavidromeRestArtist[];
|
|
|
const albumList = responses[2] as NavidromeRestAlbum[];
|
|
|
+
|
|
|
if (ticket !== this.loadTicket) {
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 记录原始数据加载结果
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `原始数据加载完成: 歌曲 ${songs.length} 首, 艺术家 ${artistList.length} 位, 专辑 ${albumList.length} 张`);
|
|
|
+
|
|
|
+ // 处理专辑封面
|
|
|
+ void ServerLogUtil.debug('NavidromeLoad', '开始构建专辑封面映射');
|
|
|
const albumCoverMap = await this.buildAlbumCoverMap(albumList, account);
|
|
|
if (ticket !== this.loadTicket) {
|
|
|
return;
|
|
|
}
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `专辑封面映射完成: ${albumCoverMap.size}/${albumList.length} 张专辑有封面`);
|
|
|
+
|
|
|
+ // 处理艺术家封面
|
|
|
+ void ServerLogUtil.debug('NavidromeLoad', '开始构建艺术家封面映射');
|
|
|
const artistCoverMap = await this.buildArtistCoverMap(artistList, account);
|
|
|
if (ticket !== this.loadTicket) {
|
|
|
return;
|
|
|
}
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `艺术家封面映射完成: ${artistCoverMap.size}/${artistList.length} 位艺术家有封面`);
|
|
|
+
|
|
|
+ // 转换歌曲数据
|
|
|
+ void ServerLogUtil.debug('NavidromeLoad', '开始转换歌曲为VideoItem对象');
|
|
|
const videos = await this.convertSongsToVideoItems(songs, account, albumCoverMap);
|
|
|
if (ticket !== this.loadTicket) {
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
this.allVideos = videos;
|
|
|
this.artists = artistList.map(artist => {
|
|
|
artist.coverUrl = artistCoverMap.get(artist.id);
|
|
|
@@ -186,15 +218,27 @@ export struct NavidromePage {
|
|
|
album.coverUrl = albumCoverMap.get(album.id);
|
|
|
return album;
|
|
|
});
|
|
|
+
|
|
|
+ // 记录最终加载结果
|
|
|
Logger.info('heanup', `Navidrome 已加载: 歌曲 ${songs.length} 首, 艺术家 ${artistList.length} 位, 专辑 ${albumList.length} 张`);
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', `数据转换完成: 歌曲 ${songs.length} -> VideoItem ${videos.length}`);
|
|
|
+ void ServerLogUtil.info('NavidromePage', `加载完成: 歌曲 ${songs.length} / 艺术家 ${artistList.length} / 专辑 ${albumList.length}`);
|
|
|
+ void ServerLogUtil.debug('NavidromePage', `歌曲ID列表: ${songs.slice(0, 50).map(s => s.id).join(',')}${songs.length > 50 ? '...' : ''}`);
|
|
|
+
|
|
|
+ // 记录缓存统计信息
|
|
|
+ await this.logCacheStatistics(account);
|
|
|
+
|
|
|
} catch (error) {
|
|
|
if (ticket === this.loadTicket) {
|
|
|
Logger.error('heanup', `Navidrome 数据加载失败: ${(error as Error).message}`);
|
|
|
+ void ServerLogUtil.error('NavidromeLoad', `数据加载失败: ${(error as Error).message}`);
|
|
|
+ void ServerLogUtil.error('NavidromeLoad', `失败时服务器信息: ${ServerLogUtil.sanitizeAccount(account)}`);
|
|
|
ToastUtil.showToast((error as Error).message ?? 'Navidrome 数据加载失败');
|
|
|
}
|
|
|
} finally {
|
|
|
if (ticket === this.loadTicket) {
|
|
|
this.loading = false;
|
|
|
+ void ServerLogUtil.info('NavidromeLoad', '加载流程结束');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -202,71 +246,137 @@ export struct NavidromePage {
|
|
|
private async buildAlbumCoverMap(albums: NavidromeRestAlbum[], account: WebDavAccount): Promise<Map<string, string>> {
|
|
|
const map = new Map<string, string>();
|
|
|
const tasks: Promise<void>[] = [];
|
|
|
+ let directCoverCount = 0;
|
|
|
+ let generatedCoverCount = 0;
|
|
|
+ let failedCoverCount = 0;
|
|
|
+
|
|
|
+ void ServerLogUtil.info('AlbumCover', `开始处理 ${albums.length} 张专辑的封面`);
|
|
|
+
|
|
|
for (let i = 0; i < albums.length; i++) {
|
|
|
const album = albums[i];
|
|
|
tasks.push((async () => {
|
|
|
try {
|
|
|
+ // 尝试获取直接嵌入的封面路径
|
|
|
const directUrl = this.resolveEmbedCover(account, album.embedArtPath ?? album.coverArtPath);
|
|
|
if (directUrl) {
|
|
|
map.set(album.id, directUrl);
|
|
|
+ directCoverCount++;
|
|
|
+ void ServerLogUtil.debug('AlbumCover', `专辑 ${album.name} 使用直接封面: ${directUrl}`);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 生成封面URL
|
|
|
const coverId = album.coverArt ?? album.coverArtId ?? (album.id ? `al-${album.id}` : undefined);
|
|
|
const url = await this.buildCoverUrl(account, coverId);
|
|
|
if (url) {
|
|
|
map.set(album.id, url);
|
|
|
+ generatedCoverCount++;
|
|
|
+ void ServerLogUtil.debug('AlbumCover', `专辑 ${album.name} 生成封面URL: ${coverId} -> ${url}`);
|
|
|
+ } else {
|
|
|
+ failedCoverCount++;
|
|
|
+ void ServerLogUtil.warn('AlbumCover', `专辑 ${album.name} 无可用封面: ${JSON.stringify({coverArt: album.coverArt, coverArtId: album.coverArtId, id: album.id})}`);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
+ failedCoverCount++;
|
|
|
Logger.warn('heanup', `Navidrome 专辑封面解析失败: ${(error as Error).message}`);
|
|
|
+ void ServerLogUtil.warn('AlbumCover', `专辑 ${album.name} 封面解析失败: ${(error as Error).message}`);
|
|
|
}
|
|
|
})());
|
|
|
}
|
|
|
+
|
|
|
await Promise.all(tasks);
|
|
|
+
|
|
|
+ void ServerLogUtil.info('AlbumCover', `专辑封面处理完成: 直接嵌入 ${directCoverCount}, 生成URL ${generatedCoverCount}, 失败 ${failedCoverCount}`);
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
private async buildArtistCoverMap(artists: NavidromeRestArtist[], account: WebDavAccount): Promise<Map<string, string>> {
|
|
|
const map = new Map<string, string>();
|
|
|
const tasks: Promise<void>[] = [];
|
|
|
+ let directCoverCount = 0;
|
|
|
+ let generatedCoverCount = 0;
|
|
|
+ let failedCoverCount = 0;
|
|
|
+
|
|
|
+ void ServerLogUtil.info('ArtistCover', `开始处理 ${artists.length} 位艺术家的封面`);
|
|
|
+
|
|
|
for (let i = 0; i < artists.length; i++) {
|
|
|
const artist = artists[i];
|
|
|
tasks.push((async () => {
|
|
|
try {
|
|
|
+ // 尝试获取已有图片URL
|
|
|
const directUrl = artist.mediumImageUrl ?? artist.largeImageUrl ?? this.resolveEmbedCover(account, artist.coverArtPath);
|
|
|
if (directUrl) {
|
|
|
map.set(artist.id, directUrl);
|
|
|
+ directCoverCount++;
|
|
|
+ void ServerLogUtil.debug('ArtistCover', `艺术家 ${artist.name} 使用已有图片: ${directUrl}`);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 生成封面URL
|
|
|
const coverId = artist.coverArt ?? artist.coverArtId ?? (artist.id ? `ar-${artist.id}` : undefined);
|
|
|
const url = await this.buildCoverUrl(account, coverId, 256);
|
|
|
if (url) {
|
|
|
map.set(artist.id, url);
|
|
|
+ generatedCoverCount++;
|
|
|
+ void ServerLogUtil.debug('ArtistCover', `艺术家 ${artist.name} 生成封面URL: ${coverId} -> ${url}`);
|
|
|
+ } else {
|
|
|
+ failedCoverCount++;
|
|
|
+ void ServerLogUtil.warn('ArtistCover', `艺术家 ${artist.name} 无可用封面: ${JSON.stringify({coverArt: artist.coverArt, coverArtId: artist.coverArtId, id: artist.id})}`);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
+ failedCoverCount++;
|
|
|
Logger.warn('heanup', `Navidrome 艺术家封面解析失败: ${(error as Error).message}`);
|
|
|
+ void ServerLogUtil.warn('ArtistCover', `艺术家 ${artist.name} 封面解析失败: ${(error as Error).message}`);
|
|
|
}
|
|
|
})());
|
|
|
}
|
|
|
+
|
|
|
await Promise.all(tasks);
|
|
|
+
|
|
|
+ void ServerLogUtil.info('ArtistCover', `艺术家封面处理完成: 直接链接 ${directCoverCount}, 生成URL ${generatedCoverCount}, 失败 ${failedCoverCount}`);
|
|
|
return map;
|
|
|
}
|
|
|
|
|
|
private async convertSongsToVideoItems(songs: NavidromeRestSong[], account: WebDavAccount,
|
|
|
albumCoverMap: Map<string, string>): Promise<VideoItem[]> {
|
|
|
const tasks: Promise<VideoItem>[] = [];
|
|
|
+ let successCount = 0;
|
|
|
+ let failedCount = 0;
|
|
|
+
|
|
|
+ void ServerLogUtil.info('SongConvert', `开始转换 ${songs.length} 首歌曲为 VideoItem`);
|
|
|
+
|
|
|
for (let i = 0; i < songs.length; i++) {
|
|
|
const song = songs[i];
|
|
|
tasks.push((async () => {
|
|
|
- let coverUrl: string | undefined;
|
|
|
try {
|
|
|
- coverUrl = await this.resolveSongCover(song, account, albumCoverMap);
|
|
|
+ let coverUrl: string | undefined;
|
|
|
+ try {
|
|
|
+ coverUrl = await this.resolveSongCover(song, account, albumCoverMap);
|
|
|
+ } catch (error) {
|
|
|
+ Logger.warn('heanup', `Navidrome 单曲封面解析失败: ${(error as Error).message}`);
|
|
|
+ void ServerLogUtil.warn('SongConvert', `歌曲 ${song.title} 封面解析失败: ${(error as Error).message}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const videoItem = this.convertSongToVideoItem(song, account, coverUrl);
|
|
|
+ successCount++;
|
|
|
+
|
|
|
+ // 记录前几首歌的详细信息用于调试
|
|
|
+ if (i < 3) {
|
|
|
+ void ServerLogUtil.debug('SongConvert', `歌曲 ${i + 1}: ${videoItem.name}, 封面: ${coverUrl ? '有' : '无'}, 路径: ${videoItem.filePath}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ return videoItem;
|
|
|
} catch (error) {
|
|
|
- Logger.warn('heanup', `Navidrome 单曲封面解析失败: ${(error as Error).message}`);
|
|
|
+ failedCount++;
|
|
|
+ void ServerLogUtil.error('SongConvert', `歌曲 ${song.title} 转换失败: ${(error as Error).message}`);
|
|
|
+ throw new Error(`歌曲 ${song.title} 转换失败: ${(error as Error).message}`);
|
|
|
}
|
|
|
- return this.convertSongToVideoItem(song, account, coverUrl);
|
|
|
})());
|
|
|
}
|
|
|
- return Promise.all(tasks);
|
|
|
+
|
|
|
+ const results = await Promise.all(tasks);
|
|
|
+ void ServerLogUtil.info('SongConvert', `歌曲转换完成: 成功 ${successCount}, 失败 ${failedCount}`);
|
|
|
+ return results;
|
|
|
}
|
|
|
|
|
|
private async resolveSongCover(song: NavidromeRestSong, account: WebDavAccount,
|
|
|
@@ -293,15 +403,79 @@ export struct NavidromePage {
|
|
|
const cacheKey = `${normalizedId}_${size}`;
|
|
|
const cached = this.coverUrlCache.get(cacheKey);
|
|
|
if (cached) {
|
|
|
+ void ServerLogUtil.debug('CoverCache', `封面URL缓存命中: ${cacheKey} -> ${cached}`);
|
|
|
return cached;
|
|
|
}
|
|
|
+
|
|
|
+ void ServerLogUtil.debug('CoverCache', `生成封面URL: ${coverId} (尺寸: ${size})`);
|
|
|
const url = await navidromeApi.buildCoverArtUrl(account, normalizedId, size);
|
|
|
if (url) {
|
|
|
this.coverUrlCache.set(cacheKey, url);
|
|
|
+ void ServerLogUtil.debug('CoverCache', `封面URL已缓存: ${cacheKey} -> ${url}`);
|
|
|
+ } else {
|
|
|
+ void ServerLogUtil.warn('CoverCache', `封面URL生成失败: ${coverId} (尺寸: ${size})`);
|
|
|
}
|
|
|
return url;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 记录账号缓存信息
|
|
|
+ */
|
|
|
+ private async logAccountCacheInfo(account: WebDavAccount): Promise<void> {
|
|
|
+ try {
|
|
|
+ void ServerLogUtil.info('AccountInfo', `账号信息: ${ServerLogUtil.sanitizeAccount(account)}`);
|
|
|
+
|
|
|
+ // 记录缓存路径信息
|
|
|
+ const accountId = account.id?.toString() || 'unknown';
|
|
|
+
|
|
|
+ // 尝试获取Navidrome缓存路径信息
|
|
|
+ try {
|
|
|
+ const cachePathInfo = await resolveCacheFilePath(RemoteCacheType.WEBDAV, accountId, 'navidrome_test_path');
|
|
|
+ void ServerLogUtil.info('AccountInfo', `Navidrome缓存目录结构:`);
|
|
|
+ void ServerLogUtil.info('AccountInfo', `- 缓存根目录: ${cachePathInfo.cacheDir}`);
|
|
|
+ void ServerLogUtil.info('AccountInfo', `- 示例缓存路径: ${cachePathInfo.cachePath}`);
|
|
|
+ } catch (error) {
|
|
|
+ void ServerLogUtil.warn('AccountInfo', `缓存路径解析失败: ${(error as Error).message}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 记录封面缓存状态
|
|
|
+ void ServerLogUtil.info('AccountInfo', `当前封面URL缓存数量: ${this.coverUrlCache.size}`);
|
|
|
+ if (this.coverUrlCache.size > 0) {
|
|
|
+ const cacheKeys = Array.from(this.coverUrlCache.keys()).slice(0, 10);
|
|
|
+ void ServerLogUtil.debug('AccountInfo', `封面缓存示例: ${cacheKeys.join(', ')}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ void ServerLogUtil.error('AccountInfo', `记录账号信息失败: ${(error as Error).message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 记录缓存统计信息
|
|
|
+ */
|
|
|
+ private async logCacheStatistics(account: WebDavAccount): Promise<void> {
|
|
|
+ try {
|
|
|
+ void ServerLogUtil.info('CacheStats', '=== Navidrome 缓存统计 ===');
|
|
|
+ void ServerLogUtil.info('CacheStats', `封面URL缓存: ${this.coverUrlCache.size} 个条目`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `已加载歌曲: ${this.allVideos.length} 首`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `已处理艺术家: ${this.artists.length} 位`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `已处理专辑: ${this.albums.length} 张`);
|
|
|
+
|
|
|
+ // 计算封面统计
|
|
|
+ const songsWithCover = this.allVideos.filter(song => song.pixelMapPath && song.pixelMapPath.length > 0).length;
|
|
|
+ const albumsWithCover = this.albums.filter(album => album.coverUrl && album.coverUrl.length > 0).length;
|
|
|
+ const artistsWithCover = this.artists.filter(artist => artist.coverUrl && artist.coverUrl.length > 0).length;
|
|
|
+
|
|
|
+ void ServerLogUtil.info('CacheStats', `封面统计:`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `- 歌曲有封面: ${songsWithCover}/${this.allVideos.length} (${Math.round(songsWithCover / this.allVideos.length * 100)}%)`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `- 专辑有封面: ${albumsWithCover}/${this.albums.length} (${Math.round(albumsWithCover / this.albums.length * 100)}%)`);
|
|
|
+ void ServerLogUtil.info('CacheStats', `- 艺术家有封面: ${artistsWithCover}/${this.artists.length} (${Math.round(artistsWithCover / this.artists.length * 100)}%)`);
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ void ServerLogUtil.error('CacheStats', `记录缓存统计失败: ${(error as Error).message}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private resolveEmbedCover(account: WebDavAccount, path?: string): string | undefined {
|
|
|
return navidromeRestApi.resolveResourceUrl(account, path);
|
|
|
}
|
|
|
@@ -552,6 +726,14 @@ export struct NavidromePage {
|
|
|
doSortType(index: number) {
|
|
|
this.sortType = index;
|
|
|
const songs = this.isSearchMode ? this.filteredList :this.allVideos;
|
|
|
+ const sortTypeNames = ['名称升序', '名称降序', '艺术家升序', '艺术家降序', '专辑升序', '专辑降序'];
|
|
|
+ const sortTypeName = sortTypeNames[index] || '未知排序';
|
|
|
+
|
|
|
+ // 记录排序操作
|
|
|
+ void ServerLogUtil.info('NavidromeSort', `应用排序: ${sortTypeName} (${index})`);
|
|
|
+ void ServerLogUtil.info('NavidromeSort', `排序范围: ${songs.length} 首歌曲 (${this.isSearchMode ? '搜索结果' : '全部歌曲'})`);
|
|
|
+
|
|
|
+ const startTime = Date.now();
|
|
|
|
|
|
// 对歌曲列表进行排序
|
|
|
switch (index) {
|
|
|
@@ -593,10 +775,17 @@ export struct NavidromePage {
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ const sortTime = Date.now() - startTime;
|
|
|
+
|
|
|
// 更新显示列表
|
|
|
if (this.isSearchMode) {
|
|
|
this.filteredList = [...songs];
|
|
|
}
|
|
|
+
|
|
|
+ // 记录排序结果
|
|
|
+ void ServerLogUtil.info('NavidromeSort', `排序完成: ${sortTypeName}`);
|
|
|
+ void ServerLogUtil.info('NavidromeSort', `- 排序耗时: ${sortTime}ms`);
|
|
|
+ void ServerLogUtil.debug('NavidromeSort', `排序结果示例: ${songs.slice(0, 3).map(s => `${s.name} (${s.artist})`).join(', ')}`);
|
|
|
}
|
|
|
|
|
|
// 实时搜索逻辑
|
|
|
@@ -604,10 +793,16 @@ export struct NavidromePage {
|
|
|
this.searchText = value.trim();
|
|
|
let mSearchList: Array<VideoItem> = [...this.allVideos];
|
|
|
|
|
|
+ // 记录搜索操作
|
|
|
+ void ServerLogUtil.debug('NavidromeSearch', `搜索输入: "${value}" -> "${this.searchText}"`);
|
|
|
+ void ServerLogUtil.debug('NavidromeSearch', `搜索范围: ${mSearchList.length} 首歌曲`);
|
|
|
+
|
|
|
// 新增条件判断:空输入时显示所有数据
|
|
|
if (this.searchText === '') {
|
|
|
this.filteredList = [...mSearchList]; // 创建新数组以触发状态更新
|
|
|
+ void ServerLogUtil.info('NavidromeSearch', '搜索已清空,显示所有歌曲');
|
|
|
} else {
|
|
|
+ const startTime = Date.now();
|
|
|
this.filteredList = mSearchList.filter((item: VideoItem) => {
|
|
|
// 支持模糊匹配和艺术家 专辑匹配
|
|
|
const regex = new RegExp(this.searchText.toLowerCase().replace(/\s+/g, '.*'), 'i');
|
|
|
@@ -616,8 +811,18 @@ export struct NavidromePage {
|
|
|
regex.test(item.artist?.toLowerCase() ?? "") ||
|
|
|
regex.test(item.album?.toLowerCase() ?? "")
|
|
|
});
|
|
|
- }
|
|
|
+ const searchTime = Date.now() - startTime;
|
|
|
|
|
|
+ // 记录搜索结果
|
|
|
+ void ServerLogUtil.info('NavidromeSearch', `搜索完成: "${this.searchText}"`);
|
|
|
+ void ServerLogUtil.info('NavidromeSearch', `- 搜索耗时: ${searchTime}ms`);
|
|
|
+ void ServerLogUtil.info('NavidromeSearch', `- 匹配结果: ${this.filteredList.length}/${mSearchList.length}`);
|
|
|
+ void ServerLogUtil.debug('NavidromeSearch', `搜索结果示例: ${this.filteredList.slice(0, 3).map(s => `${s.name} (${s.artist})`).join(', ')}`);
|
|
|
+
|
|
|
+ if (this.filteredList.length === 0) {
|
|
|
+ void ServerLogUtil.warn('NavidromeSearch', `搜索无结果: "${this.searchText}"`);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
private getCurrentCount(): number {
|
|
|
@@ -904,7 +1109,14 @@ export struct NavidromePage {
|
|
|
|
|
|
private applyFilter(type: NavFilterType, id: string, label: string): void {
|
|
|
Logger.info('heanup', `应用筛选: type=${type}, id=${id}, label=${label}`);
|
|
|
-
|
|
|
+
|
|
|
+ // 记录筛选操作
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `应用筛选:`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- 类型: ${type} (${type === NavFilterType.Artist ? '艺术家' : type === NavFilterType.Album ? '专辑' : '无'})`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- ID: ${id}`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- 标签: ${label}`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- 筛选前总歌曲数: ${this.allVideos.length}`);
|
|
|
+
|
|
|
// 先更新状态
|
|
|
this.filterType = type;
|
|
|
this.filterId = id;
|
|
|
@@ -913,14 +1125,22 @@ export struct NavidromePage {
|
|
|
this.isSearchMode = false;
|
|
|
this.searchText = '';
|
|
|
this.filteredList = [];
|
|
|
-
|
|
|
+
|
|
|
// 调试日志:检查筛选结果
|
|
|
const visibleSongs = this.getVisibleSongs();
|
|
|
Logger.info('heanup', `筛选后歌曲数量: ${visibleSongs.length}, 总歌曲数: ${this.allVideos.length}`);
|
|
|
if (visibleSongs.length > 0) {
|
|
|
Logger.info('heanup', `第一首歌: ${visibleSongs[0].name}, albumId=${visibleSongs[0].navAlbumId}, album=${visibleSongs[0].album}`);
|
|
|
+
|
|
|
+ // 记录筛选结果详情
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `筛选结果统计:`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- 筛选后歌曲数: ${visibleSongs.length}`);
|
|
|
+ void ServerLogUtil.info('NavidromeFilter', `- 筛选成功率: ${Math.round(visibleSongs.length / this.allVideos.length * 100)}%`);
|
|
|
+ void ServerLogUtil.debug('NavidromeFilter', `筛选结果示例: ${visibleSongs.slice(0, 5).map(s => `${s.name} (${s.artist})`).join(', ')}`);
|
|
|
+ } else {
|
|
|
+ void ServerLogUtil.warn('NavidromeFilter', `筛选结果为空: 未找到匹配的歌曲`);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// 然后执行动画切换标签页
|
|
|
this.getUIContext().animateTo({ duration: 555 }, () => {
|
|
|
this.selectedTab = 0;
|
|
|
@@ -945,10 +1165,26 @@ export struct NavidromePage {
|
|
|
ToastUtil.showToast('Navidrome账号信息不完整,无法播放');
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ // 记录播放详细信息
|
|
|
Logger.info('heanup', `Navidrome 播放歌曲: ${song.name}, 索引: ${index}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `开始播放歌曲: ${song.name} (#${index})`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `歌曲信息:`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- ID: ${song.id}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 艺术家: ${song.artist || '未知'}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 专辑: ${song.album || '未知'}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 文件大小: ${song.size || '未知'}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 时长: ${song.duration || '未知'}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 封面: ${song.pixelMapPath ? '有' : '无'}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `- 播放路径: ${song.filePath}`);
|
|
|
+
|
|
|
const targetIndex = this.allVideos.findIndex(item => item.id === song.id);
|
|
|
const startIndex = targetIndex >= 0 ? targetIndex : index;
|
|
|
+
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `播放列表设置: 起始索引 ${startIndex}, 总数 ${this.allVideos.length}`);
|
|
|
+
|
|
|
setNavidromePlaylist(this.allVideos, startIndex);
|
|
|
+
|
|
|
const playlistData: PlaylistEventData = {
|
|
|
playlistId: NAVIDROME_PLAYLIST_ID,
|
|
|
playlistName: `Navidrome - ${account.name ?? '未知账户'}`,
|
|
|
@@ -957,18 +1193,27 @@ export struct NavidromePage {
|
|
|
isJump: isJump,//设置true会弹出播放页
|
|
|
songFilePaths: this.allVideos.map(item => item.filePath)
|
|
|
};
|
|
|
+
|
|
|
const eventPlaylistPlay: emitter.InnerEvent = { eventId: EventConstants.EVENT_PLAYLIST_PLAY };
|
|
|
emitter.emit(eventPlaylistPlay, { data: playlistData });
|
|
|
+
|
|
|
Logger.info('heanup', `Navidrome 发送播放事件,歌曲数: ${this.allVideos.length}, 起始: ${index}`);
|
|
|
+ void ServerLogUtil.info('NavidromePlay', `播放事件已发送`);
|
|
|
+ void ServerLogUtil.debug('NavidromePlay', `播放事件详情: 列表ID=${playlistData.playlistId}, 列表名称=${playlistData.playlistName}, 歌曲数=${playlistData.songCount}, 起始索引=${playlistData.startIndex}, 是否跳转=${playlistData.isJump}`);
|
|
|
+
|
|
|
if(!this.isNoJumpToHome){
|
|
|
+ void ServerLogUtil.debug('NavidromePlay', '跳转到首页播放器');
|
|
|
// 跳转到首页播放器
|
|
|
this.getUIContext()?.animateTo({ duration: 555 }, () => {
|
|
|
this.mType = 0
|
|
|
})
|
|
|
}
|
|
|
+
|
|
|
} catch (error) {
|
|
|
const err = error as Error;
|
|
|
Logger.error('heanup', '播放歌曲失败: ' + err.message);
|
|
|
+ void ServerLogUtil.error('NavidromePlay', `播放失败: ${err.message}`);
|
|
|
+ void ServerLogUtil.error('NavidromePlay', `失败歌曲信息: ${song.name} (${song.id})`);
|
|
|
ToastUtil.showToast('播放失败');
|
|
|
}
|
|
|
}
|