File indexing completed on 2023-05-30 11:30:47

0001 /**
0002  * Copyright (C) 2012 Martin Sandsmark <martin.sandsmark@kde.org>
0003  *
0004  * This program is free software; you can redistribute it and/or modify it under
0005  * the terms of the GNU General Public License as published by the Free Software
0006  * Foundation; either version 2 of the License, or (at your option) any later
0007  * version.
0008  *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0012  *
0013  * You should have received a copy of the GNU General Public License along with
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.
0015  */
0016 
0017 #include "lyricswidget.h"
0018 
0019 #include <KActionCollection>
0020 #include <KConfigGroup>
0021 #include <KLocalizedString>
0022 #include <KSharedConfig>
0023 #include <KToggleAction>
0024 #include <QAction>
0025 #include <QDomDocument>
0026 #include <QNetworkAccessManager>
0027 #include <QNetworkReply>
0028 #include <QUrlQuery>
0029 
0030 #include "actioncollection.h"
0031 #include "iconsupport.h"
0032 #include "juk_debug.h"
0033 #include "juktag.h"
0034 
0035 static const QUrl BASE_LYRICS_URL = QUrl("https://lyrics.fandom.com/");
0036 
0037 using namespace IconSupport; // ""_icon
0038 using namespace ActionCollection; // ""_act
0039 
0040 LyricsWidget::LyricsWidget(QWidget* parent)
0041   : QTextBrowser(parent)
0042   , m_networkAccessManager(new QNetworkAccessManager)
0043   , m_lyricsCurrent(false)
0044 {
0045     setMinimumWidth(200);
0046     setReadOnly(true);
0047     setWordWrapMode(QTextOption::WordWrap);
0048     setOpenExternalLinks(true);
0049 
0050     KToggleAction *show = new KToggleAction("view-media-lyrics"_icon,
0051                                             i18n("Show &Lyrics"), this);
0052     ActionCollection::actions()->addAction("showLyrics", show);
0053     connect(show, SIGNAL(toggled(bool)), this, SLOT(setVisible(bool)));
0054 
0055     KConfigGroup config(KSharedConfig::openConfig(), "LyricsWidget");
0056     bool shown = config.readEntry("Show", true);
0057     show->setChecked(shown);
0058     setVisible(shown);
0059 }
0060 
0061 LyricsWidget::~LyricsWidget()
0062 {
0063     delete m_networkAccessManager;
0064     saveConfig();
0065 }
0066 
0067 void LyricsWidget::saveConfig()
0068 {
0069     KConfigGroup config(KSharedConfig::openConfig(), "LyricsWidget");
0070     config.writeEntry("Show", "showLyrics"_act->isChecked());
0071 }
0072 
0073 void LyricsWidget::makeLyricsRequest()
0074 {
0075     m_lyricsCurrent = true;
0076 
0077     if(m_playingFile.isNull()) {
0078         setHtml(i18n("<i>No file playing.</i>"));
0079         return;
0080     }
0081 
0082     m_title = m_playingFile.tag()->artist() + " &#8211; " + m_playingFile.tag()->title();
0083     setHtml(i18n("<i>Loading...</i>"));
0084 
0085     // lyrics.fandom.com seems to be unavailable as well now so give a better error message
0086     // and stop pinging the server
0087     if(1) {
0088         setHtml(i18n("<i>Lyrics are currently unavailable for %1 (no available lyrics provider)</i>").arg(m_title));
0089         return;
0090     }
0091 
0092     QUrl listUrl = BASE_LYRICS_URL;
0093     listUrl.setPath("/api.php");
0094 
0095     QUrlQuery listUrlQuery;
0096     listUrlQuery.addQueryItem("action", "lyrics");
0097     listUrlQuery.addQueryItem("func", "getSong");
0098     listUrlQuery.addQueryItem("fmt", "xml");
0099     listUrlQuery.addQueryItem("artist", m_playingFile.tag()->artist());
0100     listUrlQuery.addQueryItem("song", m_playingFile.tag()->title());
0101     listUrl.setQuery(listUrlQuery);
0102 
0103     connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveListReply(QNetworkReply*)));
0104     m_networkAccessManager->get(QNetworkRequest(listUrl));
0105 }
0106 
0107 void LyricsWidget::playing(const FileHandle &file)
0108 {
0109     m_playingFile = file;
0110     m_lyricsCurrent = false;
0111 
0112     if(isVisible()) {
0113         makeLyricsRequest();
0114     }
0115 }
0116 
0117 void LyricsWidget::showEvent(QShowEvent *)
0118 {
0119     if(!m_lyricsCurrent) {
0120         makeLyricsRequest();
0121     }
0122 }
0123 
0124 void LyricsWidget::receiveListReply(QNetworkReply* reply)
0125 {
0126     disconnect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveListReply(QNetworkReply*)));
0127     if (reply->error() != QNetworkReply::NoError) {
0128         qCWarning(JUK_LOG) << "Error while fetching lyrics: " << reply->errorString();
0129         setHtml(i18n("<span style='color:red'>Error while retrieving lyrics!</span>"));
0130         return;
0131     }
0132 
0133     QDomDocument document;
0134     document.setContent(reply);
0135     QString artist = document.elementsByTagName("artist").at(0).toElement().text();
0136     QString title = document.elementsByTagName("song").at(0).toElement().text();
0137 
0138     QUrl url = BASE_LYRICS_URL;
0139     url.setPath("/api.php");
0140 
0141     QUrlQuery urlQuery;
0142     urlQuery.addQueryItem("action", "query");
0143     urlQuery.addQueryItem("prop", "revisions");
0144     urlQuery.addQueryItem("rvprop", "content");
0145     urlQuery.addQueryItem("format", "xml");
0146     urlQuery.addQueryItem("titles", artist + ':' + title);
0147     url.setQuery(urlQuery);
0148 
0149     connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveLyricsReply(QNetworkReply*)));
0150     m_networkAccessManager->get(QNetworkRequest(url));
0151 }
0152 
0153 void LyricsWidget::receiveLyricsReply(QNetworkReply* reply)
0154 {
0155     disconnect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(receiveLyricsReply(QNetworkReply*)));
0156     if (reply->error() != QNetworkReply::NoError) {
0157         qCWarning(JUK_LOG) << "Error while fetching lyrics: " << reply->errorString();
0158         setHtml(i18n("<span style='color:red'>Error while retrieving lyrics!</span>"));
0159         return;
0160     }
0161     const QUrlQuery replyUrlQuery(reply->url());
0162     QString titlesUrlPart = replyUrlQuery.queryItemValue(QStringLiteral("titles"), QUrl::FullyEncoded);
0163     if (titlesUrlPart.isEmpty()) {
0164         // default homepage, but this code path should never happen at this point.
0165         titlesUrlPart = QStringLiteral("Lyrics_Wiki");
0166     }
0167     const QString lyricsUrl = BASE_LYRICS_URL.toString() + QStringLiteral("wiki/") + titlesUrlPart;
0168 
0169     QString content = QString::fromUtf8(reply->readAll());
0170     int lIndex = content.indexOf("&lt;lyrics&gt;");
0171     int rIndex = content.indexOf("&lt;/lyrics&gt;");
0172     if (lIndex == -1 || rIndex == -1) {
0173         qCWarning(JUK_LOG) << Q_FUNC_INFO << "Unable to find lyrics in text";
0174         setText(i18n("No lyrics available."));
0175         return;
0176     }
0177     lIndex += 15; // We skip the tag
0178     content = content.mid(lIndex, rIndex - lIndex).trimmed();
0179     content.replace('\n', "<br />");
0180     //setText(content);
0181     setHtml("<h1>" + m_title + "</h1>" +
0182             content +
0183             i18n("<br /><br /><i>Lyrics provided by <a href='%1'>LyricWiki</a></i>", lyricsUrl));
0184 }