6 #include <QRegularExpression>
7 #include <QDomDocument>
16 static const QRegularExpression
kTimeCode { R
"(^(\[(\d\d):(\d\d)(?:\.(\d\d))?\])(.*))" };
95 slist <<
"MUSIC_LYRICS_FIND"
111 LOG(VB_NETWORK, LOG_INFO, QString(
"LyricsData:: Sending command %1").
arg(slist.join(
'~')));
128 slist <<
"MUSIC_LYRICS_SAVE"
139 QDomDocument
doc(
"lyrics");
141 QDomElement
root =
doc.createElement(
"lyrics");
145 QDomElement
artist =
doc.createElement(
"artist");
150 QDomElement
album =
doc.createElement(
"album");
155 QDomElement
title =
doc.createElement(
"title");
165 QDomElement
grabber =
doc.createElement(
"grabber");
174 QDomElement lyric =
doc.createElement(
"lyric");
175 root.appendChild(lyric);
180 return doc.toString(4);
187 auto *me =
dynamic_cast<MythEvent*
>(event);
192 if (me->Message().startsWith(
"MUSIC_LYRICS_"))
194 QStringList list = me->
Message().simplified().split(
' ');
196 if (list.size() >= 2)
198 uint songID = list[1].toUInt();
203 if (list[0] ==
"MUSIC_LYRICS_FOUND")
207 QString xmlData = me->Message().section(
" ", 2, -1);
213 else if (list[0] ==
"MUSIC_LYRICS_STATUS")
237 if (!domDoc.setContent(xmlData,
false, &errorMsg, &errorLine, &errorColumn))
239 LOG(VB_GENERAL, LOG_ERR,
240 QString(
"LyricsData:: Could not parse lyrics from %1").
arg(xmlData) +
241 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").
arg(errorLine).
arg(errorColumn).
arg(errorMsg));
246 QDomNodeList itemList = domDoc.elementsByTagName(
"lyrics");
247 QDomNode itemNode = itemList.item(0);
249 m_grabber = itemNode.namedItem(QString(
"grabber")).toElement().text();
250 m_artist = itemNode.namedItem(QString(
"artist")).toElement().text();
251 m_album = itemNode.namedItem(QString(
"album")).toElement().text();
252 m_title = itemNode.namedItem(QString(
"title")).toElement().text();
253 m_syncronized = (itemNode.namedItem(QString(
"syncronized")).toElement().text() ==
"True");
258 itemList = itemNode.toElement().elementsByTagName(
"lyric");
262 for (
int x = 0; x < itemList.count(); x++)
264 QDomNode lyricNode = itemList.at(x);
265 QString lyric = lyricNode.toElement().text();
271 if (match.hasMatch())
273 while (match.hasMatch())
275 times.append(lyric.left(match.capturedLength(1)));
276 lyric.remove(0,match.capturedLength(1));
279 for (
const auto &time : qAsConst(times))
280 lyrics.append(time + lyric);
302 std::chrono::milliseconds lastTime = -1ms;
303 std::chrono::milliseconds offset = 0ms;
305 for (
int x = 0; x <
lyrics.count(); x++)
307 const QString& lyric =
lyrics.at(x);
311 static const QRegularExpression kOffset { R
"(^\[offset:(.+)\])" };
312 auto match = kOffset.match(lyric);
313 if (match.hasMatch())
314 offset = std::chrono::milliseconds(match.capturedRef(1).toInt());
318 if (!lyric.isEmpty())
322 if (match.hasMatch())
324 int minutes = match.capturedRef(2).toInt();
325 int seconds = match.capturedRef(3).toInt();
326 int hundredths = match.capturedRef(4).toInt();
328 line->m_lyric = match.captured(5).trimmed();
330 line->m_time = std::max(0ms, line->m_time - offset);
331 lastTime = line->m_time;
335 line->m_time = ++lastTime;
336 line->m_lyric = lyric.trimmed();
346 line->m_lyric = lyric.trimmed();
347 lastTime = line->m_time;
351 line->m_time = ++lastTime;
352 line->m_lyric = lyric.trimmed();
357 if (line->m_lyric.startsWith(
"[ti:") || line->m_lyric.startsWith(
"[al:") ||
358 line->m_lyric.startsWith(
"[ar:") || line->m_lyric.startsWith(
"[by:") ||
359 line->m_lyric.startsWith(
"[url:") || line->m_lyric.startsWith(
"[offset:") ||
360 line->m_lyric.startsWith(
"[id:") || line->m_lyric.startsWith(
"[length:") ||
361 line->m_lyric.startsWith(
"[au:") || line->m_lyric.startsWith(
"[la:"))