-
-
Notifications
You must be signed in to change notification settings - Fork 155
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
this brings more advanced lrc parsing as a fallback
- Loading branch information
Showing
7 changed files
with
250 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/// all parsers extend this class | ||
abstract class LyricsParse { | ||
String lyric; | ||
|
||
LyricsParse(this.lyric); | ||
|
||
/// call this method to parse | ||
List<LyricsLineModel> parseLines({bool isMain = true}); | ||
|
||
/// verify [lyric] is matching | ||
bool isOK() => true; | ||
} | ||
|
||
class LyricsLineModel { | ||
String? mainText; | ||
String? extText; | ||
int? startTime; | ||
int? endTime; | ||
List<LyricSpanInfo>? spanList; | ||
|
||
Duration? get timeStamp => startTime == null ? null : Duration(milliseconds: startTime!); | ||
|
||
bool get hasExt => extText?.isNotEmpty == true; | ||
|
||
bool get hasMain => mainText?.isNotEmpty == true; | ||
|
||
List<LyricSpanInfo>? _defaultSpanList; | ||
|
||
get defaultSpanList => _defaultSpanList ??= [ | ||
LyricSpanInfo() | ||
..duration = (endTime ?? 0) - (startTime ?? 0) | ||
..start = startTime ?? 0 | ||
..length = mainText?.length ?? 0 | ||
..raw = mainText ?? "" | ||
]; | ||
} | ||
|
||
class LyricSpanInfo { | ||
int index = 0; | ||
int length = 0; | ||
int duration = 0; | ||
int start = 0; | ||
String raw = ""; | ||
|
||
double drawWidth = 0; | ||
double drawHeight = 0; | ||
|
||
int get end => start + duration; | ||
|
||
int get endIndex => index + length; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import 'models.dart'; | ||
|
||
///normal lyric parser | ||
class LRCParserLrc extends LyricsParse { | ||
RegExp pattern = RegExp(r"\[\d{2}:\d{2}.\d{2,3}]"); | ||
|
||
///匹配普通格式内容 | ||
///eg:[00:03.47] -> 00:03.47 | ||
RegExp valuePattern = RegExp(r"\[(\d{2}:\d{2}.\d{2,3})\]"); | ||
|
||
LRCParserLrc(String lyric) : super(lyric); | ||
|
||
@override | ||
List<LyricsLineModel> parseLines({bool isMain = true}) { | ||
//读每一行 | ||
var lines = lyric.split("\n"); | ||
if (lines.isEmpty) { | ||
return []; | ||
} | ||
List<LyricsLineModel> lineList = []; | ||
for (var line in lines) { | ||
//匹配time | ||
var time = pattern.stringMatch(line); | ||
if (time == null) { | ||
//没有匹配到直接返回 | ||
continue; | ||
} | ||
//移除time,拿到真实歌词 | ||
var realLyrics = line.replaceFirst(pattern, ""); | ||
//转时间戳 | ||
var ts = timeTagToTS(time); | ||
var lineModel = LyricsLineModel()..startTime = ts; | ||
if (realLyrics == "//") { | ||
realLyrics = ""; | ||
} | ||
if (isMain) { | ||
lineModel.mainText = realLyrics; | ||
} else { | ||
lineModel.extText = realLyrics; | ||
} | ||
lineList.add(lineModel); | ||
} | ||
return lineList; | ||
} | ||
|
||
int? timeTagToTS(String timeTag) { | ||
if (timeTag.trim().isEmpty) { | ||
return null; | ||
} | ||
//通过正则取出value | ||
var value = valuePattern.firstMatch(timeTag)?.group(1) ?? ""; | ||
if (value.isEmpty) { | ||
return null; | ||
} | ||
var timeArray = value.split("."); | ||
var padZero = 3 - timeArray.last.length; | ||
var millisecond = timeArray.last.padRight(padZero, "0"); | ||
//避免出现奇葩 | ||
if (millisecond.length > 3) { | ||
millisecond = millisecond.substring(0, 3); | ||
} | ||
var minAndSecArray = timeArray.first.split(":"); | ||
return Duration(minutes: int.parse(minAndSecArray.first), seconds: int.parse(minAndSecArray.last), milliseconds: int.parse(millisecond)).inMilliseconds; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import 'models.dart'; | ||
|
||
///qrc lyric parser | ||
class LRCParserQrc extends LyricsParse { | ||
RegExp advancedPattern = RegExp(r"""\[\d+,\d+]"""); | ||
RegExp qrcPattern = RegExp(r"""\((\d+,\d+)\)"""); | ||
|
||
RegExp advancedValuePattern = RegExp(r"\[(\d*,\d*)\]"); | ||
|
||
LRCParserQrc(String lyric) : super(lyric); | ||
|
||
@override | ||
List<LyricsLineModel> parseLines({bool isMain = true}) { | ||
lyric = RegExp(r"""LyricContent="([\s\S]*)">""").firstMatch(lyric)?.group(1) ?? lyric; | ||
//读每一行 | ||
var lines = lyric.split("\n"); | ||
if (lines.isEmpty) { | ||
return []; | ||
} | ||
List<LyricsLineModel> lineList = []; | ||
for (var line in lines) { | ||
//匹配time | ||
var time = advancedPattern.stringMatch(line); | ||
if (time == null) { | ||
//没有匹配到直接返回 | ||
continue; | ||
} | ||
//转时间戳 | ||
var ts = int.parse(advancedValuePattern.firstMatch(time)?.group(1)?.split(",")[0] ?? "0"); | ||
//移除time,拿到真实歌词 | ||
var realLyrics = line.replaceFirst(advancedPattern, ""); | ||
|
||
List<LyricSpanInfo> spanList = getSpanList(realLyrics); | ||
|
||
var lineModel = LyricsLineModel() | ||
..mainText = realLyrics.replaceAll(qrcPattern, "") | ||
..startTime = ts | ||
..spanList = spanList; | ||
lineList.add(lineModel); | ||
} | ||
return lineList; | ||
} | ||
|
||
///get line span info list | ||
List<LyricSpanInfo> getSpanList(String realLyrics) { | ||
var invalidLength = 0; | ||
var startIndex = 0; | ||
var spanList = qrcPattern.allMatches(realLyrics).map((element) { | ||
var span = LyricSpanInfo(); | ||
|
||
span.raw = realLyrics.substring(startIndex + invalidLength, element.start); | ||
|
||
var elementText = element.group(0) ?? ""; | ||
span.index = startIndex; | ||
span.length = element.start - span.index - invalidLength; | ||
invalidLength += elementText.length; | ||
startIndex += span.length; | ||
|
||
var time = (element.group(1)?.split(",") ?? ["0", "0"]); | ||
span.start = int.parse(time[0]); | ||
span.duration = int.parse(time[1]); | ||
return span; | ||
}).toList(); | ||
return spanList; | ||
} | ||
|
||
@override | ||
bool isOK() { | ||
return lyric.contains("LyricContent=") || advancedPattern.stringMatch(lyric) != null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import 'models.dart'; | ||
import 'parser_lrc.dart'; | ||
import 'parser_qrc.dart'; | ||
|
||
///smart parser | ||
///Parser is automatically selected | ||
class LRCParserSmart extends LyricsParse { | ||
LRCParserSmart(String lyric) : super(lyric); | ||
|
||
@override | ||
List<LyricsLineModel> parseLines({bool isMain = true}) { | ||
var qrc = LRCParserQrc(lyric); | ||
if (qrc.isOK()) { | ||
return qrc.parseLines(isMain: isMain); | ||
} | ||
return LRCParserLrc(lyric).parseLines(isMain: isMain); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters