酷狗 KRC 文件的解析
2014-11-18 16:40
471 查看
清理硬盘发现以前写过一个进行一半的代码,这次补全并从硬盘删掉。
格式说明来自 https://shansing.com/read/392/
krc解码并解压缩后得到一个字符串,例子:
[id:$00000000]
[ar:信乐团]
[ti:北京一夜]
[by:韩佯Τé]
[hash:766fe295bf2722a9ede2abdd61d580c1]
[total:278438]
[sign:大家去北京玩一夜吧!!!!]
[53883,3092]<0,632,0>One <632,784,0>Night <1416,372,0>in <1788,548,0>北<2336,755,0>京
[56675,3539]<0,560,0>我<560,416,0>留<976,392,0>下<1368,412,0>许<1780,392,0>多<2172,1366,0>情
[59914,2577]<0,549,0>不<549,276,0>管<825,252,0>你<1077,214,0>爱<1291,182,0>与<1473,212,0>不 <1685,887,0>爱
[62191,3344]<0,560,0>都<560,210,0>是<770,210,0>历<980,204,0>史<1184,202,0>的<1386,564,0>尘<1950,1387,0>埃
开头的几行就不用解释了,lrc也有。
其中快速匹配歌词的可能方式是靠计算歌曲文件的hash,以及匹配歌词与歌曲的total
歌词开始的行格式:
具体代码如下:
KRCLyrics
格式说明来自 https://shansing.com/read/392/
krc解码并解压缩后得到一个字符串,例子:
[id:$00000000]
[ar:信乐团]
[ti:北京一夜]
[by:韩佯Τé]
[hash:766fe295bf2722a9ede2abdd61d580c1]
[total:278438]
[sign:大家去北京玩一夜吧!!!!]
[53883,3092]<0,632,0>One <632,784,0>Night <1416,372,0>in <1788,548,0>北<2336,755,0>京
[56675,3539]<0,560,0>我<560,416,0>留<976,392,0>下<1368,412,0>许<1780,392,0>多<2172,1366,0>情
[59914,2577]<0,549,0>不<549,276,0>管<825,252,0>你<1077,214,0>爱<1291,182,0>与<1473,212,0>不 <1685,887,0>爱
[62191,3344]<0,560,0>都<560,210,0>是<770,210,0>历<980,204,0>史<1184,202,0>的<1386,564,0>尘<1950,1387,0>埃
开头的几行就不用解释了,lrc也有。
其中快速匹配歌词的可能方式是靠计算歌曲文件的hash,以及匹配歌词与歌曲的total
歌词开始的行格式:
[此行开始时刻距0时刻的毫秒数,此行持续的毫秒数]<0,此字持续的毫秒数,0>歌<此字开始的时刻距此行开始时刻的毫秒数,此字持续的毫秒数,0>词<此字开始的时刻距此行开始时刻的毫秒数,此字持续的毫秒数,0>正<此字开始的时刻距此行开始时刻的毫秒数,此字持续的毫秒数,0>文
具体代码如下:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; namespace KRC.KRCLib { /// <summary> /// KRC歌词文件 /// </summary> public class KRCLyrics { public List<KRCLyricsLine> Lines { get { return _lines; } } /// <summary> /// 歌词文本 /// </summary> public string KRCString { get; set; } /// <summary> /// ID (总是$00000000,意义未知) /// </summary> public string ID { get; set; } /// <summary> /// 艺术家 /// </summary> public string Ar { get; set; } /// <summary> /// /// </summary> public string Al { get; set; } /// <summary> /// 标题 /// </summary> public string Title { get; set; } /// <summary> /// 歌词文件作者 /// </summary> public string By { get; set; } /// <summary> /// 歌曲文件Hash /// </summary> public string Hash { get; set; } /// <summary> /// 总时长 /// </summary> public TimeSpan Total { get { //计算总时间=所有行时间 var sum = this.Lines.Select(x => x.LineDuring.TotalMilliseconds).Sum(); return TimeSpan.FromMilliseconds(sum); } } /// <summary> /// 偏移 /// </summary> public TimeSpan Offset { get; set; } private readonly List<KRCLyricsLine> _lines = new List<KRCLyricsLine>(); private readonly List<Tuple<Regex, Action<string>>> _properties; private readonly Regex _regGetValueFromKeyValuePair = new Regex(@"\[(.*):(.*)\]"); /// <summary> /// 默认构造 /// </summary> public KRCLyrics() { //this.Total = TimeSpan.Zero; this.Offset = TimeSpan.Zero; this._properties = new List<Tuple<Regex, Action<string>>>() { new Tuple<Regex, Action<string>>(new Regex("\\[id:[^\\]]+\\]"), (s) => { this.ID = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[al:[^\\n]+\\n"), (s) => { this.Al = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[ar:[^\\]]+\\]"), (s) => { this.Ar = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[ti:[^\\]]+\\]"), (s) => { this.Title = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[hash:[^\\n]+\\n"), (s) => { this.Hash = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[by:[^\\n]+\\n"), (s) => { this.By = s; }), new Tuple<Regex, Action<string>>(new Regex("\\[total:[^\\n]+\\n"), (s) => { //this.Total = TimeSpan.FromMilliseconds(double.Parse(s)); }), new Tuple<Regex, Action<string>>(new Regex("\\[offset:[^\\n]+\\n"), (s) => { this.Offset = TimeSpan.FromMilliseconds(double.Parse(s)); }), }; } /// <summary> /// 构造 /// </summary> /// <param name="krcstring">KRC字符文本</param> private KRCLyrics(string krcstring):this() { this.KRCString = krcstring; this.LoadProperties(); this.LoadLines(); } /// <summary> /// 加载KRC属性 /// </summary> private void LoadProperties() { foreach (var prop in _properties) { var m = prop.Item1.Match(this.KRCString); if (m.Success) { var mm = _regGetValueFromKeyValuePair.Match(m.Value); if (mm.Success && mm.Groups.Count == 3) { prop.Item2(mm.Groups[2].Value); } } } } /// <summary> /// 加载KRC所有行数据 /// </summary> private void LoadLines() { var linesMachCollection = Regex.Matches(this.KRCString, @"\[\d{1,}[^\n]+\n"); foreach (Match m in linesMachCollection) { this.Lines.Add(new KRCLyricsLine(m.Value)); } } /// <summary> /// 保存到文件 /// </summary> /// <param name="outputFilePath"></param> public void SaveToFile(string outputFilePath) { var sb = new StringBuilder(); sb.AppendLine(string.Format("[id:{0}]", this.ID)); if (!string.IsNullOrEmpty(this.Al)) { sb.AppendLine(string.Format("[al:{0}]", this.Al)); } if (!string.IsNullOrEmpty(this.Ar)) { sb.AppendLine(string.Format("[ar:{0}]", this.Ar)); } if (!string.IsNullOrEmpty(this.Title)) { sb.AppendLine(string.Format("[ti:{0}]", this.Title)); } if (!string.IsNullOrEmpty(this.Hash)) { sb.AppendLine(string.Format("[hash:{0}]", this.Hash)); } if (!string.IsNullOrEmpty(this.By)) { sb.AppendLine(string.Format("[by:{0}]", this.By)); } if (this.Total!= TimeSpan.Zero) { sb.AppendLine(string.Format("[total:{0}]", this.Total.TotalMilliseconds)); } if (this.Offset != TimeSpan.Zero) { sb.AppendLine(string.Format("[offset:{0}]", this.Offset.TotalMilliseconds)); } foreach (var line in this.Lines) { sb.AppendLine(line.KRCLineString); } var bytes = KRCFile.EncodeStringToBytes(sb.ToString()); File.WriteAllBytes(outputFilePath, bytes); } /// <summary> /// 从文件加载 /// </summary> /// <param name="inputFilePath"></param> /// <returns></returns> public static KRCLyrics LoadFromFile(string inputFilePath) { var str = KRCFile.DecodeFileToString(inputFilePath); return LoadFromString(str); } /// <summary> /// 从文本加载 /// </summary> /// <param name="krcstring"></param> /// <returns></returns> public static KRCLyrics LoadFromString(string krcstring) { var aa = new KRCLyrics(krcstring); return aa; } } }
KRCLyrics
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using KRC.KRCLib; namespace KRC.Test { class Program { static void Main(string[] args) { string inputFile = @"杨钰莹.桃花运-b0c4014bd991a6a637445defa56822f9.krc"; string outputFile = @"123.krc"; KRCLyrics krc = KRCLyrics.LoadFromFile(inputFile); Console.WriteLine("解码 [{0}] 完毕。", inputFile); krc.SaveToFile(outputFile); Console.WriteLine("另存为 [{0}] 完毕。", outputFile); Console.ReadLine(); } } }
相关文章推荐
- 酷狗的krc歌词文件的解析
- 将酷狗krc歌词解析并转换为lrc歌词php源码
- 酷狗.Krc加密歌词解析
- krc歌词文件解析
- [Qt C++]对酷狗krc文件进行解码
- 将酷狗krc歌词解析并转换为lrc歌词php源码
- [转贴]用正则表达式解析C#文件(Updated)
- 读取eml格式文件,并解析
- [转贴]用正则表达式解析C#文件(Updated)
- [Java学习]使用digester 解析xml配置文件
- 在JSP开发中使用jdom解析临时存放数据的XML文件
- Intel平台下Linux中 ELF文件动态链接的加载、解析及实例分析(一): 加载
- 使用Struts Digester来解析XML文件
- XML文件解析
- 利用hosts文件,完成同一个ip,不同的主机名解析。
- FTP服务的LIST指令获取的文件列表信息的解析
- 用正则表达式解析C#文件(updated)
- 用正则表达式解析C#文件(Updated)
- Asp.net上传文件限制,在大于5M的时候出现DNS解析错误,解决方法。
- vCalendar文件格式解析