@@ -106,7 +106,10 @@ export class AbcParser extends BaseParser<SNAbcInput> {
106106 }
107107
108108 return root . addChildren (
109- scores . map ( ( scoreData ) : SNParserScore => this . parseScore ( scoreData ) ) ,
109+ scores . map (
110+ ( scoreData ) : SNParserScore =>
111+ this . parseScore ( scoreData , parsedFileHeader || undefined ) ,
112+ ) ,
110113 ) ;
111114 }
112115
@@ -188,9 +191,9 @@ export class AbcParser extends BaseParser<SNAbcInput> {
188191 return rootMeta ;
189192 }
190193
191- parseScore ( scoreData : string ) : SNParserScore {
194+ parseScore ( scoreData : string , rootMeta ?: SNRootMeta ) : SNParserScore {
192195 const { head, body } = this . splitScoreHeadAndBody ( scoreData ) ;
193- const { id, meta, props } = this . parseScoreHeader ( head ) ;
196+ const { id, meta, props } = this . parseScoreHeader ( head , rootMeta ) ;
194197 const sections = this . parseScoreBody ( body ) ;
195198
196199 return new SNParserScore ( {
@@ -242,8 +245,13 @@ export class AbcParser extends BaseParser<SNAbcInput> {
242245 /**
243246 * 解析 Score 头部
244247 * 通用布局信息存入 props,ABC 特有元数据存入 meta
248+ * @param header - Score 头部字符串
249+ * @param rootMeta - 文件头元数据(可选,用于读取 %%lyricist 等指令)
245250 */
246- private parseScoreHeader ( header : string ) : {
251+ private parseScoreHeader (
252+ header : string ,
253+ rootMeta ?: SNRootMeta ,
254+ ) : {
247255 id : string | null ;
248256 meta : SNScoreMeta ;
249257 props : SNScoreProps ;
@@ -280,12 +288,36 @@ export class AbcParser extends BaseParser<SNAbcInput> {
280288 props . subtitle = value ;
281289 }
282290 break ;
283- case 'C' :
291+ case 'C' : {
284292 if ( ! props . contributors ) {
285293 props . contributors = [ ] ;
286294 }
287- props . contributors . push ( { name : value , role : 'composer' as const } ) ;
295+ // 支持在 C: 字段中使用前缀来区分作词和作曲
296+ // 格式:C: 作词:张三 或 C: 作曲:李四
297+ const lyricistMatch = value . match ( / ^ 作 词 [ : : ] \s * ( .+ ) $ / ) ;
298+ const composerMatch = value . match ( / ^ 作 曲 [ : : ] \s * ( .+ ) $ / ) ;
299+
300+ if ( lyricistMatch ) {
301+ // 作词者
302+ props . contributors . push ( {
303+ name : lyricistMatch [ 1 ] . trim ( ) ,
304+ role : 'lyricist' as const ,
305+ } ) ;
306+ } else if ( composerMatch ) {
307+ // 作曲者
308+ props . contributors . push ( {
309+ name : composerMatch [ 1 ] . trim ( ) ,
310+ role : 'composer' as const ,
311+ } ) ;
312+ } else {
313+ // 默认作为作曲者(保持向后兼容)
314+ props . contributors . push ( {
315+ name : value ,
316+ role : 'composer' as const ,
317+ } ) ;
318+ }
288319 break ;
320+ }
289321 case 'O' :
290322 meta . origin = value ;
291323 break ;
@@ -379,6 +411,24 @@ export class AbcParser extends BaseParser<SNAbcInput> {
379411 }
380412 }
381413
414+ // 检查文件头是否有 %%lyricist 指令
415+ if ( rootMeta ?. directives ?. lyricist ) {
416+ if ( ! props . contributors ) {
417+ props . contributors = [ ] ;
418+ }
419+ // 检查是否已经存在相同的作词者(避免重复)
420+ const existingLyricist = props . contributors . find (
421+ ( c ) =>
422+ c . role === 'lyricist' && c . name === rootMeta . directives ! . lyricist ,
423+ ) ;
424+ if ( ! existingLyricist ) {
425+ props . contributors . push ( {
426+ name : rootMeta . directives . lyricist ,
427+ role : 'lyricist' as const ,
428+ } ) ;
429+ }
430+ }
431+
382432 return { id, meta, props } ;
383433 }
384434
@@ -597,12 +647,36 @@ export class AbcParser extends BaseParser<SNAbcInput> {
597647 props . subtitle = value ;
598648 }
599649 break ;
600- case 'C' :
650+ case 'C' : {
601651 if ( ! props . contributors ) {
602652 props . contributors = [ ] ;
603653 }
604- props . contributors . push ( { name : value , role : 'composer' as const } ) ;
654+ // 支持在 C: 字段中使用前缀来区分作词和作曲
655+ // 格式:C: 作词:张三 或 C: 作曲:李四
656+ const lyricistMatch = value . match ( / ^ 作 词 [ : : ] \s * ( .+ ) $ / ) ;
657+ const composerMatch = value . match ( / ^ 作 曲 [ : : ] \s * ( .+ ) $ / ) ;
658+
659+ if ( lyricistMatch ) {
660+ // 作词者
661+ props . contributors . push ( {
662+ name : lyricistMatch [ 1 ] . trim ( ) ,
663+ role : 'lyricist' as const ,
664+ } ) ;
665+ } else if ( composerMatch ) {
666+ // 作曲者
667+ props . contributors . push ( {
668+ name : composerMatch [ 1 ] . trim ( ) ,
669+ role : 'composer' as const ,
670+ } ) ;
671+ } else {
672+ // 默认作为作曲者(保持向后兼容)
673+ props . contributors . push ( {
674+ name : value ,
675+ role : 'composer' as const ,
676+ } ) ;
677+ }
605678 break ;
679+ }
606680 case 'M' : {
607681 const timeMatch = value . match ( / ^ ( \d + ) \/ ( \d + ) $ / ) ;
608682 if ( timeMatch ) {
0 commit comments