6 #include <QRegularExpression>
7 #include <QDomDocument>
17 static const QRegularExpression
kTimeCode { R
"(^(\[(\d\d):(\d\d)(?:\.(\d\d))?\])(.*))" };
96 slist <<
"MUSIC_LYRICS_FIND"
112 LOG(VB_NETWORK, LOG_INFO, QString(
"LyricsData:: Sending command %1").arg(slist.join(
'~')));
129 slist <<
"MUSIC_LYRICS_SAVE"
140 QDomDocument doc(
"lyrics");
142 QDomElement root = doc.createElement(
"lyrics");
143 doc.appendChild(root);
146 QDomElement
artist = doc.createElement(
"artist");
151 QDomElement
album = doc.createElement(
"album");
152 root.appendChild(
album);
156 QDomElement
title = doc.createElement(
"title");
157 root.appendChild(
title);
161 QDomElement
syncronized = doc.createElement(
"syncronized");
166 QDomElement
grabber = doc.createElement(
"grabber");
175 QDomElement lyric = doc.createElement(
"lyric");
176 root.appendChild(lyric);
188 auto *me =
dynamic_cast<MythEvent*
>(event);
193 if (me->Message().startsWith(
"MUSIC_LYRICS_"))
195 QStringList list = me->
Message().simplified().split(
' ');
197 if (list.size() >= 2)
199 uint songID = list[1].toUInt();
204 if (list[0] ==
"MUSIC_LYRICS_FOUND")
208 QString xmlData = me->Message().section(
" ", 2, -1);
214 else if (list[0] ==
"MUSIC_LYRICS_STATUS")
234 #if QT_VERSION < QT_VERSION_CHECK(6,5,0)
239 if (!domDoc.setContent(xmlData,
false, &errorMsg, &errorLine, &errorColumn))
241 LOG(VB_GENERAL, LOG_ERR,
242 QString(
"LyricsData:: Could not parse lyrics from %1").arg(xmlData) +
243 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3").arg(errorLine).arg(errorColumn).arg(errorMsg));
248 auto parseResult = domDoc.setContent(xmlData);
251 LOG(VB_GENERAL, LOG_ERR,
252 QString(
"LyricsData:: Could not parse lyrics from %1").arg(xmlData) +
253 QString(
"\n\t\t\tError at line: %1 column: %2 msg: %3")
254 .arg(parseResult.errorLine).arg(parseResult.errorColumn)
255 .arg(parseResult.errorMessage));
261 QDomNodeList itemList = domDoc.elementsByTagName(
"lyrics");
262 QDomNode itemNode = itemList.item(0);
264 m_grabber = itemNode.namedItem(QString(
"grabber")).toElement().text();
265 m_artist = itemNode.namedItem(QString(
"artist")).toElement().text();
266 m_album = itemNode.namedItem(QString(
"album")).toElement().text();
267 m_title = itemNode.namedItem(QString(
"title")).toElement().text();
268 m_syncronized = (itemNode.namedItem(QString(
"syncronized")).toElement().text() ==
"True");
273 itemList = itemNode.toElement().elementsByTagName(
"lyric");
277 for (
int x = 0; x < itemList.count(); x++)
279 QDomNode lyricNode = itemList.at(x);
280 QString lyric = lyricNode.toElement().text();
286 if (match.hasMatch())
288 while (match.hasMatch())
290 times.append(lyric.left(match.capturedLength(1)));
291 lyric.remove(0,match.capturedLength(1));
294 for (
const auto &time : std::as_const(times))
295 lyrics.append(time + lyric);
317 std::chrono::milliseconds lastTime = -1ms;
318 std::chrono::milliseconds offset = 0ms;
320 for (
int x = 0; x <
lyrics.count(); x++)
322 const QString& lyric =
lyrics.at(x);
326 static const QRegularExpression kOffset { R
"(^\[offset:(.+)\])" };
327 auto match = kOffset.match(lyric);
328 if (match.hasMatch())
329 offset = std::chrono::milliseconds(match.capturedView(1).toInt());
333 if (!lyric.isEmpty())
337 if (match.hasMatch())
339 int minutes = match.capturedView(2).toInt();
340 int seconds = match.capturedView(3).toInt();
341 int hundredths = match.capturedView(4).toInt();
343 line->m_lyric = match.captured(5);
345 line->m_time = std::max(0ms, line->m_time - offset);
346 lastTime = line->m_time;
350 line->m_time = ++lastTime;
351 line->m_lyric = lyric;
361 line->m_lyric = lyric;
362 lastTime = line->m_time;
366 line->m_time = ++lastTime;
367 line->m_lyric = lyric;
372 if (line->m_lyric.startsWith(
"[ti:") || line->m_lyric.startsWith(
"[al:") ||
373 line->m_lyric.startsWith(
"[ar:") || line->m_lyric.startsWith(
"[by:") ||
374 line->m_lyric.startsWith(
"[url:") || line->m_lyric.startsWith(
"[offset:") ||
375 line->m_lyric.startsWith(
"[id:") || line->m_lyric.startsWith(
"[length:") ||
376 line->m_lyric.startsWith(
"[au:") || line->m_lyric.startsWith(
"[la:"))