171 lines
4.3 KiB
C++
171 lines
4.3 KiB
C++
#include "LyricParser.h"
|
|
#include "sys_config.h"
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <regex>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#define ENABLE_PRINT_INFO 1
|
|
#define ENABLE_DEBUG 1
|
|
#if ENABLE_PRINT_INFO
|
|
#define static_print_info(...) sys_ui_log_i(__VA_ARGS__) // 一般信息打印宏控制
|
|
#define static_print_warn(...) sys_ui_log_w(__VA_ARGS__) // 警告信息打印一般常开
|
|
#define static_print_error(...) sys_ui_log_e(__VA_ARGS__) // 错误信息打印一般常开
|
|
#if ENABLE_DEBUG
|
|
#define static_print_debug(...) sys_ui_log_d(__VA_ARGS__) // 调试信息打印一般常开
|
|
#else
|
|
#define static_print_debug(...)
|
|
#endif
|
|
#else
|
|
#define static_print_info(...)
|
|
#define static_print_warn(...)
|
|
#define static_print_error(...)
|
|
#endif
|
|
|
|
// clang-format off
|
|
static const std::string MetaData[7][2] = {
|
|
{"ti", "title"},
|
|
{"al", "album"},
|
|
{"ar", "artist"},
|
|
{"au", "author"},
|
|
{"by", "creator"},
|
|
{"re", "encoder"},
|
|
{"ve", "encoder_version"}
|
|
};
|
|
// clang-format on
|
|
|
|
bool LrcParser::parseLrc(const std::string &lrcFile)
|
|
{
|
|
currentIndex_ = 0;
|
|
lrcData_.clear();
|
|
lyrics_.clear();
|
|
|
|
std::ifstream fin;
|
|
fin.open(lrcFile, std::ios_base::in);
|
|
if (!fin.is_open()) {
|
|
static_print_error("LRC Can't open file %s", lrcFile.c_str());
|
|
return false;
|
|
}
|
|
|
|
std::stringstream buffer;
|
|
buffer << fin.rdbuf();
|
|
lrcData_ = buffer.str();
|
|
fin.close();
|
|
if (lrcData_.empty()) {
|
|
static_print_error("LRC file is empty");
|
|
return false;
|
|
}
|
|
|
|
// 先读取头部
|
|
size_t index = parseHeader();
|
|
if (index == lrcData_.length()) {
|
|
static_print_error("No lyrics_ text");
|
|
return false;
|
|
}
|
|
lrcData_.erase(0, index);
|
|
|
|
std::string line = readLine();
|
|
while (!line.empty()) {
|
|
parseLine(line);
|
|
line = readLine();
|
|
}
|
|
|
|
duration_ = (--lyrics_.end())->first;
|
|
readIndex_ = lyrics_.begin();
|
|
|
|
return true;
|
|
}
|
|
|
|
LyricPacket LrcParser::readPacket()
|
|
{
|
|
LyricPacket packet;
|
|
if (readIndex_ != lyrics_.end()) {
|
|
packet.pts = readIndex_->first;
|
|
packet.lyric = readIndex_->second;
|
|
readIndex_++;
|
|
}
|
|
|
|
return packet;
|
|
}
|
|
|
|
bool LrcParser::seek(int64_t timestamp)
|
|
{
|
|
auto end = --lyrics_.end();
|
|
for (readIndex_ = lyrics_.begin(); readIndex_ != end; readIndex_++) {
|
|
if (readIndex_->first > timestamp) {
|
|
if (readIndex_ != lyrics_.begin()) {
|
|
readIndex_--;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int64_t LrcParser::duration() const { return duration_; }
|
|
|
|
size_t LrcParser::parseHeader()
|
|
{
|
|
size_t offset = 0;
|
|
size_t length = lrcData_.length();
|
|
|
|
if (offset >= length)
|
|
return offset;
|
|
|
|
while (offset < length) {
|
|
std::string meta, data;
|
|
if (lrcData_.at(offset) == '[') {
|
|
while (++offset < length && lrcData_.at(offset) != ':') {
|
|
if (lrcData_.at(offset) >= 'a' && lrcData_.at(offset) <= 'z')
|
|
meta += lrcData_.at(offset);
|
|
else
|
|
return offset - 1;
|
|
}
|
|
|
|
while (++offset < length && lrcData_.at(offset) != ']') {
|
|
data += lrcData_.at(offset);
|
|
}
|
|
}
|
|
|
|
offset++;
|
|
}
|
|
|
|
return offset;
|
|
}
|
|
|
|
void LrcParser::parseLine(const std::string &line)
|
|
{
|
|
std::regex pattern("\\[(\\d+):(\\d+).(\\d+)\\](.*)");
|
|
std::smatch matches;
|
|
|
|
if (std::regex_search(line, matches, pattern)) {
|
|
int64_t minute = std::stoi(matches[1].str()) * 60 * 1000;
|
|
int64_t second = std::stoi(matches[2].str()) * 1000;
|
|
int64_t millisecond =
|
|
matches[3].str().length() == 3 ? std::stoi(matches[3].str()) : std::stoi(matches[3].str()) * 10;
|
|
int64_t pts = minute + second + millisecond;
|
|
std::string data = matches[4].str();
|
|
lyrics_[pts] = data;
|
|
}
|
|
}
|
|
|
|
std::string LrcParser::readLine()
|
|
{
|
|
size_t length = lrcData_.length();
|
|
std::string line;
|
|
while (currentIndex_ < length) {
|
|
if (lrcData_.at(currentIndex_) == '\n') {
|
|
currentIndex_++;
|
|
break;
|
|
} else {
|
|
line += lrcData_.at(currentIndex_);
|
|
currentIndex_++;
|
|
}
|
|
}
|
|
|
|
return line;
|
|
}
|