KRA -> LRC, LRC -> KRA 変換スクリプト

歌詞定義フォーマットの、LRCファイルKRAファイル(タイムタグフォーマット)の変換用WSHスクリプト(JScript)を作成したので公開。KRA -> LRC変換と、LRC -> KRA変換の2つ。WSHスクリプトなので、Windows専用。

[使い方]

  1. KRA -> LRC変換スクリプトの場合はKRAファイル(*.kra)をドラッグ&ドロップします。
    LRC -> KRA変換スクリプトの場合はLRCファイル(*.lrc)をドラッグ&ドロップします。
  2. 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フォーマット」として定義されているため、迷うことはないのですが…。