Procházet zdrojové kódy

修复网盘随机播放-采用渐进式加载分页数据进行随机

chendeben před 6 měsíci
rodič
revize
4db80615d7

+ 58 - 0
entry/src/main/ets/common/util/NavidromePlaylistStore.ets

@@ -2,6 +2,8 @@ import { VideoItem } from '../../viewmodel/VideoItem';
 
 let navidromeVideoItems: VideoItem[] = [];
 let navidromeCurrentPlayIndex: number = 0;
+// 已播放歌曲路径集合(用于渐进式随机播放)
+let playedFilePaths: Set<string> = new Set();
 
 export function setNavidromePlaylist(items: VideoItem[], startIndex: number): void {
   navidromeVideoItems = items.slice();
@@ -19,4 +21,60 @@ export function getNavidromeCurrentPlayIndex(): number {
 export function clearNavidromePlaylist(): void {
   navidromeVideoItems = [];
   navidromeCurrentPlayIndex = 0;
+  playedFilePaths.clear();
+}
+
+// ============ 渐进式随机播放支持 ============
+
+/**
+ * 追加歌曲到播放列表(不替换现有列表,用于扩展播放库)
+ */
+export function appendToNavidromePlaylist(items: VideoItem[]): void {
+  const existingPaths = new Set(navidromeVideoItems.map(v => v.filePath));
+  const newItems = items.filter(item => !existingPaths.has(item.filePath));
+  if (newItems.length > 0) {
+    navidromeVideoItems = [...navidromeVideoItems, ...newItems];
+  }
+}
+
+/**
+ * 标记歌曲已播放
+ */
+export function markAsPlayed(filePath: string): void {
+  playedFilePaths.add(filePath);
+}
+
+/**
+ * 检查歌曲是否已播放
+ */
+export function isPlayed(filePath: string): boolean {
+  return playedFilePaths.has(filePath);
+}
+
+/**
+ * 获取未播放歌曲数量
+ */
+export function getUnplayedCount(): number {
+  return navidromeVideoItems.filter(v => !playedFilePaths.has(v.filePath)).length;
+}
+
+/**
+ * 获取未播放的歌曲列表
+ */
+export function getUnplayedSongs(): VideoItem[] {
+  return navidromeVideoItems.filter(v => !playedFilePaths.has(v.filePath));
+}
+
+/**
+ * 清除已播放记录(重新开始随机)
+ */
+export function clearPlayedHistory(): void {
+  playedFilePaths.clear();
+}
+
+/**
+ * 获取已播放数量
+ */
+export function getPlayedCount(): number {
+  return playedFilePaths.size;
 }

+ 116 - 1
entry/src/main/ets/view/LocalMusic.ets

@@ -3,7 +3,16 @@ import { curves, display, MenuModifier,PiPWindow, promptAction, router, SymbolGl
 import { VideoItem } from '../viewmodel/VideoItem';
 import {  LengthMetrics, SegmentButton,SegmentButtonOptions } from '@kit.ArkUI';
 import { getWebdavVideoItems, getWebdavCurrentPlayIndex } from '../pages/WebDavMainPage';
-import { getNavidromeVideoItems, getNavidromeCurrentPlayIndex } from '../common/util/NavidromePlaylistStore';
+import { 
+  getNavidromeVideoItems, 
+  getNavidromeCurrentPlayIndex,
+  getUnplayedSongs,
+  getUnplayedCount,
+  markAsPlayed,
+  clearPlayedHistory,
+  getPlayedCount
+} from '../common/util/NavidromePlaylistStore';
+import { triggerLoadMoreSongs, hasMoreData } from '../common/util/NavidromeRandomLoader';
 import {
   ImplOnBufferingUpdateListener,
   ImplOnCompletionListener,
@@ -15546,6 +15555,112 @@ export struct LocalMusic {
     // if (!this.debounce()) {
     //   return;
     // }
+
+    // 网盘模式: 渐进式扩展播放库的随机播放
+    // 通过检查当前歌曲类型判断是否为网盘音乐(而非modeType,因为不同网盘类型modeType不同)
+    const isCloudSong = this.currentSong && isRemoteCloudType(this.currentSong.type);
+    if (isCloudSong) {
+      // 阈值常量
+      const UNPLAYED_THRESHOLD = 10; // 剩余未播放歌曲阈值
+      const LOAD_MORE_PAGES = 3;     // 每次加载页数
+      
+      // 获取网盘播放列表
+      const navidromeList = getNavidromeVideoItems();
+      const webdavList = getWebdavVideoItems();
+      const isNavidrome = navidromeList.length > 0;
+      const remoteList = isNavidrome ? navidromeList : webdavList;
+      
+      if (remoteList.length > 0) {
+        // 将当前歌加入历史栈
+        if (this.currentSong) {
+          this.randomPlayHistory.unshift(this.currentSong);
+          if (this.randomPlayHistory.length > 50) {
+            this.randomPlayHistory = this.randomPlayHistory.slice(0, 50);
+          }
+          // 标记当前歌曲为已播放
+          markAsPlayed(this.currentSong.filePath);
+          Logger.info(TAG, `randomPlay(网盘模式): 将当前歌加入历史栈, 栈大小: ${this.randomPlayHistory.length}`);
+        }
+
+        // 检查未播放歌曲数量(仅Navidrome支持渐进式加载)
+        let unplayedCount = isNavidrome ? getUnplayedCount() : remoteList.length;
+        const totalCount = remoteList.length;
+        const playedCount = isNavidrome ? getPlayedCount() : 0;
+        
+        Logger.info(TAG, `randomPlay(网盘模式): 总数${totalCount}, 已播放${playedCount}, 未播放${unplayedCount}`);
+        
+        // 如果未播放数量不足阈值,且还有更多数据,触发加载更多页
+        if (isNavidrome && unplayedCount < UNPLAYED_THRESHOLD && hasMoreData()) {
+          Logger.info(TAG, `randomPlay(网盘模式): 未播放(${unplayedCount})不足阈值(${UNPLAYED_THRESHOLD}),触发加载更多`);
+          const loadSuccess = await triggerLoadMoreSongs(LOAD_MORE_PAGES);
+          if (loadSuccess) {
+            // 重新获取未播放数量
+            unplayedCount = getUnplayedCount();
+            Logger.info(TAG, `randomPlay(网盘模式): 加载完成,未播放数量更新为${unplayedCount}`);
+          }
+        }
+
+        // 从未播放歌曲中随机选择
+        let candidates: VideoItem[];
+        if (isNavidrome) {
+          candidates = getUnplayedSongs();
+          // 如果全部播放完,重置已播放记录
+          if (candidates.length === 0) {
+            Logger.info(TAG, 'randomPlay(网盘模式): 全部播放完毕,重置已播放记录');
+            clearPlayedHistory();
+            // 排除当前歌曲
+            const currentFilePath = this.currentSong?.filePath;
+            candidates = currentFilePath 
+              ? getNavidromeVideoItems().filter(v => v.filePath !== currentFilePath)
+              : getNavidromeVideoItems();
+          }
+        } else {
+          // WebDAV模式:简单排除当前歌曲
+          const currentFilePath = this.currentSong?.filePath;
+          candidates = currentFilePath
+            ? remoteList.filter(v => v.filePath !== currentFilePath)
+            : remoteList;
+        }
+
+        if (candidates.length > 0) {
+          const randomIndex = Math.floor(Math.random() * candidates.length);
+          const randomSong = candidates[randomIndex];
+          
+          // 标记为已播放
+          if (isNavidrome) {
+            markAsPlayed(randomSong.filePath);
+          }
+          
+          Logger.info(TAG, `randomPlay(网盘模式): 从${candidates.length}首候选中随机选择: ${randomSong.name}`);
+
+          // 将选中的歌曲加入播放列表(如果不存在)
+          let nextIndex = this.songList.findIndex(song => song.filePath === randomSong.filePath);
+          if (nextIndex < 0) {
+            this.songList = [...this.songList, randomSong];
+            this.sonDataSource.pushArrayData(this.songList);
+            nextIndex = this.songList.length - 1;
+          }
+          this.curIndex = nextIndex;
+          this.playedIndices.add(this.curIndex);
+
+          this.CONTROL_PlayStatus = PlayStatus.INIT;
+          this.stop();
+          this.currentSong = randomSong;
+
+          // 设置videoUrl
+          this.videoUrl = await setVideoUrlForSong(this.currentSong, {
+            context: this.context,
+            autoParseMusicName: this.autoParseMusicName
+          });
+          this.name = this.currentSong.name;
+          this.artist = this.currentSong.artist;
+          this.changeImageAnimation();
+          return;
+        }
+        Logger.warn(TAG, 'randomPlay(网盘模式): 无可用候选歌曲,回退到默认随机逻辑');
+      }
+    }
+
     if (this.currentSong) {
       // 将当前歌加入到随机播放历史栈(在切换到新歌之前)
       this.randomPlayHistory.unshift(this.currentSong);

+ 41 - 1
entry/src/main/ets/view/NavidromePage.ets

@@ -18,7 +18,8 @@ import { Utility } from '../common/util/Utility';
 import { Constants } from '../Constants';
 import { EventConstants } from '../common/constants/EventConstants';
 import { emitter } from '@kit.BasicServicesKit';
-import { setNavidromePlaylist } from '../common/util/NavidromePlaylistStore';
+import { setNavidromePlaylist, appendToNavidromePlaylist } from '../common/util/NavidromePlaylistStore';
+import { registerLoadMoreCallback, unregisterLoadMoreCallback } from '../common/util/NavidromeRandomLoader';
 import { navidromeApi, NavidromeSong } from '../common/network/NavidromeApi';
 import { ServerLogUtil } from '../common/util/ServerLogUtil';
 import { RemoteDriveManager } from '../common/util/RemoteDriveManager';
@@ -306,9 +307,48 @@ export struct NavidromePage {
       }
     });
 
+    // 注册加载更多页回调(用于渐进式随机播放)
+    this.registerRandomLoadCallback();
+
     this.refreshNavidromeData();
   }
 
+  /**
+   * 注册加载更多页回调函数(供LocalMusic的randomPlay调用)
+   */
+  private registerRandomLoadCallback(): void {
+    registerLoadMoreCallback(
+      // 加载一页数据并返回新增歌曲
+      async (): Promise<VideoItem[]> => {
+        const account = this.resolveActiveAccount();
+        if (!account) {
+          return [];
+        }
+        
+        // 记录加载前的数量
+        const beforeCount = this.allVideos.length;
+        
+        // 加载一页数据(会更新this.allVideos)
+        await this.loadNextSongPage(account);
+        
+        // 获取新增的歌曲
+        const newItems = this.allVideos.slice(beforeCount);
+        
+        // 同步到播放列表存储
+        if (newItems.length > 0) {
+          appendToNavidromePlaylist(newItems);
+          void ServerLogUtil.info('NavidromeRandom', `加载更多: 新增${newItems.length}首,总数${this.allVideos.length}`);
+        }
+        
+        return newItems;
+      },
+      // 检查是否还有更多数据
+      (): boolean => {
+        return this.songNextStart !== null && !this.isSongPageLoading;
+      }
+    );
+  }
+
   private async refreshNavidromeData(showToastWhenMissing: boolean = false): Promise<void> {
     const account = this.resolveActiveAccount();
     if (!account) {

+ 0 - 2
lib/Index.ets

@@ -8,7 +8,6 @@ export { LyricParser } from './src/main/ets/parse/LyricParser'
 
 export { FileParser } from './src/main/ets/parse/FileParser'
 
-export { LyricView } from './src/main/ets/view/LyricView'
 
 export { LyricView2 } from './src/main/ets/view/LyricView2'
 
@@ -16,4 +15,3 @@ export { LyricController } from './src/main/ets/LyricController'
 
 export { LyricHelper } from './src/main/ets/LyricHelper'
 
-export { CcLyricView } from './src/main/ets/view/CcLyricView'

+ 3 - 1
lib/src/main/ets/bean/Lyric.ts

@@ -7,13 +7,15 @@ export class Lyric {
     readonly by: string
     readonly offset: number
     readonly lyricList: Array<LyricLine>
+    readonly isPlainText: boolean // 是否为纯文本歌词(无时间标签)
 
-    constructor(artist: string, title: string, album: string, by: string, offset: number, lyricList: Array<LyricLine>) {
+    constructor(artist: string, title: string, album: string, by: string, offset: number, lyricList: Array<LyricLine>, isPlainText: boolean = false) {
         this.artist = artist
         this.title = title
         this.album = album
         this.by = by
         this.offset = offset
         this.lyricList = lyricList
+        this.isPlainText = isPlainText
     }
 }

+ 2 - 2
lib/src/main/ets/parse/FileParser.ets

@@ -1,6 +1,6 @@
-import { IParser, Lyric, LyricParser } from '@seagazer/cclyric';
+import { IParser, Lyric, LyricParser, LyricLine } from '@seagazer/cclyric';
 import fs from '@ohos.file.fs'
-import { printD } from '../extensions/Extension';
+import { printD, printW } from '../extensions/Extension';
 
 /**
  * Author: seagazer

+ 5 - 23
lib/src/main/ets/parse/LyricParser.ts

@@ -35,7 +35,7 @@ export class LyricParser implements IParser {
 
         // 如果没有时间标签,作为纯文本歌词处理
         if (!hasValidTimeTag) {
-            printD("检测到纯文本歌词(无时间标签),为每行添加默认时间标签");
+            printD("检测到纯文本歌词(无时间标签),不添加时间标签");
             return this.parsePlainTextLyric(src);
         }
 
@@ -355,11 +355,6 @@ export class LyricParser implements IParser {
         let by = ""
         let offset = 0
 
-        // 为纯文本歌词设置一个起始时间(比如从歌曲开始10秒后)
-        // 这样可以避免一播放就滚走
-        const START_TIME = 10000 // 10秒
-        const LINE_INTERVAL = 5000 // 每行间隔5秒
-
         for (let i = 0; i < src.length; i++) {
             let line = src[i].trim()
 
@@ -398,26 +393,13 @@ export class LyricParser implements IParser {
                 continue
             }
 
-            // 为每行设置递增的时间,这样歌词会按顺序显示
-            // 但因为时间间隔较大(5秒),用户可以慢慢阅读
-            let beginTime = START_TIME + (lyricLines.length * LINE_INTERVAL)
-            lyricLines.push(new LyricLine(line, beginTime, -1))
-        }
-
-        // 设置 nextTime
-        for (let i = 0; i < lyricLines.length; i++) {
-            let lyricLine = lyricLines[i]
-            if (i == lyricLines.length - 1) {
-                // 最后一行,设置一个较大的 nextTime 让它持续显示
-                lyricLine.nextTime = lyricLine.beginTime + 60000 // 持续显示1分钟
-            } else {
-                let next = lyricLines[i + 1]
-                lyricLine.nextTime = next.beginTime
-            }
+            // 不添加时间标签,使用 -1 表示纯文本歌词
+            lyricLines.push(new LyricLine(line, -1, -1))
         }
 
         printD(`纯文本歌词解析完成,共 ${lyricLines.length} 行歌词`)
-        let result = new Lyric(artist, title, album, by, offset, lyricLines)
+        // 标记为纯文本歌词
+        let result = new Lyric(artist, title, album, by, offset, lyricLines, true)
         return result
     }
 }

+ 63 - 47
lib/src/main/ets/view/LyricView2.ets

@@ -83,6 +83,11 @@ export struct LyricView2 {
         }, 300)
     }
     private onPositionChangedListener = (mediaPosition: number) => {
+        // 如果是纯文本歌词,不进行位置同步
+        if (this.currentLyric && this.currentLyric.isPlainText) {
+            this.currentMediaPosition = mediaPosition
+            return
+        }
         this.currentMediaPosition = mediaPosition
         this.onPositionChanged(mediaPosition)
     }
@@ -232,7 +237,8 @@ export struct LyricView2 {
             const now = Date.now()
             if (now - this.lastScrollTime  < this.scrollThrottle)  return
             this.lastScrollTime  = now
-            if (this.isUserTouching) {
+            // 纯文本歌词不支持 seek 操作
+            if (this.isUserTouching && !(this.currentLyric && this.currentLyric.isPlainText)) {
                 //修复The value of "index" is out of range. It must be >= 0 && <= -1. Received value is: -1
                 if (center >= 0 && center < this.listAdapter.totalCount()) {
                     this.seekIndex = center;
@@ -258,11 +264,20 @@ export struct LyricView2 {
                     break
                 case TouchType.Up:
                 case TouchType.Cancel:
-                    this.seekUiHideTimeout = setTimeout(() => {
-                        this.seekIndex = -1
-                        this.isUserTouching = false
-                        this.animateToIndex(this.currentIndex)
-                    }, this.autoHideSeekUIDuration)
+                    // 纯文本歌词不需要自动滚动回顶部
+                    if (this.currentLyric && this.currentLyric.isPlainText) {
+                        this.seekUiHideTimeout = setTimeout(() => {
+                            this.seekIndex = -1
+                            this.isUserTouching = false
+                            // 纯文本歌词不调用 animateToIndex,保持在当前位置
+                        }, this.autoHideSeekUIDuration)
+                    } else {
+                        this.seekUiHideTimeout = setTimeout(() => {
+                            this.seekIndex = -1
+                            this.isUserTouching = false
+                            this.animateToIndex(this.currentIndex)
+                        }, this.autoHideSeekUIDuration)
+                    }
             }
         })
     }
@@ -271,62 +286,59 @@ export struct LyricView2 {
     NormalLyricLine(item: LyricLine, index: number) {
         Column(){
             Text(item.text)
-                .fontSize(index == this.currentIndex ?this.textSize*this.controller.getHighlightScale():this.textSize)
+                .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?this.textSize*this.controller.getHighlightScale():this.textSize)
                 .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
-                .fontColor(index == this.currentIndex ? this.textHighlightColor : this.textColor)
-                .fontWeight(index == this.currentIndex && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
+                .fontColor(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor)
+                .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
                 .padding(this.isSingleLine?0:{ top:5,bottom:5 })
                 .visibility(this.isSingleLine?
                     (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                     : Visibility.Visible)
-                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex ?'95%': '80%')
-                // .animation({
-                //     duration: 150,
-                //     curve: Curve.Linear
-                // })
+                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '80%')
+                .animation({
+                    duration: 150,
+                    curve: Curve.Linear
+                })
                 .blendMode(
-                    index == this.currentIndex ? BlendMode.DST_IN : undefined,
-                    index == this.currentIndex ? BlendApplyType.OFFSCREEN : undefined
+                    index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
+                    index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendApplyType.OFFSCREEN : undefined
                 )
 
             // 中文翻译(整行显示)
             if (item.translation)  {
 
             Text(item.translation)
-                .fontSize(index == this.currentIndex ?this.textSize*this.controller.getHighlightScale():this.textSize)
+                .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?this.textSize*this.controller.getHighlightScale():this.textSize)
                 .fontColor(this.currentMediaPosition >= item.beginTime ?
-                    index == this.currentIndex ? this.textHighlightColor : this.textColor : this.textColor)
-                .fontWeight(index == this.currentIndex && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
+                    index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor : this.textColor)
+                .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) && this.isHighlightBold ? FontWeight.Bold : this.textWeight)
                 .padding(this.isSingleLine?{ bottom:2 }:{ bottom:5 })
                 .textAlign(this.alignMode == 'center' ? TextAlign.Center : TextAlign.Start)
                 .visibility(this.isSingleLine?
                     (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
                     : Visibility.Visible)
                 .blendMode(
-                    index == this.currentIndex ? BlendMode.DST_IN : undefined,
-                    index == this.currentIndex ? BlendApplyType.OFFSCREEN : undefined
+                    index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.DST_IN : undefined,
+                    index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendApplyType.OFFSCREEN : undefined
                 )
-                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex ?'95%': '80%')
-                // .animation({
-                //     duration: 150,
-                //     curve: Curve.Linear
-                // })
+                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '80%')
+                .animation({
+                    duration: 150,
+                    curve: Curve.Linear
+                })
 
             }
         }
         // 在 Row 上应用渐变
-        .linearGradient(index == this.currentIndex ? {
+        .linearGradient(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? {
             direction: GradientDirection.Right,
             colors: this.getLyricItemLinearGradient(item, index)
         } : undefined)
         .blendMode(
-            index == this.currentIndex ? BlendMode.SRC_OVER : undefined,
-            index == this.currentIndex ? BlendApplyType.OFFSCREEN : undefined
+            index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendMode.SRC_OVER : undefined,
+            index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? BlendApplyType.OFFSCREEN : undefined
         )
-        .animation({
-            duration: index == this.currentIndex ?150:0,
-            curve: Curve.Linear
-        })
+
 
     }
 
@@ -437,10 +449,10 @@ export struct LyricView2 {
 
 
                     Text(word.word)
-                        .fontSize(index == this.currentIndex ?this.textSize*this.controller.getHighlightScale():this.textSize)
+                        .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?this.textSize*this.controller.getHighlightScale():this.textSize)
                         .fontColor(this.currentMediaPosition >= word.startTime ?
-                            index == this.currentIndex ? this.textHighlightColor : this.textColor : this.textColor)
-                        .fontWeight(index == this.currentIndex? FontWeight.Bold : this.textWeight)
+                            index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor : this.textColor)
+                        .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText)? FontWeight.Bold : this.textWeight)
                         .margin(isEnglish(word.word) ?{ right:4 }:{})
                         .visibility(this.isSingleLine?
                             (index >= this.currentIndex && index <= this.currentIndex + 1 ? Visibility.Visible : Visibility.None)
@@ -457,16 +469,16 @@ export struct LyricView2 {
                 })
             }
             .justifyContent(this.alignMode === 'center' ? FlexAlign.Center : FlexAlign.Start)
-            .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex ?'95%': '85%')
+            .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '85%')
 
             // 中文翻译(整行显示)
             if (item.translation)  {
                 Row({ space: 0 }) {
                     Text(item.translation)
-                        .fontSize(index == this.currentIndex ?this.textSize*this.controller.getHighlightScale():this.textSize)
+                        .fontSize(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?this.textSize*this.controller.getHighlightScale():this.textSize)
                         .fontColor(this.currentMediaPosition >= item.beginTime ?
-                            index == this.currentIndex ? this.textHighlightColor : this.textColor : this.textColor)
-                        .fontWeight(index == this.currentIndex? FontWeight.Bold : this.textWeight)
+                            index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ? this.textHighlightColor : this.textColor : this.textColor)
+                        .fontWeight(index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText)? FontWeight.Bold : this.textWeight)
                         .padding({ bottom:5 })
                         .padding(this.isSingleLine?{ bottom:2 }:{ bottom:5 })
                         .visibility(this.isSingleLine?
@@ -478,7 +490,7 @@ export struct LyricView2 {
                         })
                 }
                 .justifyContent(this.alignMode === 'center' ? FlexAlign.Center : FlexAlign.Start)
-                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex ?'95%': '85%')
+                .width(this.alignMode == 'center' ? '100%' :index == this.currentIndex && !(this.currentLyric && this.currentLyric.isPlainText) ?'95%': '85%')
             }
         }
         .height('auto')
@@ -531,12 +543,6 @@ export struct LyricView2 {
     JumpProgress(){
         Row(){
             Row(){
-                // Divider()
-                //     .width(10)
-                //     .strokeWidth(2)
-                //     .color(Color.Transparent)
-                //     .foregroundBlurStyle(BlurStyle.BACKGROUND_REGULAR,
-                //         { colorMode: ThemeColorMode.LIGHT, adaptiveColor: AdaptiveColor.DEFAULT, scale: 1.0 })
 
                 Row({space: 10}){
                     Text(this.scrollDurationText)
@@ -636,6 +642,12 @@ export struct LyricView2 {
 
         let size = this.listAdapter.totalCount()
         if (size === 0) return 0 // 空列表保护
+
+        // 如果是纯文本歌词,始终返回 0(不滚动)
+        if (this.currentLyric && this.currentLyric.isPlainText) {
+            return 0
+        }
+
         let first = this.listAdapter.getData(0).beginTime
         if (position < first) {
             return 0
@@ -680,6 +692,10 @@ export struct LyricView2 {
             // printW('The lyric lines is empty!')
             return
         }
+        // 如果是纯文本歌词,不进行滚动同步
+        if (this.currentLyric && this.currentLyric.isPlainText) {
+            return
+        }
         let index = this.getIndex(mediaPosition)
         if (index != this.currentIndex) {
             this.animateToIndex(index)