Просмотр исходного кода

歌词没有时间戳的 也可以显示歌词

onecold 7 месяцев назад
Родитель
Сommit
68791b06aa
1 измененных файлов с 96 добавлено и 8 удалено
  1. 96 8
      lib/src/main/ets/parse/LyricParser.ts

+ 96 - 8
lib/src/main/ets/parse/LyricParser.ts

@@ -8,14 +8,6 @@ import { LyricWord } from '../bean/LyricWord';
  * The parser to parse the string array of a standard lyric file.
  */
 export class LyricParser implements IParser {
-    // Example lyric file:
-    // [ti:画心]
-    // [ar:张靓颖]
-    // [al:432326]
-    // [by:]
-    // [offset:0]
-    // [00:00.10]画心 - 张靓颖
-    // [01:05.49]看不穿 是你失落的魂魄
 
     /**
      * Parse the string array to a Lyric.
@@ -30,6 +22,23 @@ export class LyricParser implements IParser {
         let by = ""
         let offset = 0
         const ignoredTags = [ 'id', 'hash', 'sign', 'qq', 'total','Outro','Intro']; // 定义需要忽略的标签
+
+        // 首先检测是否是纯文本歌词(没有时间标签)
+        let hasValidTimeTag = false;
+        for (let i = 0; i < src.length; i++) {
+            let line = src[i].trim();
+            if (line.length > 0 && /^\[\d{2}:\d{2}\.\d{2,3}\]/.test(line)) {
+                hasValidTimeTag = true;
+                break;
+            }
+        }
+
+        // 如果没有时间标签,作为纯文本歌词处理
+        if (!hasValidTimeTag) {
+            printD("检测到纯文本歌词(无时间标签),为每行添加默认时间标签");
+            return this.parsePlainTextLyric(src);
+        }
+
         for (let i = 0; i < src.length; i++) {
             let line = src[i]
             console.info(`content The line of file:line ${line}`);
@@ -332,4 +341,83 @@ export class LyricParser implements IParser {
 
         return minutes * 60000 + seconds * 1000 + milliseconds;
     }
+
+    /**
+     * 解析纯文本歌词(没有时间标签的歌词)
+     * @param src 歌词行数组
+     * @returns Lyric 对象
+     */
+    private parsePlainTextLyric(src: Array<string>): Lyric {
+        let lyricLines = new Array<LyricLine>()
+        let title = ""
+        let artist = ""
+        let album = ""
+        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()
+
+            // 跳过空行
+            if (line.length === 0 || line === "\n" || line === "\r" || line === "\r\n") {
+                continue
+            }
+
+            // 跳过元数据行(以 [ti:、[ar:、[al:、[by:、[offset: 等开头)
+            if (line.startsWith('[ti:') || line.startsWith('[ar:') || line.startsWith('[al:') ||
+                line.startsWith('[by:') || line.startsWith('[offset:') || line.startsWith('[length:') ||
+                line.startsWith('[id:') || line.startsWith('[hash:') || line.startsWith('[sign:')) {
+                // 解析元数据
+                if (line.startsWith("[ti:")) {
+                    title = this.parseIdTag(line);
+                } else if (line.startsWith("[ar:")) {
+                    artist = this.parseIdTag(line);
+                } else if (line.startsWith("[al:")) {
+                    album = this.parseIdTag(line);
+                } else if (line.startsWith("[by:")) {
+                    by = this.parseIdTag(line);
+                } else if (line.startsWith("[offset:")) {
+                    offset = Number.parseInt(this.parseIdTag(line));
+                }
+                continue
+            }
+
+            // 跳过标签行(如 [Verse]、[Chorus] 等)
+            if (line === "[Verse]" || line === "[Chorus]" || line === "[PreChorus]" ||
+                line === "[Bridge]" || line === "[Intro]" || line === "[Outro]") {
+                continue
+            }
+
+            // 跳过其他以 [ 开头但不是时间标签的行
+            if (line.startsWith('[') && !/^\[\d{2}:\d{2}\.\d{2,3}\]/.test(line)) {
+                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
+            }
+        }
+
+        printD(`纯文本歌词解析完成,共 ${lyricLines.length} 行歌词`)
+        let result = new Lyric(artist, title, album, by, offset, lyricLines)
+        return result
+    }
 }