Selaa lähdekoodia

优化Navidrome判断fetchSongsWithFilter如果返回空数据,则用搜索的接口去搜索专辑或艺术家 label就是名称

onecold 7 kuukautta sitten
vanhempi
sitoutus
c5d3c8ba93

+ 81 - 8
entry/src/main/ets/common/network/NavidromeRestApi.ets

@@ -1,6 +1,7 @@
 import { http } from '@kit.NetworkKit';
 import { WebDavAccount } from '../../viewmodel/WebDavAccount';
 import { ServerLogUtil } from '../util/ServerLogUtil';
+import { navidromeApi } from './NavidromeApi';
 
 const TAG = 'heanup NavidromeRestApi';
 
@@ -96,23 +97,89 @@ export class NavidromeRestApi {
   }
 
   async fetchArtistPage(account: WebDavAccount, start: number): Promise<NavidromePagedResponse<NavidromeRestArtist>> {
-    return this.fetchPage<NavidromeRestArtist>(account, '/api/artist', start, 'name', 'ASC');
+    return this.fetchPage<NavidromeRestArtist>(account, '/api/artist', start, 'name', 'ASC','albumartist');
   }
 
   async fetchAlbumPage(account: WebDavAccount, start: number): Promise<NavidromePagedResponse<NavidromeRestAlbum>> {
     return this.fetchPage<NavidromeRestAlbum>(account, '/api/album', start, 'name', 'ASC');
   }
 
-  async fetchSongsByArtist(account: WebDavAccount, artistId: string): Promise<NavidromeRestSong[]> {
-    return this.fetchSongsWithFilter(account, [new QueryParam('artist_id', artistId)]);
+  async fetchSongsByArtist(account: WebDavAccount, artistId: string, label?: string): Promise<NavidromeRestSong[]> {
+    // 这里判断fetchSongsWithFilter如果返回空数据,则用搜索的接口去搜索艺术家 label就是艺术家名称
+    const songs = await this.fetchSongsWithFilter(account, [new QueryParam('artist_id', artistId)]);
+
+    // 如果通过 artist_id 查询结果为空,且有艺术家名称,则使用搜索接口
+    if ((!songs || songs.length === 0) && label && label.trim().length > 0) {
+      void ServerLogUtil.warn(TAG, `通过 artist_id 查询为空,尝试搜索艺术家: "${label}"`);
+      try {
+        const searchResults = await navidromeApi.searchSongs(account, label.trim(), 500);
+
+        // 将 NavidromeSong 转换为 NavidromeRestSong
+        if (searchResults && searchResults.length > 0) {
+          void ServerLogUtil.info(TAG, `搜索接口返回 ${searchResults.length} 首歌曲`);
+          return this.convertToRestSongs(searchResults);
+        }
+      } catch (error) {
+        const err = error as Error;
+        void ServerLogUtil.error(TAG, `搜索艺术家歌曲失败: ${err.message}`);
+      }
+    }
+
+    return songs ?? [];
   }
 
-  async fetchSongsByAlbum(account: WebDavAccount, albumId: string): Promise<NavidromeRestSong[]> {
-    return this.fetchSongsWithFilter(account, [new QueryParam('album_id', albumId)]);
+  async fetchSongsByAlbum(account: WebDavAccount, albumId: string, label?: string): Promise<NavidromeRestSong[]> {
+    // 这里判断fetchSongsWithFilter如果返回空数据,则用搜索的接口去搜索专辑 label就是专辑名称
+    const songs = await this.fetchSongsWithFilter(account, [new QueryParam('album_id', albumId)]);
+
+    // 如果通过 album_id 查询结果为空,且有专辑名称,则使用搜索接口
+    if ((!songs || songs.length === 0) && label && label.trim().length > 0) {
+      void ServerLogUtil.warn(TAG, `通过 album_id 查询为空,尝试搜索专辑: "${label}"`);
+      try {
+
+        const searchResults = await navidromeApi.searchSongs(account, label.trim(), 500);
+
+        // 将 NavidromeSong 转换为 NavidromeRestSong
+        if (searchResults && searchResults.length > 0) {
+          void ServerLogUtil.info(TAG, `搜索接口返回 ${searchResults.length} 首歌曲`);
+          return this.convertToRestSongs(searchResults);
+        }
+      } catch (error) {
+        const err = error as Error;
+        void ServerLogUtil.error(TAG, `搜索专辑歌曲失败: ${err.message}`);
+      }
+    }
+
+    return songs ?? [];
+  }
+
+  // 将 NavidromeSong 转换为 NavidromeRestSong
+  private convertToRestSongs(songs: import('./NavidromeApi').NavidromeSong[]): NavidromeRestSong[] {
+    return songs.map((song): NavidromeRestSong => ({
+      id: song.id,
+      title: song.title,
+      artist: song.artist,
+      artistId: song.artistId,
+      album: song.album,
+      albumId: song.albumId,
+      duration: song.duration,
+      bitRate: song.bitRate,
+      suffix: song.suffix,
+      size: song.size,
+      createdAt: song.created,
+      genre: song.genre,
+      track: song.track,
+      year: song.year,
+      contentType: song.contentType,
+      coverArt: song.coverArt,
+      coverArtId: song.coverArt,
+      coverArtPath: undefined,
+      embedArtPath: undefined
+    }));
   }
 
   private async fetchPage<T extends object>(account: WebDavAccount, path: string,
-    start: number, sortField: string, order: 'ASC' | 'DESC'): Promise<NavidromePagedResponse<T>> {
+    start: number, sortField: string, order: 'ASC' | 'DESC',role?:string): Promise<NavidromePagedResponse<T>> {
     const end = start + this.PAGE_SIZE;
     const params: Array<QueryParam> = [
       new QueryParam('_start', `${start}`),
@@ -120,6 +187,9 @@ export class NavidromeRestApi {
       new QueryParam('_sort', sortField),
       new QueryParam('_order', order)
     ];
+    if(role){
+      params.push(new QueryParam('_role', role));
+    }
     void ServerLogUtil.debug(TAG, `${path} 分页请求: start=${start}, end=${end}`);
     const chunk = await this.get<T[]>(account, path, params);
     const nextStart = chunk && chunk.length === this.PAGE_SIZE ? end : null;
@@ -221,7 +291,9 @@ export class NavidromeRestApi {
         readTimeout: 15000,
         expectDataType: http.HttpDataType.STRING,
         header: {
-          'Content-Type': 'application/json'
+          'Content-Type': 'application/json; charset=utf-8',
+          'Accept': 'application/json; charset=utf-8',
+          'Accept-Charset': 'utf-8'
         },
         extraData: JSON.stringify(this.buildLoginBody(username, password))
       });
@@ -252,7 +324,8 @@ export class NavidromeRestApi {
     return {
       'x-nd-authorization': `Bearer ${auth.token}`,
       'x-nd-client-unique-id': auth.clientId,
-      'Accept': 'application/json'
+      'Accept': 'application/json; charset=utf-8',
+      'Accept-Charset': 'utf-8'
     };
   }
 

+ 4 - 6
entry/src/main/ets/view/NavidromePage.ets

@@ -1401,7 +1401,7 @@ export struct NavidromePage {
     this.isFilterLoading = true;
 
     // 调试日志:检查筛选结果
-    void this.loadSongsForFilter().catch((error: Error) => {
+    void this.loadSongsForFilter(label).catch((error: Error) => {
       void ServerLogUtil.error('NavidromeFilter', `筛选歌曲加载失败: ${error.message}`);
       ToastUtil.showToast(error.message || '筛选数据加载失败');
     });
@@ -1409,7 +1409,7 @@ export struct NavidromePage {
     // 不再自动切换标签页,保持在详情视图模式
   }
 
-  private async loadSongsForFilter(): Promise<void> {
+  private async loadSongsForFilter(label:string): Promise<void> {
     if (this.filterType === NavFilterType.None || !this.filterId) {
       this.filterSongs = [];
       this.isFilterLoading = false;
@@ -1426,9 +1426,9 @@ export struct NavidromePage {
     try {
       let songs: NavidromeRestSong[] = [];
       if (this.filterType === NavFilterType.Artist) {
-        songs = await navidromeRestApi.fetchSongsByArtist(account, this.filterId);
+        songs = await navidromeRestApi.fetchSongsByArtist(account, this.filterId,label);
       } else if (this.filterType === NavFilterType.Album) {
-        songs = await navidromeRestApi.fetchSongsByAlbum(account, this.filterId);
+        songs = await navidromeRestApi.fetchSongsByAlbum(account, this.filterId,label);
       }
       const videoItems = await this.convertSongsToVideoItems(songs, account);
       if (expectedFilterId !== this.filterId || expectedFilterType !== this.filterType) {
@@ -1600,10 +1600,8 @@ export struct NavidromePage {
             const currentOffsetY = this.scroller.currentOffset().yOffset;
             // 判断滚动方向
             if (currentOffsetY > this.prevOffsetY) {
-              console.log("onecold 向上滚动");
               this.isShowTitleBar = false
             } else if (currentOffsetY < this.prevOffsetY) {
-              console.log("onecold 向下滚动");
               this.isShowTitleBar = true
             }
             // 更新前一次偏移量