diff --git a/README.md b/README.md
index 6e00704d..9d3b1f8a 100644
--- a/README.md
+++ b/README.md
@@ -52,7 +52,7 @@ Funding developers is a way to contribute to open source projects you appreciate
* Edit tags on audio files
* Fetch tags from MusicBrainz
* Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Musixmatch](https://www.musixmatch.com/), [Deezer](https://www.deezer.com/), [Tidal](https://www.tidal.com/), [Qobuz](https://www.qobuz.com/) and [Spotify](https://www.spotify.com/)
- * Song lyrics from [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/) and [lololyrics.com](https://www.lololyrics.com/)
+ * Song lyrics from [Genius](https://genius.com/), [Musixmatch](https://www.musixmatch.com/), [ChartLyrics](http://www.chartlyrics.com/), [lyrics.ovh](https://lyrics.ovh/), [lololyrics.com](https://www.lololyrics.com/) and [songlyrics.com](https://www.songlyrics.com/)
* Support for multiple backends
* Audio analyzer
* Audio equalizer
diff --git a/debian/control.in b/debian/control.in
index 9c44ed10..60acf126 100644
--- a/debian/control.in
+++ b/debian/control.in
@@ -52,7 +52,7 @@ Description: music player and music collection organizer
- Edit tags on audio files
- Automatically retrieve tags from MusicBrainz
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
- - Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
+ - Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com and songlyrics.com
- Audio analyzer
- Audio equalizer
- Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
diff --git a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
index ecf00b1b..43a17762 100644
--- a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
+++ b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
@@ -29,7 +29,7 @@
Edit tags on audio files
Automatically retrieve tags from MusicBrainz
Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
- Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
+ Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com and songlyrics.com
Support for multiple backends
Audio analyzer and equalizer
Transfer music to mass-storage USB players, MTP compatible devices and iPod Nano/Classic
diff --git a/dist/unix/strawberry.spec.in b/dist/unix/strawberry.spec.in
index aa57460c..9d01419b 100644
--- a/dist/unix/strawberry.spec.in
+++ b/dist/unix/strawberry.spec.in
@@ -118,7 +118,7 @@ Features:
- Edit tags on audio files
- Automatically retrieve tags from MusicBrainz
- Album cover art from Last.fm, Musicbrainz, Discogs, Musixmatch, Deezer, Tidal, Qobuz and Spotify
- - Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh and lololyrics.com
+ - Song lyrics from Genius, Musixmatch, ChartLyrics, lyrics.ovh, lololyrics.com and songlyrics.com
- Support for multiple backends
- Audio analyzer
- Audio equalizer
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index b667dcae..3f43395c 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -183,6 +183,7 @@ set(SOURCES
lyrics/geniuslyricsprovider.cpp
lyrics/musixmatchlyricsprovider.cpp
lyrics/chartlyricsprovider.cpp
+ lyrics/songlyricscomlyricsprovider.cpp
providers/musixmatchprovider.cpp
@@ -420,6 +421,7 @@ set(HEADERS
lyrics/geniuslyricsprovider.h
lyrics/musixmatchlyricsprovider.h
lyrics/chartlyricsprovider.h
+ lyrics/songlyricscomlyricsprovider.h
settings/settingsdialog.h
settings/settingspage.h
diff --git a/src/core/application.cpp b/src/core/application.cpp
index 4168f3d8..ec591a3e 100644
--- a/src/core/application.cpp
+++ b/src/core/application.cpp
@@ -64,6 +64,7 @@
#include "lyrics/lololyricsprovider.h"
#include "lyrics/musixmatchlyricsprovider.h"
#include "lyrics/chartlyricsprovider.h"
+#include "lyrics/songlyricscomlyricsprovider.h"
#include "scrobbler/audioscrobbler.h"
#include "scrobbler/lastfmscrobbler.h"
@@ -162,6 +163,7 @@ class ApplicationImpl {
lyrics_providers->AddProvider(new LoloLyricsProvider(app->network()));
lyrics_providers->AddProvider(new MusixmatchLyricsProvider(app->network()));
lyrics_providers->AddProvider(new ChartLyricsProvider(app->network()));
+ lyrics_providers->AddProvider(new SongLyricsComLyricsProvider(app->network()));
lyrics_providers->ReloadSettings();
return lyrics_providers;
}),
diff --git a/src/lyrics/lyricsprovider.cpp b/src/lyrics/lyricsprovider.cpp
index a6cab13b..d7cf5068 100644
--- a/src/lyrics/lyricsprovider.cpp
+++ b/src/lyrics/lyricsprovider.cpp
@@ -74,6 +74,8 @@ QString LyricsProvider::ParseLyricsFromHTML(const QString &content, const QRegul
lyrics.append("\n");
}
lyrics.append(content.mid(start_lyrics_idx, end_lyrics_idx - start_lyrics_idx)
+ .remove('\r')
+ .remove('\n')
.replace(QRegularExpression("
]*>"), "\n")
.remove(QRegularExpression("<[^>]*>"))
.trimmed());
diff --git a/src/lyrics/songlyricscomlyricsprovider.cpp b/src/lyrics/songlyricscomlyricsprovider.cpp
new file mode 100644
index 00000000..562cf36b
--- /dev/null
+++ b/src/lyrics/songlyricscomlyricsprovider.cpp
@@ -0,0 +1,135 @@
+/*
+ * Strawberry Music Player
+ * Copyright 2023, Jonas Kvinge
+ *
+ * Strawberry is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Strawberry is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Strawberry. If not, see .
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "core/logging.h"
+#include "core/shared_ptr.h"
+#include "core/networkaccessmanager.h"
+#include "lyricssearchrequest.h"
+#include "lyricssearchresult.h"
+#include "songlyricscomlyricsprovider.h"
+
+const char *SongLyricsComLyricsProvider::kUrl = "https://www.songlyrics.com/";
+
+SongLyricsComLyricsProvider::SongLyricsComLyricsProvider(SharedPtr network, QObject *parent) : LyricsProvider("songlyrics.com", true, false, network, parent) {}
+
+SongLyricsComLyricsProvider::~SongLyricsComLyricsProvider() {
+
+ while (!replies_.isEmpty()) {
+ QNetworkReply *reply = replies_.takeFirst();
+ QObject::disconnect(reply, nullptr, this, nullptr);
+ reply->abort();
+ reply->deleteLater();
+ }
+
+}
+
+bool SongLyricsComLyricsProvider::StartSearch(const int id, const LyricsSearchRequest &request) {
+
+ SendRequest(id, request, request.artist, request.album, request.title);
+
+ return true;
+
+}
+
+void SongLyricsComLyricsProvider::CancelSearch(const int id) { Q_UNUSED(id); }
+
+void SongLyricsComLyricsProvider::SendRequest(const int id, const LyricsSearchRequest &request, const QString &result_artist, const QString &result_album, const QString &result_title, QUrl url) {
+
+ if (url.isEmpty() || !url.isValid()) {
+ url.setUrl(kUrl + StringFixup(result_artist) + "/" + StringFixup(result_title) + "-lyrics/");
+ }
+
+ QNetworkRequest req(url);
+ req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
+ QNetworkReply *reply = network_->get(req);
+ replies_ << reply;
+ QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, id, request, result_artist, result_album, result_title]() { HandleLyricsReply(reply, id, request, result_artist, result_album, result_title); });
+
+}
+
+void SongLyricsComLyricsProvider::HandleLyricsReply(QNetworkReply *reply, const int id, const LyricsSearchRequest &request, const QString &result_artist, const QString &result_album, const QString &result_title) {
+
+ if (!replies_.contains(reply)) return;
+ replies_.removeAll(reply);
+ QObject::disconnect(reply, nullptr, this, nullptr);
+ reply->deleteLater();
+
+ if (reply->error() != QNetworkReply::NoError) {
+ qLog(Error) << "songlyrics.com:" << reply->errorString() << reply->error();
+ emit SearchFinished(id);
+ return;
+ }
+ else if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
+ qLog(Error) << "songlyrics.com: Received HTTP code" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ emit SearchFinished(id);
+ return;
+ }
+
+ const QByteArray data = reply->readAll();
+ if (data.isEmpty()) {
+ qLog(Error) << "songlyrics.com: Empty reply received from server.";
+ emit SearchFinished(id);
+ return;
+ }
+
+ const QString lyrics = ParseLyricsFromHTML(QString::fromUtf8(data), QRegularExpression("]*>"), QRegularExpression("<\\/p>"), QRegularExpression("
]+>"), false);
+ if (lyrics.isEmpty()) {
+ qLog(Debug) << "songlyrics.com: No lyrics for" << request.artist << request.album << request.title;
+ emit SearchFinished(id);
+ return;
+ }
+
+ qLog(Debug) << "songlyrics.com: Got lyrics for" << request.artist << request.album << request.title;
+
+ LyricsSearchResult result(lyrics);
+ result.artist = result_artist;
+ result.album = result_album;
+ result.title = result_title;
+ emit SearchFinished(id, LyricsSearchResults() << result);
+
+}
+
+QString SongLyricsComLyricsProvider::StringFixup(QString string) {
+
+ return string.replace('/', '-')
+ .replace('\'', '-')
+ .remove(QRegularExpression("[^\\w0-9\\- ]", QRegularExpression::UseUnicodePropertiesOption))
+ .simplified()
+ .replace(' ', '-')
+ .replace(QRegularExpression("(-)\\1+"), "-")
+ .toLower();
+
+}
+
+void SongLyricsComLyricsProvider::Error(const QString &error, const QVariant &debug) {
+
+ qLog(Error) << "songlyrics.com:" << error;
+ if (debug.isValid()) qLog(Debug) << debug;
+
+}
diff --git a/src/lyrics/songlyricscomlyricsprovider.h b/src/lyrics/songlyricscomlyricsprovider.h
new file mode 100644
index 00000000..8ef39cc0
--- /dev/null
+++ b/src/lyrics/songlyricscomlyricsprovider.h
@@ -0,0 +1,60 @@
+/*
+ * Strawberry Music Player
+ * Copyright 2023, Jonas Kvinge
+ *
+ * Strawberry is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Strawberry is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Strawberry. If not, see .
+ *
+ */
+
+#ifndef SONGLYRICSCOMLYRICSPROVIDER_H
+#define SONGLYRICSCOMLYRICSPROVIDER_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "core/shared_ptr.h"
+#include "lyricsprovider.h"
+#include "lyricssearchrequest.h"
+
+class QNetworkReply;
+class NetworkAccessManager;
+
+class SongLyricsComLyricsProvider : public LyricsProvider {
+ Q_OBJECT
+
+ public:
+ explicit SongLyricsComLyricsProvider(SharedPtr network, QObject *parent = nullptr);
+ ~SongLyricsComLyricsProvider() override;
+
+ bool StartSearch(const int id, const LyricsSearchRequest &request) override;
+ void CancelSearch(const int id) override;
+
+ private:
+ void SendRequest(const int id, const LyricsSearchRequest &request, const QString &result_artist, const QString &result_album, const QString &result_title, QUrl url = QUrl());
+ void Error(const QString &error, const QVariant &debug = QVariant()) override;
+ static QString StringFixup(QString string);
+
+ private slots:
+ void HandleLyricsReply(QNetworkReply *reply, const int id, const LyricsSearchRequest &request, const QString &result_artist, const QString &result_album, const QString &result_title);
+
+ private:
+ static const char *kUrl;
+ QList replies_;
+};
+
+#endif // SONGLYRICSCOMLYRICSPROVIDER_H