decodeLrcString static method
- 解析歌词文件 .lrc
removeEmptyLine
是否删除包含歌词时间,但内容却为空的行
limitInfoType
限制需要的 info 类型,默认不传入则接收所有的 info
Implementation
static LyricSrcEntity_c decodeLrcString(
String lrcStr, {
bool removeEmptyLine = true,
bool parseHtmlEscape = true,
bool Function(String typeStr)? limitInfoType,
}) {
final lrcObj = LyricSrcEntity_c();
// 按行切割
var lrcArr = lrcStr.split(RegExp(r"\n|\r"));
for (int i = 0; i < lrcArr.length; ++i) {
// 去掉空白符
StringUtilxx_c.removeAllSpace(lrcArr[i]);
if (lrcArr[i].isEmpty) {
// 如果是空行则丢弃这一行
continue;
}
// 逐行解析
final relist = _decodeLrcStrLine(
lrcArr[i],
removeEmptyLine: removeEmptyLine,
parseHtmlEscape: parseHtmlEscape,
);
if (null == relist) {
continue;
}
for (final line in relist) {
switch (line.type) {
case _ParseLyricType_e.Lrc:
lrcObj.lrc.add(LyricSrcItemEntity_c(
time: line.time ?? -1,
content: line.content,
));
break;
case _ParseLyricType_e.Info:
if (true == line.infoKey?.isNotEmpty &&
line.infoKey != "lrc" &&
false != limitInfoType?.call(line.infoKey!)) {
lrcObj.info[line.infoKey!] = line.content;
}
break;
}
}
}
// 排序
// <time, index>
final templist = <MapEntry<double, LyricSrcItemEntity_c>>[];
// 保存最近一次时间为正的值
double lastAvailTime = 0;
// * 将待排序歌词行进行临时时间转换,
// 以保持没有指定时间的歌词行仍然可以跟随在正确的歌词行后面
// 确保app显示解析的正确。
for (int i = 0; i < lrcObj.lrc.length; ++i) {
final item = lrcObj.lrc[i];
if (item.time >= 0) {
// 时间为正,取其时间
lastAvailTime = item.time;
templist.add(MapEntry(item.time, item));
} else {
// 没有指定时间,则回退取最近一行歌词的正的时间
templist.add(MapEntry(lastAvailTime, item));
}
}
// 进行稳定排序
final relist = Utilxx_c.mergeSort<MapEntry<double, LyricSrcItemEntity_c>>(
templist,
(left, right) => ((left.key - right.key) * 1000).toInt(),
);
lrcObj.lrc = [];
for (int i = 0; i < relist.length; ++i) {
lrcObj.lrc.add(relist[i].value);
}
return lrcObj;
}