歌詞定義フォーマットの、LRCファイルとKRAファイル(タイムタグフォーマット)の変換用WSHスクリプト(JScript)を作成したので公開。KRA -> LRC変換と、LRC -> KRA変換の2つ。WSHスクリプトなので、Windows専用。
[使い方]
- KRA -> LRC変換スクリプトの場合はKRAファイル(*.kra)をドラッグ&ドロップします。
LRC -> KRA変換スクリプトの場合はLRCファイル(*.lrc)をドラッグ&ドロップします。 - KRAファイルの場合は、同じフォルダ上にLRCファイル(KRAファイル名.lrc)が作成されます。
LRCファイルの場合は、同様にKRAファイルが作成されます。
[注意事項]
- 埋め込まれているタグのうち、 タイトル、アーティスト、アルバム、作詞者、曲の長さ、ファイル作成者以外の情報は削除されます。
- UnicodeのBOMが不要な場合は、コメントアウトしてある「// delete BOM」の辺りをコメント解除すると、BOMが削除されます。
- あんまり真面目にテストしてないので、きちんと動かない場合があるかもしれません。
- とりあえず拡張子固定なので、拡張子lrcでKRAフォーマットにしている人や、拡張子txtでフォーマット定義してる人は知ったこっちゃないです。
KRA -> LRC変換WSHスクリプト
/*==== 設定 ==================================================================*/ var inputExt = /.kra$/i; var outputExt = ".lrc"; var inputEncoding = "_autodetect_all"; var outputEncoding = "UTF-8"; /*============================================================================*/ /*==== 定数 ==================================================================*/ // 保存データの種類 // StreamTypeEnum // http://msdn.microsoft.com/ja-jp/library/cc389884.aspx var adTypeBinary = 1; // バイナリ var adTypeText = 2; // テキスト // 読み込み方法 // StreamReadEnum // http://msdn.microsoft.com/ja-jp/library/cc389881.aspx var adReadAll = -1; // 全行 var adReadLine = -2; // 一行ごと // 書き込み方法 // StreamWriteEnum // http://msdn.microsoft.com/ja-jp/library/cc389886.aspx var adWriteChar = 0; // 改行なし var adWriteLine = 1; // 改行あり // ファイルの保存方法 // SaveOptionsEnum // http://msdn.microsoft.com/ja-jp/library/cc389870.aspx var adSaveCreateNotExist = 1; // ない場合は新規作成 var adSaveCreateOverWrite = 2; // ある場合は上書き /*============================================================================*/ var args = WScript.Arguments; if (args.length == 0) { WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。"); WScript.Quit(); } for (var i = 0; i < args.length; i++) { var path = args(i); if (path.match(inputExt) != null) { writeLyrics(path); } } function writeLyrics(path) { var streamReader = new ActiveXObject("ADODB.Stream"); var streamWriter = new ActiveXObject("ADODB.Stream"); try { // read streamReader.Open(); streamReader.Type = adTypeText; streamReader.Position = 0; streamReader.Charset = inputEncoding; streamReader.LoadFromFile( path ); var text = streamReader.ReadText( adReadAll ); if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) { text = text.substr(1); // delete BOM } // replace text = text.replace(/(^s+)|(s+$)/g, ""); text = text.replace(/(rn|n|r|^)[(dd:dd):(dd)]/g, "$1[$2.$3]"); text = text.replace(/[(dd:dd):(dd)]/g, "<$1.$2>"); text = text.replace(/@Title= *(.*?)(rn|n|r|$)/g, "[ti:$1]$2"); text = text.replace(/@Artist= *(.*?)(rn|n|r|$)/g, "[ar:$1]$2"); text = text.replace(/@Album= *(.*?)(rn|n|r|$)/g, "[al:$1]$2"); text = text.replace(/@Lyricist= *(.*?)(rn|n|r|$)/g, "[au:$1]$2"); text = text.replace(/@Length= *(.*?)(rn|n|r|$)/g, "[length:$1]$2"); text = text.replace(/@TaggingBy= *(.*?)(rn|n|r|$)/g, "[by:$1]$2"); var offset = text.match(/@Offset= *(.*?)(rn|n|r|$)/); if (offset && offset.length >= 2) { text = text.replace(/@Offset= *(.*?)(rn|n|r|$)/, "[offset:" + (offset[1] * -1) + "]$2"); } text = text.replace(/(@.*=.*?)(rn|n|r|$)/g, ""); // write streamWriter.Type = adTypeText; streamWriter.Charset = outputEncoding; streamWriter.Open(); streamWriter.WriteText(text, adWriteChar); /* // delete BOM var bomSize = 0; if (outputEncoding == "UTF-8") { bomSize = 3; } else if (outputEncoding.indexOf("UTF-16") == 0) { bomSize = 2; } streamWriter.Position = 0; streamWriter.Type = adTypeBinary; streamWriter.Position = bomSize; var buffer = streamWriter.Read(); streamWriter.Position = 0; streamWriter.Write(buffer); streamWriter.SetEOS(); */ streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite ); } finally { if (streamReader != null) streamReader.Close(); if (streamWriter != null) streamWriter.Close(); } }
LRC -> KRA変換WSHスクリプト
/*==== 設定 ==================================================================*/ var inputExt = /.lrc$/i; var outputExt = ".kra"; var inputEncoding = "_autodetect_all"; var outputEncoding = "UTF-8"; /*============================================================================*/ /*==== 定数 ==================================================================*/ // 保存データの種類 // StreamTypeEnum // http://msdn.microsoft.com/ja-jp/library/cc389884.aspx var adTypeBinary = 1; // バイナリ var adTypeText = 2; // テキスト // 読み込み方法 // StreamReadEnum // http://msdn.microsoft.com/ja-jp/library/cc389881.aspx var adReadAll = -1; // 全行 var adReadLine = -2; // 一行ごと // 書き込み方法 // StreamWriteEnum // http://msdn.microsoft.com/ja-jp/library/cc389886.aspx var adWriteChar = 0; // 改行なし var adWriteLine = 1; // 改行あり // ファイルの保存方法 // SaveOptionsEnum // http://msdn.microsoft.com/ja-jp/library/cc389870.aspx var adSaveCreateNotExist = 1; // ない場合は新規作成 var adSaveCreateOverWrite = 2; // ある場合は上書き /*============================================================================*/ var args = WScript.Arguments; if (args.length == 0) { WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。"); WScript.Quit(); } for (var i = 0; i < args.length; i++) { var path = args(i); if (path.match(inputExt) != null) { writeLyrics(path); } } function writeLyrics(path) { var streamReader = new ActiveXObject("ADODB.Stream"); var streamWriter = new ActiveXObject("ADODB.Stream"); try { // read streamReader.Open(); streamReader.Type = adTypeText; streamReader.Position = 0; streamReader.Charset = inputEncoding; streamReader.LoadFromFile( path ); var text = streamReader.ReadText( adReadAll ); if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) { text = text.substr(1); // delete BOM } // replace text = text.replace(/(^s+)|(s+$)/g, ""); text = text.replace(/<(dd:dd).(dd)>/g, "[$1:$2]"); text = text.replace(/[(dd:dd).(dd)]/g, "[$1:$2]"); text = text.replace(/[ti: *(.*?)]/g, "@Title=$1"); text = text.replace(/[ar: *(.*?)]/g, "@Artist=$1"); text = text.replace(/[al: *(.*?)]/g, "@Album=$1"); text = text.replace(/[au: *(.*?)]/g, "@Lyricist=$1"); text = text.replace(/[length: *(.*?)]/g, "@Length=$1"); text = text.replace(/[by: *(.*?)]/g, "@TaggingBy=$1"); var offset = text.match(/[offset: *(.*?)]/); if (offset && offset.length >= 2) { text = text.replace(/[offset: *(.*?)]/, "@Offset=" + (offset[1] * -1)); } text = text.replace(/[[^d].*?](r?n)?/, ""); text = text + "rn@TimeRatio=1rn"; // write streamWriter.Type = adTypeText; streamWriter.Charset = outputEncoding; streamWriter.Open(); streamWriter.WriteText(text, adWriteChar); /* // delete BOM var bomSize = 0; if (outputEncoding == "UTF-8") { bomSize = 3; } else if (outputEncoding.indexOf("UTF-16") == 0) { bomSize = 2; } streamWriter.Position = 0; streamWriter.Type = adTypeBinary; streamWriter.Position = bomSize; var buffer = streamWriter.Read(); streamWriter.Position = 0; streamWriter.Write(buffer); streamWriter.SetEOS(); */ streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite ); } finally { if (streamReader != null) streamReader.Close(); if (streamWriter != null) streamWriter.Close(); } }
備考
タイムタグ仕様書(一般者向け)で定義されたフォーマットを「KRAフォーマット」と書いてはいますが、「KRAフォーマット」と言う名称はどこにも定義されてないので、便宜上の名前です。
「タイムタグ」や「タイムタグ歌詞」という名称は、LRC等を含めた歌詞定義フォーマット全般で使われる名称なので、フォーマット名称としてはあまり適切ではないと思います。そんなわけで、主に利用される拡張子「KRA」に基づき「KRAフォーマット」と呼称しています。
LRCは「LRCフォーマット」として定義されているため、迷うことはないのですが…。