@@ -415,7 +415,8 @@ class LyricManager {
415415 }
416416 if ( isStale ( ) ) return ;
417417 if ( ! ttmlContent || typeof ttmlContent !== "string" ) return ;
418- const parsed = parseTTML ( ttmlContent ) ;
418+ const sorted = this . sortTTMLTranslations ( ttmlContent ) ;
419+ const parsed = parseTTML ( sorted ) ;
419420 const lines = parsed ?. lines || [ ] ;
420421 if ( ! lines . length ) return ;
421422 result . yrcData = lines ;
@@ -498,7 +499,8 @@ class LyricManager {
498499 if ( ! lyric ) return { lrcData : [ ] , yrcData : [ ] } ;
499500 // TTML 直接返回
500501 if ( format === "ttml" ) {
501- const ttml = parseTTML ( lyric ) ;
502+ const sorted = this . sortTTMLTranslations ( lyric ) ;
503+ const ttml = parseTTML ( sorted ) ;
502504 const lines = ttml ?. lines || [ ] ;
503505 statusStore . usingTTMLLyric = true ;
504506 return { lrcData : [ ] , yrcData : lines } ;
@@ -524,6 +526,59 @@ class LyricManager {
524526 }
525527 }
526528
529+ /**
530+ * 处理 TTML 内容并排序翻译
531+ * @param ttmlContent 原始 TTML 内容
532+ * @param translationOrder 翻译排序顺序
533+ * @returns 排序后的 TTML 内容
534+ */
535+ // 此函数应该在 AMLL 的 TTML 解析器支持多语言翻译后删除
536+ private sortTTMLTranslations (
537+ ttmlContent : string ,
538+ translationOrder : string [ ] = [ "zh-CN" , "zh-Hans" , "zh-TW" , "zh-Hant" ] ,
539+ ) : string {
540+ // 使用 DOMParser 解析 XML 内容
541+ const parser = new DOMParser ( ) ;
542+ const xmlDoc = parser . parseFromString ( ttmlContent , "text/xml" ) ;
543+
544+ // 查找所有歌词行元素
545+ const lyricsElements = xmlDoc . querySelectorAll ( "tt > body > div > p" ) ;
546+
547+ lyricsElements . forEach ( ( element : Element ) => {
548+ // 获取当前歌词行的所有翻译元素
549+ const translationElements = Array . from ( element . children ) . filter (
550+ ( child ) =>
551+ child . hasAttribute ( "ttm:role" ) && child . getAttribute ( "ttm:role" ) === "x-translation" ,
552+ ) ;
553+
554+ // 按照指定顺序对翻译进行排序
555+ // 按照指定顺序对翻译进行排序
556+ translationElements . sort ( ( a , b ) => {
557+ const aLang = ( a . getAttribute ( "xml:lang" ) || a . getAttribute ( "lang" ) || "" ) . toLowerCase ( ) ;
558+ const bLang = ( b . getAttribute ( "xml:lang" ) || b . getAttribute ( "lang" ) || "" ) . toLowerCase ( ) ;
559+
560+ const aIndex = translationOrder . findIndex ( ( lang ) =>
561+ aLang . startsWith ( lang . toLowerCase ( ) ) ,
562+ ) ;
563+ const bIndex = translationOrder . findIndex ( ( lang ) =>
564+ bLang . startsWith ( lang . toLowerCase ( ) ) ,
565+ ) ;
566+
567+ // 如果找不到指定语言,则放在最后
568+ return ( aIndex === - 1 ? Infinity : aIndex ) - ( bIndex === - 1 ? Infinity : bIndex ) ;
569+ } ) ;
570+
571+ // 重新排列翻译元素
572+ translationElements . forEach ( ( translationElement ) => {
573+ element . appendChild ( translationElement ) ; // 移动到末尾以实现排序
574+ } ) ;
575+ } ) ;
576+
577+ // 序列化回字符串
578+ const serializer = new XMLSerializer ( ) ;
579+ return serializer . serializeToString ( xmlDoc ) ;
580+ }
581+
527582 /**
528583 * 检测本地歌词覆盖
529584 * @param id 歌曲 ID
0 commit comments