@@ -405,7 +405,8 @@ class LyricManager {
405405 }
406406 if ( isStale ( ) ) return ;
407407 if ( ! ttmlContent || typeof ttmlContent !== "string" ) return ;
408- const parsed = parseTTML ( ttmlContent ) ;
408+ const sorted = this . sortTTMLTranslations ( ttmlContent ) ;
409+ const parsed = parseTTML ( sorted ) ;
409410 const lines = parsed ?. lines || [ ] ;
410411 if ( ! lines . length ) return ;
411412 result . yrcData = lines ;
@@ -488,7 +489,8 @@ class LyricManager {
488489 if ( ! lyric ) return { lrcData : [ ] , yrcData : [ ] } ;
489490 // TTML 直接返回
490491 if ( format === "ttml" ) {
491- const ttml = parseTTML ( lyric ) ;
492+ const sorted = this . sortTTMLTranslations ( lyric ) ;
493+ const ttml = parseTTML ( sorted ) ;
492494 const lines = ttml ?. lines || [ ] ;
493495 statusStore . usingTTMLLyric = true ;
494496 return { lrcData : [ ] , yrcData : lines } ;
@@ -514,6 +516,58 @@ class LyricManager {
514516 }
515517 }
516518
519+ /**
520+ * 处理 TTML 内容并排序翻译
521+ * @param ttmlContent 原始 TTML 内容
522+ * @param translationOrder 翻译排序顺序
523+ * @returns 排序后的 TTML 内容
524+ */
525+ // 此函数应该在 AMLL 的 TTML 解析器支持多语言翻译后删除
526+ private sortTTMLTranslations (
527+ ttmlContent : string ,
528+ translationOrder : string [ ] = [ "zh-CN" , "zh-Hans" , "zh-TW" , "zh-Hant" ] ,
529+ ) : string {
530+ // 使用 DOMParser 解析 XML 内容
531+ const parser = new DOMParser ( ) ;
532+ const xmlDoc = parser . parseFromString ( ttmlContent , "text/xml" ) ;
533+
534+ // 查找所有歌词行元素
535+ const lyricsElements = xmlDoc . querySelectorAll ( "tt > body > div > p" ) ;
536+
537+ lyricsElements . forEach ( ( element : Element ) => {
538+ // 获取当前歌词行的所有翻译元素
539+ const translationElements = Array . from ( element . children ) . filter (
540+ ( child ) =>
541+ child . hasAttribute ( "ttm:role" ) && child . getAttribute ( "ttm:role" ) === "x-translation" ,
542+ ) ;
543+
544+ // 按照指定顺序对翻译进行排序
545+ translationElements . sort ( ( a , b ) => {
546+ const aLang = a . getAttribute ( "xml:lang" ) || a . getAttribute ( "lang" ) || "" ;
547+ const bLang = b . getAttribute ( "xml:lang" ) || b . getAttribute ( "lang" ) || "" ;
548+
549+ const aIndex = translationOrder . findIndex ( ( lang ) =>
550+ aLang . toLowerCase ( ) . includes ( lang . toLowerCase ( ) ) ,
551+ ) ;
552+ const bIndex = translationOrder . findIndex ( ( lang ) =>
553+ bLang . toLowerCase ( ) . includes ( lang . toLowerCase ( ) ) ,
554+ ) ;
555+
556+ // 如果找不到指定语言,则放在最后
557+ return ( aIndex === - 1 ? Infinity : aIndex ) - ( bIndex === - 1 ? Infinity : bIndex ) ;
558+ } ) ;
559+
560+ // 重新排列翻译元素
561+ translationElements . forEach ( ( translationElement ) => {
562+ element . appendChild ( translationElement ) ; // 移动到末尾以实现排序
563+ } ) ;
564+ } ) ;
565+
566+ // 序列化回字符串
567+ const serializer = new XMLSerializer ( ) ;
568+ return serializer . serializeToString ( xmlDoc ) ;
569+ }
570+
517571 /**
518572 * 检测本地歌词覆盖
519573 * @param id 歌曲 ID
0 commit comments