diff --git a/CMakeLists.txt b/CMakeLists.txt
index 89c816300..8714493a0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -326,8 +326,6 @@ optional_component(TRANSLATIONS ON "Translations"
DEPENDS "Qt5LinguistTools" Qt5LinguistTools_FOUND
)
-optional_component(TIDAL ON "Tidal support")
-optional_component(QOBUZ ON "Qobuz support")
optional_component(SUBSONIC ON "Subsonic support")
optional_component(MOODBAR ON "Moodbar"
diff --git a/README.md b/README.md
index 12eda6889..a1dceb899 100644
--- a/README.md
+++ b/README.md
@@ -19,17 +19,15 @@ Strawberry is a music player and music collection organizer. It is a fork of Cle
* Advanced audio output and device configuration for bit-perfect playback on Linux
* Edit tags on music files
* Fetch tags from MusicBrainz
- * Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/), [Deezer](https://www.deezer.com/) and [Tidal](https://tidal.com/)
+ * Album cover art from [Last.fm](https://www.last.fm/), [Musicbrainz](https://musicbrainz.org/), [Discogs](https://www.discogs.com/) and [Deezer](https://www.deezer.com/)
* Song lyrics from [AudD](https://audd.io/), [lyrics.ovh](https://lyrics.ovh/) and [lololyrics.com](https://www.lololyrics.com/)
* Support for multiple backends
* Audio analyzer
* Audio equalizer
* Transfer music to iPod, iPhone, MTP or mass-storage USB player
- * Subsonic streaming support
- * Unofficial streaming support for [Tidal](https://tidal.com/) and [Qobuz](https://www.qobuz.com/)
* Scrobbler with support for [Last.fm](https://www.last.fm/), [Libre.fm](https://libre.fm/) and [ListenBrainz](https://listenbrainz.org/)
-
-**Tidal and Qobuz streaming in Strawberry is unofficial. You need an official API token (or App ID/Secret) to use it, we can not provide API tokens, or help getting them. Tidal will not work with Tidal Masters (MQA), because MQA is a proprietary format in lossy quality without an open source decoder, we can't support it.**
+ * Subsonic streaming support
+
It has so far been tested to work on Linux, OpenBSD and Windows.
diff --git a/data/data.qrc b/data/data.qrc
index 001450bd6..b8dac0813 100644
--- a/data/data.qrc
+++ b/data/data.qrc
@@ -10,6 +10,7 @@
schema/schema-7.sql
schema/schema-8.sql
schema/schema-9.sql
+ schema/schema-10.sql
schema/device-schema.sql
style/strawberry.css
html/playing-tooltip-plain.html
diff --git a/data/icons.qrc b/data/icons.qrc
index 242c2d300..ff491cc7a 100644
--- a/data/icons.qrc
+++ b/data/icons.qrc
@@ -89,8 +89,6 @@
icons/128x128/moodbar.png
icons/128x128/love.png
icons/128x128/subsonic.png
- icons/128x128/tidal.png
- icons/128x128/qobuz.png
icons/64x64/albums.png
icons/64x64/alsa.png
icons/64x64/application-exit.png
@@ -181,8 +179,6 @@
icons/64x64/moodbar.png
icons/64x64/love.png
icons/64x64/subsonic.png
- icons/64x64/tidal.png
- icons/64x64/qobuz.png
icons/48x48/albums.png
icons/48x48/alsa.png
icons/48x48/application-exit.png
@@ -276,8 +272,6 @@
icons/48x48/moodbar.png
icons/48x48/love.png
icons/48x48/subsonic.png
- icons/48x48/tidal.png
- icons/48x48/qobuz.png
icons/32x32/albums.png
icons/32x32/alsa.png
icons/32x32/application-exit.png
@@ -371,8 +365,6 @@
icons/32x32/moodbar.png
icons/32x32/love.png
icons/32x32/subsonic.png
- icons/32x32/tidal.png
- icons/32x32/qobuz.png
icons/22x22/albums.png
icons/22x22/alsa.png
icons/22x22/application-exit.png
@@ -466,7 +458,5 @@
icons/22x22/moodbar.png
icons/22x22/love.png
icons/22x22/subsonic.png
- icons/22x22/tidal.png
- icons/22x22/qobuz.png
diff --git a/data/icons/128x128/qobuz.png b/data/icons/128x128/qobuz.png
deleted file mode 100644
index 4b6b17756..000000000
Binary files a/data/icons/128x128/qobuz.png and /dev/null differ
diff --git a/data/icons/128x128/tidal.png b/data/icons/128x128/tidal.png
deleted file mode 100644
index 5b7e2f11e..000000000
Binary files a/data/icons/128x128/tidal.png and /dev/null differ
diff --git a/data/icons/22x22/qobuz.png b/data/icons/22x22/qobuz.png
deleted file mode 100644
index 09834a5f1..000000000
Binary files a/data/icons/22x22/qobuz.png and /dev/null differ
diff --git a/data/icons/22x22/tidal.png b/data/icons/22x22/tidal.png
deleted file mode 100644
index 496105541..000000000
Binary files a/data/icons/22x22/tidal.png and /dev/null differ
diff --git a/data/icons/32x32/qobuz.png b/data/icons/32x32/qobuz.png
deleted file mode 100644
index c9c6b8a32..000000000
Binary files a/data/icons/32x32/qobuz.png and /dev/null differ
diff --git a/data/icons/32x32/tidal.png b/data/icons/32x32/tidal.png
deleted file mode 100644
index c206ac0a3..000000000
Binary files a/data/icons/32x32/tidal.png and /dev/null differ
diff --git a/data/icons/48x48/qobuz.png b/data/icons/48x48/qobuz.png
deleted file mode 100644
index 08af18ceb..000000000
Binary files a/data/icons/48x48/qobuz.png and /dev/null differ
diff --git a/data/icons/48x48/tidal.png b/data/icons/48x48/tidal.png
deleted file mode 100644
index fb0143432..000000000
Binary files a/data/icons/48x48/tidal.png and /dev/null differ
diff --git a/data/icons/64x64/qobuz.png b/data/icons/64x64/qobuz.png
deleted file mode 100644
index 4c7f31b4e..000000000
Binary files a/data/icons/64x64/qobuz.png and /dev/null differ
diff --git a/data/icons/64x64/tidal.png b/data/icons/64x64/tidal.png
deleted file mode 100644
index cbd33703d..000000000
Binary files a/data/icons/64x64/tidal.png and /dev/null differ
diff --git a/data/icons/full/qobuz.png b/data/icons/full/qobuz.png
deleted file mode 100644
index c7ad97fdb..000000000
Binary files a/data/icons/full/qobuz.png and /dev/null differ
diff --git a/data/icons/full/tidal.png b/data/icons/full/tidal.png
deleted file mode 100644
index 316831c69..000000000
Binary files a/data/icons/full/tidal.png and /dev/null differ
diff --git a/data/schema/schema-10.sql b/data/schema/schema-10.sql
new file mode 100644
index 000000000..971f59f14
--- /dev/null
+++ b/data/schema/schema-10.sql
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS tidal_artists_songs;
+
+DROP TABLE IF EXISTS tidal_albums_songs;
+
+DROP TABLE IF EXISTS tidal_songs;
+
+DROP TABLE IF EXISTS qobuz_artists_songs;
+
+DROP TABLE IF EXISTS qobuz_albums_songs;
+
+DROP TABLE IF EXISTS qobuz_songs;
+
+DROP TABLE IF EXISTS tidal_artists_songs_fts;
+
+DROP TABLE IF EXISTS tidal_albums_songs_fts;
+
+DROP TABLE IF EXISTS tidal_songs_fts;
+
+DROP TABLE IF EXISTS qobuz_artists_songs_fts;
+
+DROP TABLE IF EXISTS qobuz_albums_songs_fts;
+
+DROP TABLE IF EXISTS qobuz_songs_fts;
+
+UPDATE schema_version SET version=10;
diff --git a/data/schema/schema.sql b/data/schema/schema.sql
index 4d54de7cd..d21148e09 100644
--- a/data/schema/schema.sql
+++ b/data/schema/schema.sql
@@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS schema_version (
DELETE FROM schema_version;
-INSERT INTO schema_version (version) VALUES (9);
+INSERT INTO schema_version (version) VALUES (10);
CREATE TABLE IF NOT EXISTS directories (
path TEXT NOT NULL,
@@ -74,177 +74,6 @@ CREATE TABLE IF NOT EXISTS songs (
);
-CREATE TABLE IF NOT EXISTS tidal_artists_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
-CREATE TABLE IF NOT EXISTS tidal_albums_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
-CREATE TABLE IF NOT EXISTS tidal_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
CREATE TABLE IF NOT EXISTS subsonic_songs (
title TEXT NOT NULL,
@@ -302,177 +131,6 @@ CREATE TABLE IF NOT EXISTS subsonic_songs (
);
-CREATE TABLE IF NOT EXISTS qobuz_artists_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
-CREATE TABLE IF NOT EXISTS qobuz_albums_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
-CREATE TABLE IF NOT EXISTS qobuz_songs (
-
- title TEXT NOT NULL,
- album TEXT NOT NULL,
- artist TEXT NOT NULL,
- albumartist TEXT NOT NULL,
- track INTEGER NOT NULL DEFAULT -1,
- disc INTEGER NOT NULL DEFAULT -1,
- year INTEGER NOT NULL DEFAULT -1,
- originalyear INTEGER NOT NULL DEFAULT 0,
- genre TEXT NOT NULL,
- compilation INTEGER NOT NULL DEFAULT -1,
- composer TEXT NOT NULL,
- performer TEXT NOT NULL,
- grouping TEXT NOT NULL,
- comment TEXT NOT NULL,
- lyrics TEXT NOT NULL,
-
- artist_id INTEGER NOT NULL DEFAULT -1,
- album_id TEXT NOT NULL,
- song_id INTEGER NOT NULL DEFAULT -1,
-
- beginning INTEGER NOT NULL DEFAULT 0,
- length INTEGER NOT NULL DEFAULT 0,
-
- bitrate INTEGER NOT NULL DEFAULT -1,
- samplerate INTEGER NOT NULL DEFAULT -1,
- bitdepth INTEGER NOT NULL DEFAULT -1,
-
- source INTEGER NOT NULL DEFAULT 0,
- directory_id INTEGER NOT NULL DEFAULT -1,
- url TEXT NOT NULL,
- filetype INTEGER NOT NULL DEFAULT 0,
- filesize INTEGER NOT NULL DEFAULT -1,
- mtime INTEGER NOT NULL DEFAULT -1,
- ctime INTEGER NOT NULL DEFAULT -1,
- unavailable INTEGER DEFAULT 0,
-
- playcount INTEGER NOT NULL DEFAULT 0,
- skipcount INTEGER NOT NULL DEFAULT 0,
- lastplayed INTEGER NOT NULL DEFAULT -1,
-
- compilation_detected INTEGER DEFAULT 0,
- compilation_on INTEGER NOT NULL DEFAULT 0,
- compilation_off INTEGER NOT NULL DEFAULT 0,
- compilation_effective INTEGER NOT NULL DEFAULT 0,
-
- art_automatic TEXT,
- art_manual TEXT,
-
- effective_albumartist TEXT,
- effective_originalyear INTEGER NOT NULL DEFAULT 0,
-
- cue_path TEXT
-
-);
-
CREATE TABLE IF NOT EXISTS playlists (
name TEXT NOT NULL,
@@ -585,51 +243,6 @@ CREATE VIRTUAL TABLE IF NOT EXISTS songs_fts USING fts5(
);
-CREATE VIRTUAL TABLE IF NOT EXISTS tidal_artists_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
-CREATE VIRTUAL TABLE IF NOT EXISTS tidal_albums_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
-CREATE VIRTUAL TABLE IF NOT EXISTS tidal_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts5(
ftstitle,
@@ -645,51 +258,6 @@ CREATE VIRTUAL TABLE IF NOT EXISTS subsonic_songs_fts USING fts5(
);
-CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_artists_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
-CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_albums_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
-CREATE VIRTUAL TABLE IF NOT EXISTS qobuz_songs_fts USING fts5(
-
- ftstitle,
- ftsalbum,
- ftsartist,
- ftsalbumartist,
- ftscomposer,
- ftsperformer,
- ftsgrouping,
- ftsgenre,
- ftscomment,
- tokenize = "unicode61 remove_diacritics 0"
-
-);
-
CREATE VIRTUAL TABLE IF NOT EXISTS playlist_items_fts_ USING fts5(
ftstitle,
diff --git a/debian/control b/debian/control
index 11d55ee14..2e6acbaa3 100644
--- a/debian/control
+++ b/debian/control
@@ -55,13 +55,13 @@ Description: Audio player and music collection organizer
- Advanced audio output and device configuration for bit-perfect playback on Linux
- Edit tags on music files
- Fetch tags from MusicBrainz
- - Album cover art from Lastfm, Musicbrainz, Discogs, Deezer and Tidal
+ - Album cover art from Lastfm, Musicbrainz, Discogs and Deezer
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
- Support for multiple backends
- Audio analyzer
- Audio equalizer
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
- - Streaming support for Tidal, Qobuz and Subsonic
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
+ - Streaming support for Subsonic
.
It is a fork of Clementine. The name is inspired by the band Strawbs.
diff --git a/debian/copyright b/debian/copyright
index 8cb570695..6d615810d 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -44,14 +44,10 @@ Files: src/core/main.h
src/settings/backendsettingspage.h
src/settings/scrobblersettingspage.cpp
src/settings/scrobblersettingspage.h
- src/settings/tidalsettingspage.cpp
- src/settings/tidalsettingspage.h
src/covermanager/lastfmcoverprovider.cpp
src/covermanager/lastfmcoverprovider.h
src/covermanager/musicbrainzcoverprovider.cpp
src/covermanager/musicbrainzcoverprovider.h
- src/covermanager/tidalcoverprovider.cpp
- src/covermanager/tidalcoverprovider.h
src/covermanager/deezercoverprovider.cpp
src/covermanager/deezercoverprovider.h
src/globalshortcuts/globalshortcutbackend-system.cpp
@@ -64,8 +60,6 @@ Files: src/core/main.h
src/globalshortcuts/keymapper_win.h
src/lyrics/*
src/scrobbler/*
- src/tidal/*
- src/qobuz/*
src/subsonic/*
src/transcoder/transcoderoptionswavpack.cpp
src/transcoder/transcoderoptionswavpack.h
diff --git a/dist/man/strawberry.1 b/dist/man/strawberry.1
index 340995e21..791f15efb 100644
--- a/dist/man/strawberry.1
+++ b/dist/man/strawberry.1
@@ -25,7 +25,7 @@ Features:
.br
- Fetch tags from MusicBrainz
.br
-- Album cover art from Lastfm, Musicbrainz, Discogs, Deezer and Tidal
+- Album cover art from Lastfm, Musicbrainz, Discogs and Deezer
.br
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
.br
@@ -37,7 +37,7 @@ Features:
.br
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
.br
-- Streaming from Tidal, Qobuz and Subsonic
+- Streaming from Subsonic
.TP
It is a fork of Clementine. The name is inspired by the band Strawbs.
.SH OPTIONS
diff --git a/dist/rpm/strawberry.spec.in b/dist/rpm/strawberry.spec.in
index eef19bef7..129951ce4 100644
--- a/dist/rpm/strawberry.spec.in
+++ b/dist/rpm/strawberry.spec.in
@@ -104,14 +104,14 @@ Features:
- Advanced audio output and device configuration for bit-perfect playback on Linux
- Edit tags on music files
- Fetch tags from MusicBrainz
- - Album cover art from Last.fm, Musicbrainz, Discogs, Deezer and Tidal
+ - Album cover art from Last.fm, Musicbrainz, Discogs and Deezer
- Song lyrics from AudD, lyrics.ovh and lololyrics.com
- Support for multiple backends
- Audio analyzer
- Audio equalizer
- Transfer music to iPod, iPhone, MTP or mass-storage USB player
- - Streaming support for Tidal, Qobuz and Subsonic
- Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
+ - Streaming support for Subsonic
%prep
%setup -qn %{name}-@STRAWBERRY_VERSION_PACKAGE@
diff --git a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
index 83740ff08..41a1a6a0d 100644
--- a/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
+++ b/dist/unix/org.strawberrymusicplayer.strawberry.appdata.xml
@@ -31,8 +31,8 @@
Support for multiple backends
Audio analyzer and equalizer
Transfer music to iPod, iPhone, MTP or mass-storage USB player
- Streaming support for Tidal, Qobuz and Subsonic
Scrobbler with support for Last.fm, Libre.fm and ListenBrainz
+ Streaming support for Subsonic
diff --git a/dist/unix/org.strawberrymusicplayer.strawberry.desktop b/dist/unix/org.strawberrymusicplayer.strawberry.desktop
index c687087af..0e1538758 100755
--- a/dist/unix/org.strawberrymusicplayer.strawberry.desktop
+++ b/dist/unix/org.strawberrymusicplayer.strawberry.desktop
@@ -10,5 +10,5 @@ Icon=strawberry
Terminal=false
Categories=AudioVideo;Player;Qt;Audio;
StartupNotify=false
-MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf;x-scheme-handler/tidal;
+MimeType=x-content/audio-player;application/ogg;application/x-ogg;application/x-ogm-audio;audio/flac;audio/ogg;audio/vorbis;audio/aac;audio/mp4;audio/mpeg;audio/mpegurl;audio/vnd.rn-realaudio;audio/x-flac;audio/x-oggflac;audio/x-vorbis;audio/x-vorbis+ogg;audio/x-speex;audio/x-wav;audio/x-wavpack;audio/x-ape;audio/x-mp3;audio/x-mpeg;audio/x-mpegurl;audio/x-ms-wma;audio/x-musepack;audio/x-pn-realaudio;audio/x-scpls;video/x-ms-asf
StartupWMClass=strawberry
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f308f332b..e9dd0db50 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -906,50 +906,6 @@ optional_source(WIN32
core/windows7thumbbar.h
)
-optional_source(HAVE_TIDAL
- SOURCES
- tidal/tidalservice.cpp
- tidal/tidalurlhandler.cpp
- tidal/tidalbaserequest.cpp
- tidal/tidalrequest.cpp
- tidal/tidalstreamurlrequest.cpp
- tidal/tidalfavoriterequest.cpp
- settings/tidalsettingspage.cpp
- covermanager/tidalcoverprovider.cpp
- HEADERS
- tidal/tidalservice.h
- tidal/tidalurlhandler.h
- tidal/tidalbaserequest.h
- tidal/tidalrequest.h
- tidal/tidalstreamurlrequest.h
- tidal/tidalfavoriterequest.h
- settings/tidalsettingspage.h
- covermanager/tidalcoverprovider.h
- UI
- settings/tidalsettingspage.ui
-)
-
-optional_source(HAVE_QOBUZ
- SOURCES
- qobuz/qobuzservice.cpp
- qobuz/qobuzurlhandler.cpp
- qobuz/qobuzbaserequest.cpp
- qobuz/qobuzrequest.cpp
- qobuz/qobuzstreamurlrequest.cpp
- qobuz/qobuzfavoriterequest.cpp
- settings/qobuzsettingspage.cpp
- HEADERS
- qobuz/qobuzservice.h
- qobuz/qobuzurlhandler.h
- qobuz/qobuzbaserequest.h
- qobuz/qobuzrequest.h
- qobuz/qobuzstreamurlrequest.h
- qobuz/qobuzfavoriterequest.h
- settings/qobuzsettingspage.h
- UI
- settings/qobuzsettingspage.ui
-)
-
optional_source(HAVE_SUBSONIC
SOURCES
subsonic/subsonicservice.cpp
diff --git a/src/config.h.in b/src/config.h.in
index a474395cd..1755932e5 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -47,9 +47,7 @@
#cmakedefine HAVE_PHONON
#cmakedefine XINE_ANALYZER
-#cmakedefine HAVE_TIDAL
#cmakedefine HAVE_SUBSONIC
-#cmakedefine HAVE_QOBUZ
#cmakedefine HAVE_MOODBAR
diff --git a/src/core/application.cpp b/src/core/application.cpp
index 645e6bb72..df2ec261e 100644
--- a/src/core/application.cpp
+++ b/src/core/application.cpp
@@ -67,15 +67,6 @@
#include "internet/internetservices.h"
#include "internet/internetsearch.h"
-#ifdef HAVE_TIDAL
-# include "tidal/tidalservice.h"
-# include "covermanager/tidalcoverprovider.h"
-#endif
-
-#ifdef HAVE_QOBUZ
-# include "qobuz/qobuzservice.h"
-#endif
-
#ifdef HAVE_SUBSONIC
# include "subsonic/subsonicservice.h"
#endif
@@ -121,9 +112,6 @@ class ApplicationImpl {
cover_providers->AddProvider(new DiscogsCoverProvider(app, app));
cover_providers->AddProvider(new MusicbrainzCoverProvider(app, app));
cover_providers->AddProvider(new DeezerCoverProvider(app, app));
-#ifdef HAVE_TIDAL
- cover_providers->AddProvider(new TidalCoverProvider(app, app));
-#endif
return cover_providers;
}),
album_cover_loader_([=]() {
@@ -141,23 +129,11 @@ class ApplicationImpl {
}),
internet_services_([=]() {
InternetServices *internet_services = new InternetServices(app);
-#ifdef HAVE_TIDAL
- internet_services->AddService(new TidalService(app, internet_services));
-#endif
-#ifdef HAVE_QOBUZ
- internet_services->AddService(new QobuzService(app, internet_services));
-#endif
#ifdef HAVE_SUBSONIC
internet_services->AddService(new SubsonicService(app, internet_services));
#endif
return internet_services;
}),
-#ifdef HAVE_TIDAL
- tidal_search_([=]() { return new InternetSearch(app, Song::Source_Tidal, app); }),
-#endif
-#ifdef HAVE_QOBUZ
- qobuz_search_([=]() { return new InternetSearch(app, Song::Source_Qobuz, app); }),
-#endif
scrobbler_([=]() { return new AudioScrobbler(app, app); }),
#ifdef HAVE_MOODBAR
@@ -185,12 +161,6 @@ class ApplicationImpl {
Lazy current_albumcover_loader_;
Lazy lyrics_providers_;
Lazy internet_services_;
-#ifdef HAVE_TIDAL
- Lazy tidal_search_;
-#endif
-#ifdef HAVE_QOBUZ
- Lazy qobuz_search_;
-#endif
Lazy scrobbler_;
#ifdef HAVE_MOODBAR
Lazy moodbar_loader_;
@@ -319,12 +289,6 @@ LyricsProviders *Application::lyrics_providers() const { return p_->lyrics_provi
PlaylistBackend *Application::playlist_backend() const { return p_->playlist_backend_.get(); }
PlaylistManager *Application::playlist_manager() const { return p_->playlist_manager_.get(); }
InternetServices *Application::internet_services() const { return p_->internet_services_.get(); }
-#ifdef HAVE_TIDAL
-InternetSearch *Application::tidal_search() const { return p_->tidal_search_.get(); }
-#endif
-#ifdef HAVE_QOBUZ
-InternetSearch *Application::qobuz_search() const { return p_->qobuz_search_.get(); }
-#endif
AudioScrobbler *Application::scrobbler() const { return p_->scrobbler_.get(); }
#ifdef HAVE_MOODBAR
MoodbarController *Application::moodbar_controller() const { return p_->moodbar_controller_.get(); }
diff --git a/src/core/application.h b/src/core/application.h
index d6f44ab79..51862f523 100644
--- a/src/core/application.h
+++ b/src/core/application.h
@@ -97,12 +97,6 @@ class Application : public QObject {
AudioScrobbler *scrobbler() const;
InternetServices *internet_services() const;
-#ifdef HAVE_TIDAL
- InternetSearch *tidal_search() const;
-#endif
-#ifdef HAVE_QOBUZ
- InternetSearch *qobuz_search() const;
-#endif
#ifdef HAVE_MOODBAR
MoodbarController *moodbar_controller() const;
@@ -114,7 +108,7 @@ class Application : public QObject {
QThread *MoveToNewThread(QObject *object);
void MoveToThread(QObject *object, QThread *thread);
-private slots:
+ private slots:
void ExitReceived();
public slots:
@@ -122,7 +116,7 @@ private slots:
void ReloadSettings();
void OpenSettingsDialogAtPage(SettingsDialog::Page page);
-signals:
+ signals:
void ErrorAdded(const QString &message);
void SettingsChanged();
void SettingsDialogRequested(SettingsDialog::Page page);
diff --git a/src/core/database.cpp b/src/core/database.cpp
index 31734b29a..307a78031 100644
--- a/src/core/database.cpp
+++ b/src/core/database.cpp
@@ -54,7 +54,7 @@
#include "scopedtransaction.h"
const char *Database::kDatabaseFilename = "strawberry.db";
-const int Database::kSchemaVersion = 9;
+const int Database::kSchemaVersion = 10;
const char *Database::kMagicAllSongsTables = "%allsongstables";
int Database::sNextConnectionId = 1;
diff --git a/src/core/iconmapper.h b/src/core/iconmapper.h
index 162732767..313770768 100644
--- a/src/core/iconmapper.h
+++ b/src/core/iconmapper.h
@@ -105,7 +105,6 @@ static const QMap iconmapper_ = {
{ "moodbar", { {"preferences-desktop-icons"}, 0, 0 } },
{ "nvidia", { {}, 0, 0 } },
{ "pulseaudio", { {}, 0, 0 } },
- { "qobuz", { {}, 0, 0 } },
{ "realtek", { {}, 0, 0 } },
{ "scrobble-disabled", { {}, 0, 0 } },
{ "scrobble", { {}, 0, 0 } },
@@ -116,7 +115,6 @@ static const QMap iconmapper_ = {
{ "star", { {}, 0, 0 } },
{ "strawberry", { {}, 0, 0 } },
{ "subsonic", { {}, 0, 0 } },
- { "tidal", { {}, 0, 0 } },
{ "tools-wizard", { {}, 0, 0 } },
{ "view-choose", { {}, 0, 0 } },
{ "view-fullscreen", { {}, 0, 0 } },
diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp
index 95b06aa36..b6e117fd1 100644
--- a/src/core/mainwindow.cpp
+++ b/src/core/mainwindow.cpp
@@ -144,13 +144,6 @@
#include "settings/behavioursettingspage.h"
#include "settings/backendsettingspage.h"
#include "settings/playlistsettingspage.h"
-#ifdef HAVE_TIDAL
-# include "tidal/tidalservice.h"
-# include "settings/tidalsettingspage.h"
-#endif
-#ifdef HAVE_QOBUZ
-# include "settings/qobuzsettingspage.h"
-#endif
#ifdef HAVE_SUBSONIC
# include "settings/subsonicsettingspage.h"
#endif
@@ -230,12 +223,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
dialog->SetDestinationModel(app->collection()->model()->directory_model());
return dialog;
}),
-#ifdef HAVE_TIDAL
- tidal_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source_Tidal), app_->tidal_search(), TidalSettingsPage::kSettingsGroup, SettingsDialog::Page_Tidal, this)),
-#endif
-#ifdef HAVE_QOBUZ
- qobuz_view_(new InternetTabsView(app_, app->internet_services()->ServiceBySource(Song::Source_Qobuz), app_->qobuz_search(), QobuzSettingsPage::kSettingsGroup, SettingsDialog::Page_Qobuz, this)),
-#endif
#ifdef HAVE_SUBSONIC
subsonic_view_(new InternetSongsView(app_, app->internet_services()->ServiceBySource(Song::Source_Subsonic), SubsonicSettingsPage::kSettingsGroup, SettingsDialog::Page_Subsonic, this)),
#endif
@@ -288,12 +275,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
#ifndef Q_OS_WIN
ui_->tabs->AddTab(device_view_, "devices", IconLoader::Load("device"), tr("Devices"));
#endif
-#ifdef HAVE_TIDAL
- ui_->tabs->AddTab(tidal_view_, "tidal", IconLoader::Load("tidal"), tr("Tidal"));
-#endif
-#ifdef HAVE_QOBUZ
- ui_->tabs->AddTab(qobuz_view_, "qobuz", IconLoader::Load("qobuz"), tr("Qobuz"));
-#endif
#ifdef HAVE_SUBSONIC
ui_->tabs->AddTab(subsonic_view_, "subsonic", IconLoader::Load("subsonic"), tr("Subsonic"));
#endif
@@ -578,22 +559,6 @@ MainWindow::MainWindow(Application *app, SystemTrayIcon *tray_icon, OSD *osd, co
collection_view_->filter()->AddMenuAction(separator);
collection_view_->filter()->AddMenuAction(collection_config_action);
-#ifdef HAVE_TIDAL
- connect(tidal_view_->artists_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(tidal_view_->albums_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(tidal_view_->songs_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(tidal_view_->search_view(), SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- if (TidalService *tidalservice = qobject_cast (app_->internet_services()->ServiceBySource(Song::Source_Tidal)))
- connect(this, SIGNAL(AuthorisationUrlReceived(const QUrl&)), tidalservice, SLOT(AuthorisationUrlReceived(const QUrl&)));
-#endif
-
-#ifdef HAVE_QOBUZ
- connect(qobuz_view_->artists_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(qobuz_view_->albums_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(qobuz_view_->songs_collection_view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
- connect(qobuz_view_->search_view(), SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
-#endif
-
#ifdef HAVE_SUBSONIC
connect(subsonic_view_->view(), SIGNAL(AddToPlaylistSignal(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
#endif
@@ -916,26 +881,6 @@ void MainWindow::ReloadSettings() {
}
}
-#ifdef HAVE_TIDAL
- settings.beginGroup(TidalSettingsPage::kSettingsGroup);
- bool enable_tidal = settings.value("enabled", false).toBool();
- settings.endGroup();
- if (enable_tidal)
- ui_->tabs->EnableTab(tidal_view_);
- else
- ui_->tabs->DisableTab(tidal_view_);
-#endif
-
-#ifdef HAVE_QOBUZ
- settings.beginGroup(QobuzSettingsPage::kSettingsGroup);
- bool enable_qobuz = settings.value("enabled", false).toBool();
- settings.endGroup();
- if (enable_qobuz)
- ui_->tabs->EnableTab(qobuz_view_);
- else
- ui_->tabs->DisableTab(qobuz_view_);
-#endif
-
#ifdef HAVE_SUBSONIC
settings.beginGroup(SubsonicSettingsPage::kSettingsGroup);
bool enable_subsonic = settings.value("enabled", false).toBool();
@@ -966,12 +911,6 @@ void MainWindow::ReloadAllSettings() {
album_cover_choice_controller_->ReloadSettings();
if (cover_manager_.get()) cover_manager_->ReloadSettings();
context_view_->ReloadSettings();
-#ifdef HAVE_TIDAL
- tidal_view_->ReloadSettings();
-#endif
-#ifdef HAVE_QOBUZ
- qobuz_view_->ReloadSettings();
-#endif
#ifdef HAVE_SUBSONIC
subsonic_view_->ReloadSettings();
#endif
@@ -2043,14 +1982,6 @@ void MainWindow::CommandlineOptionsReceived(const CommandlineOptions &options) {
if (!options.urls().empty()) {
-#ifdef HAVE_TIDAL
- for (const QUrl url : options.urls()) {
- if (url.scheme() == "tidal" && url.host() == "login") {
- emit AuthorisationUrlReceived(url);
- return;
- }
- }
-#endif
MimeData *data = new MimeData;
data->setUrls(options.urls());
// Behaviour depends on command line options, so set it here
diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h
index 38d6dea60..24d2e8719 100644
--- a/src/core/mainwindow.h
+++ b/src/core/mainwindow.h
@@ -315,8 +315,6 @@ class MainWindow : public QMainWindow, public PlatformInterface {
std::unique_ptr track_selection_dialog_;
PlaylistItemList autocomplete_tag_items_;
- InternetTabsView *tidal_view_;
- InternetTabsView *qobuz_view_;
InternetSongsView *subsonic_view_;
QAction *collection_show_all_;
diff --git a/src/covermanager/tidalcoverprovider.cpp b/src/covermanager/tidalcoverprovider.cpp
deleted file mode 100644
index 562515bbe..000000000
--- a/src/covermanager/tidalcoverprovider.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/application.h"
-#include "core/closure.h"
-#include "core/network.h"
-#include "core/logging.h"
-#include "core/song.h"
-#include "internet/internetservices.h"
-#include "tidal/tidalservice.h"
-#include "albumcoverfetcher.h"
-#include "coverprovider.h"
-#include "tidalcoverprovider.h"
-
-const char *TidalCoverProvider::kApiUrl = "https://api.tidalhifi.com/v1";
-const char *TidalCoverProvider::kResourcesUrl = "https://resources.tidal.com";
-const int TidalCoverProvider::kLimit = 10;
-
-TidalCoverProvider::TidalCoverProvider(Application *app, QObject *parent) :
- CoverProvider("Tidal", 2.0, true, app, parent),
- service_(app->internet_services()->Service()),
- network_(new NetworkAccessManager(this)) {
-
-}
-
-bool TidalCoverProvider::StartSearch(const QString &artist, const QString &album, const int id) {
-
- if (!service_ || !service_->authenticated()) return false;
-
- ParamList params = ParamList() << Param("query", QString(artist + " " + album))
- << Param("limit", QString::number(kLimit));
-
- QNetworkReply *reply = CreateRequest("search/albums", params);
- NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleSearchReply(QNetworkReply*, int)), reply, id);
-
- return true;
-
-}
-
-void TidalCoverProvider::CancelSearch(int id) { Q_UNUSED(id); }
-
-QNetworkReply *TidalCoverProvider::CreateRequest(const QString &ressource_name, const ParamList ¶ms_supplied) {
-
- const ParamList params = ParamList() << params_supplied
- << Param("countryCode", service_->country_code());
-
- QUrlQuery url_query;
- for (const Param ¶m : params) {
- EncodedParam encoded_param(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
- url_query.addQueryItem(encoded_param.first, encoded_param.second);
- }
-
- QUrl url(kApiUrl + QString("/") + ressource_name);
- url.setQuery(url_query);
- QNetworkRequest req(url);
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
-#endif
- req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
- if (!service_->access_token().isEmpty()) req.setRawHeader("authorization", "Bearer " + service_->access_token().toUtf8());
- if (!service_->session_id().isEmpty()) req.setRawHeader("X-Tidal-SessionId", service_->session_id().toUtf8());
- QNetworkReply *reply = network_->get(req);
-
- return reply;
-
-}
-
-QByteArray TidalCoverProvider::GetReplyData(QNetworkReply *reply, QString &error) {
-
- QByteArray data;
-
- if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
- data = reply->readAll();
- }
- else {
- if (reply->error() != QNetworkReply::NoError && reply->error() < 200) {
- // This is a network error, there is nothing more to do.
- error = Error(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
- }
- else {
- // See if there is Json data containing "status" and "userMessage" - then use that instead.
- data = reply->readAll();
- QJsonParseError parse_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &parse_error);
- int status = 0;
- int sub_status = 0;
- if (parse_error.error == QJsonParseError::NoError && !json_doc.isNull() && !json_doc.isEmpty() && json_doc.isObject()) {
- QJsonObject json_obj = json_doc.object();
- if (!json_obj.isEmpty() && json_obj.contains("status") && json_obj.contains("userMessage")) {
- status = json_obj["status"].toInt();
- sub_status = json_obj["subStatus"].toInt();
- QString user_message = json_obj["userMessage"].toString();
- error = QString("%1 (%2) (%3)").arg(user_message).arg(status).arg(sub_status);
- }
- }
- if (error.isEmpty()) {
- if (reply->error() != QNetworkReply::NoError) {
- error = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
- }
- else {
- error = QString("Received HTTP code %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
- }
- }
- if (status == 401 && sub_status == 6001) { // User does not have a valid session
- service_->Logout();
- }
- error = Error(error);
- }
- return QByteArray();
- }
-
- return data;
-
-}
-
-QJsonObject TidalCoverProvider::ExtractJsonObj(QByteArray &data, QString &error) {
-
- QJsonParseError json_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
-
- if (json_error.error != QJsonParseError::NoError) {
- error = Error("Reply from server missing Json data.", data);
- return QJsonObject();
- }
-
- if (json_doc.isEmpty()) {
- error = Error("Received empty Json document.", data);
- return QJsonObject();
- }
-
- if (!json_doc.isObject()) {
- error = Error("Json document is not an object.", json_doc);
- return QJsonObject();
- }
-
- QJsonObject json_obj = json_doc.object();
- if (json_obj.isEmpty()) {
- error = Error("Received empty Json object.", json_doc);
- return QJsonObject();
- }
-
- return json_obj;
-
-}
-
-QJsonValue TidalCoverProvider::ExtractItems(QByteArray &data, QString &error) {
-
- QJsonObject json_obj = ExtractJsonObj(data, error);
- if (json_obj.isEmpty()) return QJsonValue();
- return ExtractItems(json_obj, error);
-
-}
-
-QJsonValue TidalCoverProvider::ExtractItems(QJsonObject &json_obj, QString &error) {
-
- if (!json_obj.contains("items")) {
- error = Error("Json reply is missing items.", json_obj);
- return QJsonArray();
- }
- QJsonValue json_items = json_obj["items"];
- return json_items;
-
-}
-
-void TidalCoverProvider::HandleSearchReply(QNetworkReply *reply, const int id) {
-
- reply->deleteLater();
-
- CoverSearchResults results;
- QString error;
-
- QByteArray data = GetReplyData(reply, error);
- if (data.isEmpty()) {
- emit SearchFinished(id, results);
- return;
- }
-
- QJsonObject json_obj = ExtractJsonObj(data, error);
- if (json_obj.isEmpty()) {
- emit SearchFinished(id, results);
- return;
- }
-
- QJsonValue json_value = ExtractItems(json_obj, error);
- if (!json_value.isArray()) {
- emit SearchFinished(id, results);
- return;
- }
- QJsonArray json_items = json_value.toArray();
- if (json_items.isEmpty()) {
- emit SearchFinished(id, results);
- return;
- }
-
- for (const QJsonValue &value : json_items) {
- if (!value.isObject()) {
- Error("Invalid Json reply, item not a object.", value);
- continue;
- }
- QJsonObject json_obj = value.toObject();
-
- if (!json_obj.contains("artist") || !json_obj.contains("type") || !json_obj.contains("id") || !json_obj.contains("title") || !json_obj.contains("cover")) {
- Error("Invalid Json reply, item missing id, type, album or cover.", json_obj);
- continue;
- }
- QString album = json_obj["title"].toString();
- QString cover = json_obj["cover"].toString();
-
- QJsonValue json_value_artist = json_obj["artist"];
- if (!json_value_artist.isObject()) {
- Error("Invalid Json reply, item artist is not a object.", json_value_artist);
- continue;
- }
- QJsonObject json_artist = json_value_artist.toObject();
- if (!json_artist.contains("name")) {
- Error("Invalid Json reply, item artist missing name.", json_artist);
- continue;
- }
- QString artist = json_artist["name"].toString();
-
- album.remove(Song::kAlbumRemoveDisc);
- album.remove(Song::kAlbumRemoveMisc);
-
- cover = cover.replace("-", "/");
- QUrl cover_url (QString("%1/images/%2/%3.jpg").arg(kResourcesUrl).arg(cover).arg("1280x1280"));
-
- CoverSearchResult cover_result;
- cover_result.artist = artist;
- cover_result.album = album;
- cover_result.image_url = cover_url;
- results << cover_result;
-
- }
- emit SearchFinished(id, results);
-
-}
-
-QString TidalCoverProvider::Error(QString error, QVariant debug) {
- qLog(Error) << "Tidal:" << error;
- if (debug.isValid()) qLog(Debug) << debug;
- return error;
-}
diff --git a/src/covermanager/tidalcoverprovider.h b/src/covermanager/tidalcoverprovider.h
deleted file mode 100644
index 9eb3ee2e4..000000000
--- a/src/covermanager/tidalcoverprovider.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 TIDALCOVERPROVIDER_H
-#define TIDALCOVERPROVIDER_H
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "coverprovider.h"
-
-class QNetworkAccessManager;
-class QNetworkReply;
-class Application;
-class TidalService;
-
-class TidalCoverProvider : public CoverProvider {
- Q_OBJECT
-
- public:
- explicit TidalCoverProvider(Application *app, QObject *parent = nullptr);
- bool StartSearch(const QString &artist, const QString &album, const int id);
- void CancelSearch(int id);
-
- private slots:
- void HandleSearchReply(QNetworkReply *reply, const int id);
-
- private:
- typedef QPair Param;
- typedef QList ParamList;
- typedef QPair EncodedParam;
- static const char *kApiUrl;
- static const char *kResourcesUrl;
- static const int kLimit;
-
- QNetworkReply *CreateRequest(const QString &ressource_name, const ParamList ¶ms_supplied);
- QByteArray GetReplyData(QNetworkReply *reply, QString &error);
- QJsonObject ExtractJsonObj(QByteArray &data, QString &error);
- QJsonValue ExtractItems(QByteArray &data, QString &error);
- QJsonValue ExtractItems(QJsonObject &json_obj, QString &error);
- QString Error(QString error, QVariant debug = QVariant());
-
- TidalService *service_;
- QNetworkAccessManager *network_;
-
-};
-
-#endif // TIDALCOVERPROVIDER_H
diff --git a/src/qobuz/qobuzbaserequest.cpp b/src/qobuz/qobuzbaserequest.cpp
deleted file mode 100644
index dcb74c196..000000000
--- a/src/qobuz/qobuzbaserequest.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/network.h"
-#include "qobuzservice.h"
-#include "qobuzbaserequest.h"
-
-const char *QobuzBaseRequest::kApiUrl = "https://www.qobuz.com/api.json/0.2";
-
-QobuzBaseRequest::QobuzBaseRequest(QobuzService *service, NetworkAccessManager *network, QObject *parent) :
- QObject(parent),
- service_(service),
- network_(network)
- {}
-
-QobuzBaseRequest::~QobuzBaseRequest() {}
-
-QNetworkReply *QobuzBaseRequest::CreateRequest(const QString &ressource_name, const QList ¶ms_provided) {
-
- ParamList params = ParamList() << params_provided
- << Param("app_id", app_id());
-
- std::sort(params.begin(), params.end());
-
- QUrlQuery url_query;
- for (const Param& param : params) {
- EncodedParam encoded_param(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
- url_query.addQueryItem(encoded_param.first, encoded_param.second);
- }
-
- QUrl url(kApiUrl + QString("/") + ressource_name);
- url.setQuery(url_query);
- QNetworkRequest req(url);
- req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
- req.setRawHeader("X-App-Id", app_id().toUtf8());
- if (authenticated())
- req.setRawHeader("X-User-Auth-Token", user_auth_token().toUtf8());
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
-#endif
-
- QNetworkReply *reply = network_->get(req);
- connect(reply, SIGNAL(sslErrors(QList)), this, SLOT(HandleSSLErrors(QList)));
-
- //qLog(Debug) << "Qobuz: Sending request" << url;
-
- return reply;
-
-}
-
-void QobuzBaseRequest::HandleSSLErrors(QList ssl_errors) {
-
- for (QSslError &ssl_error : ssl_errors) {
- Error(ssl_error.errorString());
- }
-
-}
-
-QByteArray QobuzBaseRequest::GetReplyData(QNetworkReply *reply) {
-
- QByteArray data;
-
- if (reply->error() == QNetworkReply::NoError && reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
- data = reply->readAll();
- }
- else {
- if (reply->error() != QNetworkReply::NoError && reply->error() < 200) {
- // This is a network error, there is nothing more to do.
- Error(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
- }
- else {
- // See if there is Json data containing "status", "code" and "message" - then use that instead.
- data = reply->readAll();
- QString error;
- QJsonParseError parse_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &parse_error);
- if (parse_error.error == QJsonParseError::NoError && !json_doc.isEmpty() && json_doc.isObject()) {
- QJsonObject json_obj = json_doc.object();
- if (!json_obj.isEmpty() && json_obj.contains("status") && json_obj.contains("code") && json_obj.contains("message")) {
- QString status = json_obj["status"].toString();
- int code = json_obj["code"].toInt();
- QString message = json_obj["message"].toString();
- error = QString("%1 (%2)").arg(message).arg(code);
- }
- }
- if (error.isEmpty()) {
- if (reply->error() != QNetworkReply::NoError) {
- error = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
- }
- else {
- error = QString("Received HTTP code %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
- }
- }
- Error(error);
- }
- return QByteArray();
- }
-
- return data;
-
-}
-
-QJsonObject QobuzBaseRequest::ExtractJsonObj(QByteArray &data) {
-
- QJsonParseError json_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
-
- if (json_error.error != QJsonParseError::NoError) {
- Error("Reply from server missing Json data.", data);
- return QJsonObject();
- }
-
- if (json_doc.isEmpty()) {
- Error("Received empty Json document.", data);
- return QJsonObject();
- }
-
- if (!json_doc.isObject()) {
- Error("Json document is not an object.", json_doc);
- return QJsonObject();
- }
-
- QJsonObject json_obj = json_doc.object();
- if (json_obj.isEmpty()) {
- Error("Received empty Json object.", json_doc);
- return QJsonObject();
- }
-
- return json_obj;
-
-}
-
-QJsonValue QobuzBaseRequest::ExtractItems(QByteArray &data) {
-
- QJsonObject json_obj = ExtractJsonObj(data);
- if (json_obj.isEmpty()) return QJsonValue();
- return ExtractItems(json_obj);
-
-}
-
-QJsonValue QobuzBaseRequest::ExtractItems(QJsonObject &json_obj) {
-
- if (!json_obj.contains("items")) {
- Error("Json reply is missing items.", json_obj);
- return QJsonArray();
- }
- QJsonValue json_items = json_obj["items"];
- return json_items;
-
-}
-
-QString QobuzBaseRequest::ErrorsToHTML(const QStringList &errors) {
-
- QString error_html;
- for (const QString &error : errors) {
- error_html += error + "
";
- }
- return error_html;
-
-}
diff --git a/src/qobuz/qobuzbaserequest.h b/src/qobuz/qobuzbaserequest.h
deleted file mode 100644
index aea92e31b..000000000
--- a/src/qobuz/qobuzbaserequest.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZBASEREQUEST_H
-#define QOBUZBASEREQUEST_H
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/song.h"
-#include "qobuzservice.h"
-
-class QNetworkReply;
-class NetworkAccessManager;
-
-class QobuzBaseRequest : public QObject {
- Q_OBJECT
-
- public:
-
- enum QueryType {
- QueryType_None,
- QueryType_Artists,
- QueryType_Albums,
- QueryType_Songs,
- QueryType_SearchArtists,
- QueryType_SearchAlbums,
- QueryType_SearchSongs,
- QueryType_StreamURL,
- };
-
- QobuzBaseRequest(QobuzService *service, NetworkAccessManager *network, QObject *parent);
- ~QobuzBaseRequest();
-
- typedef QPair Param;
- typedef QList ParamList;
-
- typedef QPair EncodedParam;
- typedef QList EncodedParamList;
-
- QNetworkReply *CreateRequest(const QString &ressource_name, const QList ¶ms_provided);
- QByteArray GetReplyData(QNetworkReply *reply);
- QJsonObject ExtractJsonObj(QByteArray &data);
- QJsonValue ExtractItems(QByteArray &data);
- QJsonValue ExtractItems(QJsonObject &json_obj);
-
- virtual void Error(const QString &error, const QVariant &debug = QVariant()) = 0;
- QString ErrorsToHTML(const QStringList &errors);
-
- QString api_url() { return QString(kApiUrl); }
- QString app_id() { return service_->app_id(); }
- QString app_secret() { return service_->app_secret(); }
- QString username() { return service_->username(); }
- QString password() { return service_->password(); }
- int format() { return service_->format(); }
- int artistssearchlimit() { return service_->artistssearchlimit(); }
- int albumssearchlimit() { return service_->albumssearchlimit(); }
- int songssearchlimit() { return service_->songssearchlimit(); }
-
- qint64 user_id() { return service_->user_id(); }
- QString user_auth_token() { return service_->user_auth_token(); }
- QString device_id() { return service_->device_id(); }
- qint64 credential_id() { return service_->credential_id(); }
-
- bool authenticated() { return service_->authenticated(); }
- bool login_sent() { return service_->login_sent(); }
- int max_login_attempts() { return service_->max_login_attempts(); }
- int login_attempts() { return service_->login_attempts(); }
-
- private slots:
- void HandleSSLErrors(QList ssl_errors);
-
- private:
-
- static const char *kApiUrl;
-
- QobuzService *service_;
- NetworkAccessManager *network_;
-
-};
-
-#endif // QOBUZBASEREQUEST_H
diff --git a/src/qobuz/qobuzfavoriterequest.cpp b/src/qobuz/qobuzfavoriterequest.cpp
deleted file mode 100644
index 1b479a4b7..000000000
--- a/src/qobuz/qobuzfavoriterequest.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/logging.h"
-#include "core/network.h"
-#include "core/closure.h"
-#include "core/song.h"
-#include "qobuzservice.h"
-#include "qobuzbaserequest.h"
-#include "qobuzfavoriterequest.h"
-
-QobuzFavoriteRequest::QobuzFavoriteRequest(QobuzService *service, NetworkAccessManager *network, QObject *parent)
- : QobuzBaseRequest(service, network, parent),
- service_(service),
- network_(network) {}
-
-QobuzFavoriteRequest::~QobuzFavoriteRequest() {
-
- while (!replies_.isEmpty()) {
- QNetworkReply *reply = replies_.takeFirst();
- disconnect(reply, 0, this, 0);
- reply->abort();
- reply->deleteLater();
- }
-
-}
-
-QString QobuzFavoriteRequest::FavoriteText(const FavoriteType type) {
-
- switch (type) {
- case FavoriteType_Artists:
- return "artists";
- case FavoriteType_Albums:
- return "albums";
- case FavoriteType_Songs:
- default:
- return "tracks";
- }
-
-}
-
-void QobuzFavoriteRequest::AddArtists(const SongList &songs) {
- AddFavorites(FavoriteType_Artists, songs);
-}
-
-void QobuzFavoriteRequest::AddAlbums(const SongList &songs) {
- AddFavorites(FavoriteType_Albums, songs);
-}
-
-void QobuzFavoriteRequest::AddSongs(const SongList &songs) {
- AddFavorites(FavoriteType_Songs, songs);
-}
-
-void QobuzFavoriteRequest::AddFavorites(const FavoriteType type, const SongList &songs) {
-
- if (songs.isEmpty()) return;
-
- QString text;
- switch (type) {
- case FavoriteType_Artists:
- text = "artist_ids";
- break;
- case FavoriteType_Albums:
- text = "album_ids";
- break;
- case FavoriteType_Songs:
- text = "track_ids";
- break;
- }
-
- QStringList ids_list;
- for (const Song &song : songs) {
- QString id;
- switch (type) {
- case FavoriteType_Artists:
- if (song.artist_id() <= 0) continue;
- id = QString::number(song.artist_id());
- break;
- case FavoriteType_Albums:
- if (song.album_id().isEmpty()) continue;
- id = song.album_id();
- break;
- case FavoriteType_Songs:
- if (song.song_id() <= 0) continue;
- id = QString::number(song.song_id());
- break;
- }
- if (id.isEmpty()) continue;
- if (!ids_list.contains(id)) {
- ids_list << id;
- }
- }
- if (ids_list.isEmpty()) return;
-
- QString ids = ids_list.join(',');
-
- typedef QPair EncodedParam;
-
- ParamList params = ParamList() << Param("app_id", app_id())
- << Param("user_auth_token", user_auth_token())
- << Param(text, ids);
-
- QUrlQuery url_query;
- for (const Param& param : params) {
- EncodedParam encoded_param(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
- url_query.addQueryItem(encoded_param.first, encoded_param.second);
- }
-
- QNetworkReply *reply = CreateRequest("favorite/create", params);
- NewClosure(reply, SIGNAL(finished()), this, SLOT(AddFavoritesReply(QNetworkReply*, const FavoriteType, const SongList&)), reply, type, songs);
- replies_ << reply;
-
-}
-
-void QobuzFavoriteRequest::AddFavoritesReply(QNetworkReply *reply, const FavoriteType type, const SongList &songs) {
-
- if (replies_.contains(reply)) {
- replies_.removeAll(reply);
- reply->deleteLater();
- }
- else {
- return;
- }
-
- QByteArray data = GetReplyData(reply);
-
- if (reply->error() != QNetworkReply::NoError) {
- return;
- }
-
- qLog(Debug) << "Qobuz:" << songs.count() << "songs added to" << FavoriteText(type) << "favorites.";
-
- switch (type) {
- case FavoriteType_Artists:
- emit ArtistsAdded(songs);
- break;
- case FavoriteType_Albums:
- emit AlbumsAdded(songs);
- break;
- case FavoriteType_Songs:
- emit SongsAdded(songs);
- break;
- }
-
-}
-
-void QobuzFavoriteRequest::RemoveArtists(const SongList &songs) {
- RemoveFavorites(FavoriteType_Artists, songs);
-}
-
-void QobuzFavoriteRequest::RemoveAlbums(const SongList &songs) {
- RemoveFavorites(FavoriteType_Albums, songs);
-}
-
-void QobuzFavoriteRequest::RemoveSongs(const SongList &songs) {
- RemoveFavorites(FavoriteType_Songs, songs);
-}
-
-void QobuzFavoriteRequest::RemoveFavorites(const FavoriteType type, const SongList &songs) {
-
- if (songs.isEmpty()) return;
-
- QString text;
- switch (type) {
- case FavoriteType_Artists:
- text = "artist_ids";
- break;
- case FavoriteType_Albums:
- text = "album_ids";
- break;
- case FavoriteType_Songs:
- text = "track_ids";
- break;
- }
-
- QStringList ids_list;
- for (const Song &song : songs) {
- QString id;
- switch (type) {
- case FavoriteType_Artists:
- if (song.artist_id() <= 0) continue;
- id = QString::number(song.artist_id());
- break;
- case FavoriteType_Albums:
- if (song.album_id().isEmpty()) continue;
- id = song.album_id();
- break;
- case FavoriteType_Songs:
- if (song.song_id() <= 0) continue;
- id = QString::number(song.song_id());
- break;
- }
- if (id.isEmpty()) continue;
- if (!ids_list.contains(id)) {
- ids_list << id;
- }
- }
- if (ids_list.isEmpty()) return;
-
- QString ids = ids_list.join(',');
-
- ParamList params = ParamList() << Param("app_id", app_id())
- << Param("user_auth_token", user_auth_token())
- << Param(text, ids);
-
- QUrlQuery url_query;
- for (const Param ¶m : params) {
- EncodedParam encoded_param(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
- url_query.addQueryItem(encoded_param.first, encoded_param.second);
- }
-
- QNetworkReply *reply = CreateRequest("favorite/delete", params);
- NewClosure(reply, SIGNAL(finished()), this, SLOT(RemoveFavoritesReply(QNetworkReply*, const FavoriteType, const SongList&)), reply, type, songs);
- replies_ << reply;
-
-}
-
-void QobuzFavoriteRequest::RemoveFavoritesReply(QNetworkReply *reply, const FavoriteType type, const SongList &songs) {
-
- if (replies_.contains(reply)) {
- replies_.removeAll(reply);
- reply->deleteLater();
- }
- else {
- return;
- }
-
- QByteArray data = GetReplyData(reply);
- if (reply->error() != QNetworkReply::NoError) {
- return;
- }
-
- qLog(Debug) << "Qobuz:" << songs.count() << "songs removed from" << FavoriteText(type) << "favorites.";
-
- switch (type) {
- case FavoriteType_Artists:
- emit ArtistsRemoved(songs);
- break;
- case FavoriteType_Albums:
- emit AlbumsRemoved(songs);
- break;
- case FavoriteType_Songs:
- emit SongsRemoved(songs);
- break;
- }
-
-}
-
-void QobuzFavoriteRequest::Error(const QString &error, const QVariant &debug) {
-
- qLog(Error) << "Qobuz:" << error;
- if (debug.isValid()) qLog(Debug) << debug;
-
-}
diff --git a/src/qobuz/qobuzfavoriterequest.h b/src/qobuz/qobuzfavoriterequest.h
deleted file mode 100644
index d176c833e..000000000
--- a/src/qobuz/qobuzfavoriterequest.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZFAVORITEREQUEST_H
-#define QOBUZFAVORITEREQUEST_H
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-
-#include "qobuzbaserequest.h"
-#include "core/song.h"
-
-class QNetworkReply;
-class QobuzService;
-class NetworkAccessManager;
-
-class QobuzFavoriteRequest : public QobuzBaseRequest {
- Q_OBJECT
-
- public:
- QobuzFavoriteRequest(QobuzService *service, NetworkAccessManager *network, QObject *parent);
- ~QobuzFavoriteRequest();
-
- enum FavoriteType {
- FavoriteType_Artists,
- FavoriteType_Albums,
- FavoriteType_Songs
- };
-
- signals:
- void ArtistsAdded(const SongList &songs);
- void AlbumsAdded(const SongList &songs);
- void SongsAdded(const SongList &songs);
- void ArtistsRemoved(const SongList &songs);
- void AlbumsRemoved(const SongList &songs);
- void SongsRemoved(const SongList &songs);
-
- private slots:
- void AddArtists(const SongList &songs);
- void AddAlbums(const SongList &songs);
- void AddSongs(const SongList &songs);
-
- void RemoveArtists(const SongList &songs);
- void RemoveAlbums(const SongList &songs);
- void RemoveSongs(const SongList &songs);
-
- void AddFavoritesReply(QNetworkReply *reply, const FavoriteType type, const SongList &songs);
- void RemoveFavoritesReply(QNetworkReply *reply, const FavoriteType type, const SongList &songs);
-
- private:
- void Error(const QString &error, const QVariant &debug = QVariant());
- QString FavoriteText(const FavoriteType type);
- void AddFavorites(const FavoriteType type, const SongList &songs);
- void RemoveFavorites(const FavoriteType type, const SongList &songs);
-
- QobuzService *service_;
- NetworkAccessManager *network_;
- QList replies_;
-
-};
-
-#endif // QOBUZFAVORITEREQUEST_H
diff --git a/src/qobuz/qobuzrequest.cpp b/src/qobuz/qobuzrequest.cpp
deleted file mode 100644
index f45697567..000000000
--- a/src/qobuz/qobuzrequest.cpp
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/closure.h"
-#include "core/logging.h"
-#include "core/network.h"
-#include "core/song.h"
-#include "core/timeconstants.h"
-#include "core/application.h"
-#include "covermanager/albumcoverloader.h"
-#include "qobuzservice.h"
-#include "qobuzurlhandler.h"
-#include "qobuzbaserequest.h"
-#include "qobuzrequest.h"
-
-const int QobuzRequest::kMaxConcurrentArtistsRequests = 3;
-const int QobuzRequest::kMaxConcurrentAlbumsRequests = 3;
-const int QobuzRequest::kMaxConcurrentSongsRequests = 3;
-const int QobuzRequest::kMaxConcurrentArtistAlbumsRequests = 3;
-const int QobuzRequest::kMaxConcurrentAlbumSongsRequests = 3;
-const int QobuzRequest::kMaxConcurrentAlbumCoverRequests = 1;
-
-QobuzRequest::QobuzRequest(QobuzService *service, QobuzUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent)
- : QobuzBaseRequest(service, network, parent),
- service_(service),
- url_handler_(url_handler),
- app_(app),
- network_(network),
- type_(type),
- query_id_(-1),
- finished_(false),
- artists_requests_active_(0),
- artists_total_(0),
- artists_received_(0),
- albums_requests_active_(0),
- songs_requests_active_(0),
- artist_albums_requests_active_(0),
- artist_albums_requested_(0),
- artist_albums_received_(0),
- album_songs_requests_active_(0),
- album_songs_requested_(0),
- album_songs_received_(0),
- album_covers_requests_active_(),
- album_covers_requested_(0),
- album_covers_received_(0),
- no_results_(false) {}
-
-QobuzRequest::~QobuzRequest() {
-
- while (!replies_.isEmpty()) {
- QNetworkReply *reply = replies_.takeFirst();
- disconnect(reply, 0, this, 0);
- if (reply->isRunning()) reply->abort();
- reply->deleteLater();
- }
-
- while (!album_cover_replies_.isEmpty()) {
- QNetworkReply *reply = album_cover_replies_.takeFirst();
- disconnect(reply, 0, this, 0);
- if (reply->isRunning()) reply->abort();
- reply->deleteLater();
- }
-
-}
-
-void QobuzRequest::Process() {
-
- switch (type_) {
- case QueryType::QueryType_Artists:
- GetArtists();
- break;
- case QueryType::QueryType_Albums:
- GetAlbums();
- break;
- case QueryType::QueryType_Songs:
- GetSongs();
- break;
- case QueryType::QueryType_SearchArtists:
- ArtistsSearch();
- break;
- case QueryType::QueryType_SearchAlbums:
- AlbumsSearch();
- break;
- case QueryType::QueryType_SearchSongs:
- SongsSearch();
- break;
- default:
- Error("Invalid query type.");
- break;
- }
-
-}
-
-void QobuzRequest::Search(const int query_id, const QString &search_text) {
- query_id_ = query_id;
- search_text_ = search_text;
-}
-
-void QobuzRequest::GetArtists() {
-
- emit UpdateStatus(query_id_, tr("Retrieving artists..."));
- emit UpdateProgress(query_id_, 0);
- AddArtistsRequest();
-
-}
-
-void QobuzRequest::AddArtistsRequest(const int offset, const int limit) {
-
- Request request;
- request.limit = limit;
- request.offset = offset;
- artists_requests_queue_.enqueue(request);
- if (artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests();
-
-}
-
-void QobuzRequest::FlushArtistsRequests() {
-
- while (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) {
-
- Request request = artists_requests_queue_.dequeue();
- ++artists_requests_active_;
-
- ParamList params;
- if (type_ == QueryType_Artists) {
- params << Param("type", "artists");
- params << Param("user_auth_token", user_auth_token());
- }
- else if (type_ == QueryType_SearchArtists) params << Param("query", search_text_);
- if (request.limit > 0) params << Param("limit", QString::number(request.limit));
- if (request.offset > 0) params << Param("offset", QString::number(request.offset));
- QNetworkReply *reply = nullptr;
- if (type_ == QueryType_Artists) {
- reply = CreateRequest(QString("favorite/getUserFavorites"), params);
- }
- else if (type_ == QueryType_SearchArtists) {
- reply = CreateRequest("artist/search", params);
- }
- if (!reply) continue;
- replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(ArtistsReplyReceived(QNetworkReply*, const int, const int)), reply, request.limit, request.offset);
-
- }
-
-}
-
-void QobuzRequest::GetAlbums() {
-
- emit UpdateStatus(query_id_, tr("Retrieving albums..."));
- emit UpdateProgress(query_id_, 0);
- AddAlbumsRequest();
-
-}
-
-void QobuzRequest::AddAlbumsRequest(const int offset, const int limit) {
-
- Request request;
- request.limit = limit;
- request.offset = offset;
- albums_requests_queue_.enqueue(request);
- if (albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests();
-
-}
-
-void QobuzRequest::FlushAlbumsRequests() {
-
- while (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) {
-
- Request request = albums_requests_queue_.dequeue();
- ++albums_requests_active_;
-
- ParamList params;
- if (type_ == QueryType_Albums) {
- params << Param("type", "albums");
- params << Param("user_auth_token", user_auth_token());
- }
- else if (type_ == QueryType_SearchAlbums) params << Param("query", search_text_);
- if (request.limit > 0) params << Param("limit", QString::number(request.limit));
- if (request.offset > 0) params << Param("offset", QString::number(request.offset));
- QNetworkReply *reply = nullptr;
- if (type_ == QueryType_Albums) {
- reply = CreateRequest(QString("favorite/getUserFavorites"), params);
- }
- else if (type_ == QueryType_SearchAlbums) {
- reply = CreateRequest("album/search", params);
- }
- if (!reply) continue;
- replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(AlbumsReplyReceived(QNetworkReply*, const int, const int)), reply, request.limit, request.offset);
-
- }
-
-}
-
-void QobuzRequest::GetSongs() {
-
- emit UpdateStatus(query_id_, tr("Retrieving songs..."));
- emit UpdateProgress(query_id_, 0);
- AddSongsRequest();
-
-}
-
-void QobuzRequest::AddSongsRequest(const int offset, const int limit) {
-
- Request request;
- request.limit = limit;
- request.offset = offset;
- songs_requests_queue_.enqueue(request);
- if (songs_requests_active_ < kMaxConcurrentSongsRequests) FlushSongsRequests();
-
-}
-
-void QobuzRequest::FlushSongsRequests() {
-
- while (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentSongsRequests) {
-
- Request request = songs_requests_queue_.dequeue();
- ++songs_requests_active_;
-
- ParamList params;
- if (type_ == QueryType_Songs) {
- params << Param("type", "tracks");
- params << Param("user_auth_token", user_auth_token());
- }
- else if (type_ == QueryType_SearchSongs) params << Param("query", search_text_);
- if (request.limit > 0) params << Param("limit", QString::number(request.limit));
- if (request.offset > 0) params << Param("offset", QString::number(request.offset));
- QNetworkReply *reply = nullptr;
- if (type_ == QueryType_Songs) {
- reply = CreateRequest(QString("favorite/getUserFavorites"), params);
- }
- else if (type_ == QueryType_SearchSongs) {
- reply = CreateRequest("track/search", params);
- }
- if (!reply) continue;
- replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(SongsReplyReceived(QNetworkReply*, const int, const int)), reply, request.limit, request.offset);
-
- }
-
-}
-
-void QobuzRequest::ArtistsSearch() {
-
- emit UpdateStatus(query_id_, tr("Searching..."));
- emit UpdateProgress(query_id_, 0);
- AddArtistsSearchRequest();
-
-}
-
-void QobuzRequest::AddArtistsSearchRequest(const int offset) {
-
- AddArtistsRequest(offset, service_->artistssearchlimit());
-
-}
-
-void QobuzRequest::AlbumsSearch() {
-
- emit UpdateStatus(query_id_, tr("Searching..."));
- emit UpdateProgress(query_id_, 0);
- AddAlbumsSearchRequest();
-
-}
-
-void QobuzRequest::AddAlbumsSearchRequest(const int offset) {
-
- AddAlbumsRequest(offset, service_->albumssearchlimit());
-
-}
-
-void QobuzRequest::SongsSearch() {
-
- emit UpdateStatus(query_id_, tr("Searching..."));
- emit UpdateProgress(query_id_, 0);
- AddSongsSearchRequest();
-
-}
-
-void QobuzRequest::AddSongsSearchRequest(const int offset) {
-
- AddSongsRequest(offset, service_->songssearchlimit());
-
-}
-
-void QobuzRequest::ArtistsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) {
-
- if (!replies_.contains(reply)) return;
- replies_.removeAll(reply);
- reply->deleteLater();
-
- QByteArray data = GetReplyData(reply);
-
- --artists_requests_active_;
-
- if (finished_) return;
-
- if (data.isEmpty()) {
- ArtistsFinishCheck();
- return;
- }
-
- QJsonObject json_obj = ExtractJsonObj(data);
- if (json_obj.isEmpty()) {
- ArtistsFinishCheck();
- return;
- }
-
- if (!json_obj.contains("artists")) {
- ArtistsFinishCheck();
- Error("Json object is missing artists.", json_obj);
- return;
- }
- QJsonValue json_artists = json_obj["artists"];
- if (!json_artists.isObject()) {
- Error("Json artists is not an object.", json_obj);
- ArtistsFinishCheck();
- return;
- }
- QJsonObject json_obj_artists = json_artists.toObject();
-
- if (!json_obj_artists.contains("limit") ||
- !json_obj_artists.contains("offset") ||
- !json_obj_artists.contains("total") ||
- !json_obj_artists.contains("items")) {
- ArtistsFinishCheck();
- Error("Json artists object is missing values.", json_obj);
- return;
- }
- //int limit = json_obj_artists["limit"].toInt();
- int offset = json_obj_artists["offset"].toInt();
- int artists_total = json_obj_artists["total"].toInt();
-
- if (offset_requested == 0) {
- artists_total_ = artists_total;
- }
- else if (artists_total != artists_total_) {
- Error(QString("total returned does not match previous total! %1 != %2").arg(artists_total).arg(artists_total_));
- ArtistsFinishCheck();
- return;
- }
-
- if (offset != offset_requested) {
- Error(QString("Offset returned does not match offset requested! %1 != %2").arg(offset).arg(offset_requested));
- ArtistsFinishCheck();
- return;
- }
-
- if (offset_requested == 0) {
- emit ProgressSetMaximum(query_id_, artists_total_);
- emit UpdateProgress(query_id_, artists_received_);
- }
-
- QJsonValue json_value = ExtractItems(json_obj_artists);
- if (!json_value.isArray()) {
- ArtistsFinishCheck();
- return;
- }
-
- QJsonArray json_items = json_value.toArray();
- if (json_items.isEmpty()) { // Empty array means no results
- if (offset_requested == 0) no_results_ = true;
- ArtistsFinishCheck();
- return;
- }
-
- int artists_received = 0;
- for (const QJsonValue &value : json_items) {
-
- ++artists_received;
-
- if (!value.isObject()) {
- Error("Invalid Json reply, item not a object.", value);
- continue;
- }
- QJsonObject json_obj = value.toObject();
-
- if (json_obj.contains("item")) {
- QJsonValue json_item = json_obj["item"];
- if (!json_item.isObject()) {
- Error("Invalid Json reply, item not a object.", json_item);
- continue;
- }
- json_obj = json_item.toObject();
- }
-
- if (!json_obj.contains("id") || !json_obj.contains("name")) {
- Error("Invalid Json reply, item missing id or album.", json_obj);
- continue;
- }
-
- qint64 artist_id = json_obj["id"].toInt();
- if (artist_albums_requests_pending_.contains(artist_id)) continue;
- artist_albums_requests_pending_.append(artist_id);
-
- }
- artists_received_ += artists_received;
-
- if (offset_requested != 0) emit UpdateProgress(query_id_, artists_received_);
-
- ArtistsFinishCheck(limit_requested, offset, artists_received);
-
-}
-
-void QobuzRequest::ArtistsFinishCheck(const int limit, const int offset, const int artists_received) {
-
- if (finished_) return;
-
- if ((limit == 0 || limit > artists_received) && artists_received_ < artists_total_) {
- int offset_next = offset + artists_received;
- if (offset_next > 0 && offset_next < artists_total_) {
- if (type_ == QueryType_Artists) AddArtistsRequest(offset_next);
- else if (type_ == QueryType_SearchArtists) AddArtistsSearchRequest(offset_next);
- }
- }
-
- if (!artists_requests_queue_.isEmpty() && artists_requests_active_ < kMaxConcurrentArtistsRequests) FlushArtistsRequests();
-
- if (artists_requests_queue_.isEmpty() && artists_requests_active_ <= 0) { // Artist query is finished, get all albums for all artists.
-
- // Get artist albums
- for (qint64 artist_id : artist_albums_requests_pending_) {
- AddArtistAlbumsRequest(artist_id);
- ++artist_albums_requested_;
- }
- artist_albums_requests_pending_.clear();
-
- if (artist_albums_requested_ > 0) {
- if (artist_albums_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artist...").arg(artist_albums_requested_));
- else emit UpdateStatus(query_id_, tr("Retrieving albums for %1 artists...").arg(artist_albums_requested_));
- emit ProgressSetMaximum(query_id_, artist_albums_requested_);
- emit UpdateProgress(query_id_, 0);
- }
-
- }
-
- FinishCheck();
-
-}
-
-void QobuzRequest::AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) {
- --albums_requests_active_;
- AlbumsReceived(reply, 0, limit_requested, offset_requested);
- if (!albums_requests_queue_.isEmpty() && albums_requests_active_ < kMaxConcurrentAlbumsRequests) FlushAlbumsRequests();
-}
-
-void QobuzRequest::AddArtistAlbumsRequest(const qint64 artist_id, const int offset) {
-
- Request request;
- request.artist_id = artist_id;
- request.offset = offset;
- artist_albums_requests_queue_.enqueue(request);
- if (artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests();
-
-}
-
-void QobuzRequest::FlushArtistAlbumsRequests() {
-
- while (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) {
-
- Request request = artist_albums_requests_queue_.dequeue();
- ++artist_albums_requests_active_;
-
- ParamList params = ParamList() << Param("artist_id", QString::number(request.artist_id))
- << Param("extra", "albums");
-
- if (request.offset > 0) params << Param("offset", QString::number(request.offset));
- QNetworkReply *reply = CreateRequest(QString("artist/get"), params);
- replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(ArtistAlbumsReplyReceived(QNetworkReply*, const qint64, const int)), reply, request.artist_id, request.offset);
-
- }
-
-}
-
-void QobuzRequest::ArtistAlbumsReplyReceived(QNetworkReply *reply, const qint64 artist_id, const int offset_requested) {
-
- --artist_albums_requests_active_;
- ++artist_albums_received_;
- emit UpdateProgress(query_id_, artist_albums_received_);
- AlbumsReceived(reply, artist_id, 0, offset_requested);
- if (!artist_albums_requests_queue_.isEmpty() && artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests) FlushArtistAlbumsRequests();
-
-}
-
-void QobuzRequest::AlbumsReceived(QNetworkReply *reply, const qint64 artist_id_requested, const int limit_requested, const int offset_requested) {
-
- if (!replies_.contains(reply)) return;
- replies_.removeAll(reply);
- reply->deleteLater();
-
- QByteArray data = GetReplyData(reply);
-
- if (finished_) return;
-
- if (data.isEmpty()) {
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
-
- QJsonObject json_obj = ExtractJsonObj(data);
- if (json_obj.isEmpty()) {
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
-
- qint64 album_artist_id = artist_id_requested;
- if (json_obj.contains("id")) {
- album_artist_id = json_obj["id"].toInt();
- }
- QString album_artist;
- if (json_obj.contains("name")) {
- album_artist = json_obj["name"].toString();
- }
-
- if (album_artist_id != artist_id_requested) {
- AlbumsFinishCheck(artist_id_requested);
- Error("Artist id returned does not match artist id requested.", json_obj);
- return;
- }
-
- if (!json_obj.contains("albums")) {
- AlbumsFinishCheck(artist_id_requested);
- Error("Json object is missing albums.", json_obj);
- return;
- }
- QJsonValue json_albums = json_obj["albums"];
- if (!json_albums.isObject()) {
- Error("Json albums is not an object.", json_obj);
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
- QJsonObject json_obj_albums = json_albums.toObject();
-
- if (!json_obj_albums.contains("limit") ||
- !json_obj_albums.contains("offset") ||
- !json_obj_albums.contains("total") ||
- !json_obj_albums.contains("items")) {
- AlbumsFinishCheck(artist_id_requested);
- Error("Json albums object is missing values.", json_obj);
- return;
- }
-
- //int limit = json_obj["limit"].toInt();
- int offset = json_obj["offset"].toInt();
- int albums_total = json_obj["total"].toInt();
-
- if (offset != offset_requested) {
- Error(QString("Offset returned does not match offset requested! %1 != %2").arg(offset).arg(offset_requested));
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
-
- QJsonValue json_value = ExtractItems(json_obj_albums);
- if (!json_value.isArray()) {
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
- QJsonArray json_items = json_value.toArray();
- if (json_items.isEmpty()) {
- if ((type_ == QueryType_Albums || type_ == QueryType_SearchAlbums) && offset_requested == 0) {
- no_results_ = true;
- }
- AlbumsFinishCheck(artist_id_requested);
- return;
- }
-
- int albums_received = 0;
- for (const QJsonValue &value : json_items) {
-
- ++albums_received;
-
- if (!value.isObject()) {
- Error("Invalid Json reply, item not a object.", value);
- continue;
- }
- QJsonObject json_obj = value.toObject();
-
- if (!json_obj.contains("artist") || !json_obj.contains("title") || !json_obj.contains("id")) {
- Error("Invalid Json reply, item missing artist, title or id.", json_obj);
- continue;
- }
-
- QString album_id = json_obj["id"].toString();
- if (album_songs_requests_pending_.contains(album_id)) continue;
-
- QString album = json_obj["title"].toString();
-
- QJsonValue json_value_artist = json_obj["artist"];
- if (!json_value_artist.isObject()) {
- Error("Invalid Json reply, item artist is not a object.", json_value_artist);
- continue;
- }
- QJsonObject json_artist = json_value_artist.toObject();
- if (!json_artist.contains("id") || !json_artist.contains("name")) {
- Error("Invalid Json reply, item artist missing id or name.", json_artist);
- continue;
- }
-
- qint64 artist_id = json_artist["id"].toInt();
- QString artist = json_artist["name"].toString();
- if (artist_id_requested != 0 && artist_id != artist_id_requested) {
- qLog(Debug) << "Skipping artist" << "artist" << artist << artist_id << "does not match album artist" << album_artist_id << album_artist;
- continue;
- }
-
- Request request;
- request.artist_id = artist_id;
- request.album_id = album_id;
- request.album_artist = artist;
- request.album = album;
- album_songs_requests_pending_.insert(album_id, request);
-
- }
-
- AlbumsFinishCheck(artist_id_requested, limit_requested, offset, albums_total, albums_received);
-
-}
-
-void QobuzRequest::AlbumsFinishCheck(const qint64 artist_id, const int limit, const int offset, const int albums_total, const int albums_received) {
-
- if (finished_) return;
-
- if (limit == 0 || limit > albums_received) {
- int offset_next = offset + albums_received;
- if (offset_next > 0 && offset_next < albums_total) {
- switch (type_) {
- case QueryType_Albums:
- AddAlbumsRequest(offset_next);
- break;
- case QueryType_SearchAlbums:
- AddAlbumsSearchRequest(offset_next);
- break;
- case QueryType_Artists:
- case QueryType_SearchArtists:
- AddArtistAlbumsRequest(artist_id, offset_next);
- break;
- default:
- break;
- }
- }
- }
-
- if (
- albums_requests_queue_.isEmpty() &&
- albums_requests_active_ <= 0 &&
- artist_albums_requests_queue_.isEmpty() &&
- artist_albums_requests_active_ <= 0
- ) { // Artist albums query is finished, get all songs for all albums.
-
- // Get songs for all the albums.
-
- QHash ::iterator i;
- for (i = album_songs_requests_pending_.begin() ; i != album_songs_requests_pending_.end() ; ++i) {
- Request request = i.value();
- AddAlbumSongsRequest(request.artist_id, request.album_id, request.album_artist, request.album);
- }
- album_songs_requests_pending_.clear();
-
- if (album_songs_requested_ > 0) {
- if (album_songs_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving songs for %1 album...").arg(album_songs_requested_));
- else emit UpdateStatus(query_id_, tr("Retrieving songs for %1 albums...").arg(album_songs_requested_));
- emit ProgressSetMaximum(query_id_, album_songs_requested_);
- emit UpdateProgress(query_id_, 0);
- }
- }
-
- FinishCheck();
-
-}
-
-void QobuzRequest::SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested) {
-
- --songs_requests_active_;
- SongsReceived(reply, 0, 0, limit_requested, offset_requested);
-
-}
-
-void QobuzRequest::AddAlbumSongsRequest(const qint64 artist_id, const QString &album_id, const QString &album_artist, const QString &album, const int offset) {
-
- Request request;
- request.artist_id = artist_id;
- request.album_id = album_id;
- request.album_artist = album_artist;
- request.album = album;
- request.offset = offset;
- album_songs_requests_queue_.enqueue(request);
- ++album_songs_requested_;
- if (album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests();
-
-}
-
-void QobuzRequest::FlushAlbumSongsRequests() {
-
- while (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) {
-
- Request request = album_songs_requests_queue_.dequeue();
- ++album_songs_requests_active_;
- ParamList params = ParamList() << Param("album_id", request.album_id);
- if (request.offset > 0) params << Param("offset", QString::number(request.offset));
- QNetworkReply *reply = CreateRequest(QString("album/get"), params);
- replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(AlbumSongsReplyReceived(QNetworkReply*, const qint64, const QString&, const int, const QString&, const QString&)), reply, request.artist_id, request.album_id, request.offset, request.album_artist, request.album);
-
- }
-
-}
-
-void QobuzRequest::AlbumSongsReplyReceived(QNetworkReply *reply, const qint64 artist_id, const QString &album_id, const int offset_requested, const QString &album_artist, const QString &album) {
-
- --album_songs_requests_active_;
- ++album_songs_received_;
- if (offset_requested == 0) {
- emit UpdateProgress(query_id_, album_songs_received_);
- }
- SongsReceived(reply, artist_id, album_id, 0, offset_requested, album_artist, album);
-
-}
-
-void QobuzRequest::SongsReceived(QNetworkReply *reply, const qint64 artist_id_requested, const QString &album_id_requested, const int limit_requested, const int offset_requested, const QString &album_artist_requested, const QString &album_requested) {
-
- if (!replies_.contains(reply)) return;
- replies_.removeAll(reply);
- reply->deleteLater();
-
- QByteArray data = GetReplyData(reply);
-
- if (finished_) return;
-
- if (data.isEmpty()) {
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested);
- return;
- }
-
- QJsonObject json_obj = ExtractJsonObj(data);
- if (json_obj.isEmpty()) {
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested);
- return;
- }
-
- if (!json_obj.contains("tracks")) {
- Error("Json object is missing tracks.", json_obj);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist_requested, album_requested);
- return;
- }
-
- qint64 artist_id = artist_id_requested;
- QString album_artist = album_artist_requested;
- QString album_id = album_id_requested;
- QString album = album_requested;
- QUrl cover_url;
-
- if (json_obj.contains("id")) {
- album_id = json_obj["id"].toString();
- }
-
- if (json_obj.contains("title")) {
- album = json_obj["title"].toString();
- }
-
- if (json_obj.contains("artist")) {
- QJsonValue json_artist = json_obj["artist"];
- if (!json_artist.isObject()) {
- Error("Invalid Json reply, album artist is not a object.", json_artist);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- return;
- }
- QJsonObject json_obj_artist = json_artist.toObject();
- if (!json_obj_artist.contains("id") || !json_obj_artist.contains("name")) {
- Error("Invalid Json reply, album artist is missing id or name.", json_obj_artist);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- return;
- }
- artist_id = json_obj_artist["id"].toInt();
- album_artist = json_obj_artist["name"].toString();
- }
-
- if (json_obj.contains("image")) {
- QJsonValue json_image = json_obj["image"];
- if (!json_image.isObject()) {
- Error("Invalid Json reply, album image is not a object.", json_image);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- return;
- }
- QJsonObject json_obj_image = json_image.toObject();
- if (!json_obj_image.contains("large")) {
- Error("Invalid Json reply, album image is missing large.", json_obj_image);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- return;
- }
- QString album_image = json_obj_image["large"].toString();
- if (!album_image.isEmpty()) {
- cover_url = QUrl(album_image);
- }
- }
-
- QJsonValue json_tracks = json_obj["tracks"];
- if (!json_tracks.isObject()) {
- Error("Json tracks is not an object.", json_obj);
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- return;
- }
- QJsonObject json_obj_tracks = json_tracks.toObject();
-
- if (!json_obj_tracks.contains("limit") ||
- !json_obj_tracks.contains("offset") ||
- !json_obj_tracks.contains("total") ||
- !json_obj_tracks.contains("items")) {
- SongsFinishCheck(artist_id_requested, album_id_requested, limit_requested, offset_requested, 0, 0, album_artist, album);
- Error("Json songs object is missing values.", json_obj);
- return;
- }
-
- //int limit = json_obj_tracks["limit"].toInt();
- int offset = json_obj_tracks["offset"].toInt();
- int songs_total = json_obj_tracks["total"].toInt();
-
- if (offset != offset_requested) {
- Error(QString("Offset returned does not match offset requested! %1 != %2").arg(offset).arg(offset_requested));
- SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album);
- return;
- }
-
- QJsonValue json_value = ExtractItems(json_obj_tracks);
- if (!json_value.isArray()) {
- SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album);
- return;
- }
-
- QJsonArray json_items = json_value.toArray();
- if (json_items.isEmpty()) {
- if ((type_ == QueryType_Songs || type_ == QueryType_SearchSongs) && offset_requested == 0) {
- no_results_ = true;
- }
- SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, 0, album_artist, album);
- return;
- }
-
- bool compilation = false;
- bool multidisc = false;
- SongList songs;
- int songs_received = 0;
- for (const QJsonValue &value : json_items) {
-
- if (!value.isObject()) {
- Error("Invalid Json reply, track is not a object.", value);
- continue;
- }
- QJsonObject json_obj = value.toObject();
-
- ++songs_received;
- Song song(Song::Source_Qobuz);
- ParseSong(song, json_obj, artist_id, album_id, album_artist, album, cover_url);
- if (!song.is_valid()) continue;
- if (song.disc() >= 2) multidisc = true;
- if (song.is_compilation()) compilation = true;
- songs << song;
- }
-
- for (Song &song : songs) {
- if (compilation) song.set_compilation_detected(true);
- if (multidisc) {
- QString album_full(QString("%1 - (Disc %2)").arg(song.album()).arg(song.disc()));
- song.set_album(album_full);
- }
- songs_ << song;
- }
-
- SongsFinishCheck(artist_id, album_id, limit_requested, offset_requested, songs_total, songs_received, album_artist, album);
-
-}
-
-void QobuzRequest::SongsFinishCheck(const qint64 artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist, const QString &album) {
-
- if (finished_) return;
-
- if (limit == 0 || limit > songs_received) {
- int offset_next = offset + songs_received;
- if (offset_next > 0 && offset_next < songs_total) {
- switch (type_) {
- case QueryType_Songs:
- AddSongsRequest(offset_next);
- break;
- case QueryType_SearchSongs:
- AddSongsSearchRequest(offset_next);
- break;
- case QueryType_Artists:
- case QueryType_SearchArtists:
- case QueryType_Albums:
- case QueryType_SearchAlbums:
- AddAlbumSongsRequest(artist_id, album_id, album_artist, album, offset_next);
- break;
- default:
- break;
- }
- }
- }
-
- if (!songs_requests_queue_.isEmpty() && songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests();
- if (!album_songs_requests_queue_.isEmpty() && album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests) FlushAlbumSongsRequests();
-
- if (
- service_->download_album_covers() &&
- IsQuery() &&
- songs_requests_queue_.isEmpty() &&
- songs_requests_active_ <= 0 &&
- album_songs_requests_queue_.isEmpty() &&
- album_songs_requests_active_ <= 0 &&
- album_cover_requests_queue_.isEmpty() &&
- album_covers_received_ <= 0 &&
- album_covers_requests_sent_.isEmpty() &&
- album_songs_received_ >= album_songs_requested_
- ) {
- GetAlbumCovers();
- }
-
- FinishCheck();
-
-}
-
-int QobuzRequest::ParseSong(Song &song, const QJsonObject &json_obj, qint64 artist_id, QString album_id, QString album_artist, QString album, QUrl cover_url) {
-
- if (
- !json_obj.contains("id") ||
- !json_obj.contains("title") ||
- !json_obj.contains("track_number") ||
- !json_obj.contains("duration") ||
- !json_obj.contains("copyright") ||
- !json_obj.contains("streamable")
- ) {
- Error("Invalid Json reply, track is missing one or more values.", json_obj);
- return -1;
- }
-
- qint64 song_id = json_obj["id"].toInt();
- QString title = json_obj["title"].toString();
- int track = json_obj["track_number"].toInt();
- QString copyright = json_obj["copyright"].toString();
- quint64 duration = json_obj["duration"].toInt() * kNsecPerSec;
- //bool streamable = json_obj["streamable"].toBool();
- QString composer;
- QString performer;
-
- if (json_obj.contains("album")) {
-
- QJsonValue json_album = json_obj["album"];
- if (!json_album.isObject()) {
- Error("Invalid Json reply, album is not an object.", json_album);
- return -1;
- }
- QJsonObject json_obj_album = json_album.toObject();
-
- if (json_obj_album.contains("id")) {
- album_id = json_obj_album["id"].toString();
- }
-
- if (json_obj_album.contains("title")) {
- album = json_obj_album["title"].toString();
- }
-
- if (json_obj_album.contains("artist")) {
- QJsonValue json_artist = json_obj_album["artist"];
- if (!json_artist.isObject()) {
- Error("Invalid Json reply, album artist is not a object.", json_artist);
- return -1;
- }
- QJsonObject json_obj_artist = json_artist.toObject();
- if (!json_obj_artist.contains("id") || !json_obj_artist.contains("name")) {
- Error("Invalid Json reply, album artist is missing id or name.", json_obj_artist);
- return -1;
- }
- artist_id = json_obj_artist["id"].toInt();
- album_artist = json_obj_artist["name"].toString();
- }
-
- if (json_obj_album.contains("image")) {
- QJsonValue json_image = json_obj_album["image"];
- if (!json_image.isObject()) {
- Error("Invalid Json reply, album image is not a object.", json_image);
- return -1;
- }
- QJsonObject json_obj_image = json_image.toObject();
- if (!json_obj_image.contains("large")) {
- Error("Invalid Json reply, album image is missing large.", json_obj_image);
- return -1;
- }
- QString album_image = json_obj_image["large"].toString();
- if (!album_image.isEmpty()) {
- cover_url = QUrl(album_image);
- }
- }
- }
-
- if (json_obj.contains("composer")) {
- QJsonValue json_composer = json_obj["composer"];
- if (!json_composer.isObject()) {
- Error("Invalid Json reply, track composer is not a object.", json_composer);
- return -1;
- }
- QJsonObject json_obj_composer = json_composer.toObject();
- if (!json_obj_composer.contains("id") || !json_obj_composer.contains("name")) {
- Error("Invalid Json reply, track composer is missing id or name.", json_obj_composer);
- return -1;
- }
- composer = json_obj_composer["name"].toString();
- }
-
- if (json_obj.contains("performer")) {
- QJsonValue json_performer = json_obj["performer"];
- if (!json_performer.isObject()) {
- Error("Invalid Json reply, track performer is not a object.", json_performer);
- return -1;
- }
- QJsonObject json_obj_performer = json_performer.toObject();
- if (!json_obj_performer.contains("id") || !json_obj_performer.contains("name")) {
- Error("Invalid Json reply, track performer is missing id or name.", json_obj_performer);
- return -1;
- }
- performer = json_obj_performer["name"].toString();
- }
-
- //if (!streamable) {
- //Warn(QString("Song %1 %2 %3 is not streamable").arg(album_artist).arg(album).arg(title));
- //}
-
- QUrl url;
- url.setScheme(url_handler_->scheme());
- url.setPath(QString::number(song_id));
-
- title.remove(Song::kTitleRemoveMisc);
-
- //qLog(Debug) << "id" << song_id << "track" << track << "title" << title << "album" << album << "album artist" << album_artist << cover_url << streamable << url;
-
- song.set_source(Song::Source_Qobuz);
- song.set_song_id(song_id);
- song.set_album_id(album_id);
- song.set_artist_id(artist_id);
- song.set_album(album);
- song.set_artist(album_artist);
- song.set_title(title);
- song.set_track(track);
- song.set_url(url);
- song.set_length_nanosec(duration);
- song.set_art_automatic(cover_url);
- song.set_comment(copyright);
- song.set_directory_id(0);
- song.set_filetype(Song::FileType_Stream);
- song.set_filesize(0);
- song.set_mtime(0);
- song.set_ctime(0);
- song.set_valid(true);
-
- return song_id;
-
-}
-
-void QobuzRequest::GetAlbumCovers() {
-
- for (Song &song : songs_) {
- AddAlbumCoverRequest(song);
- }
- FlushAlbumCoverRequests();
-
- if (album_covers_requested_ == 1) emit UpdateStatus(query_id_, tr("Retrieving album cover for %1 album...").arg(album_covers_requested_));
- else emit UpdateStatus(query_id_, tr("Retrieving album covers for %1 albums...").arg(album_covers_requested_));
- emit ProgressSetMaximum(query_id_, album_covers_requested_);
- emit UpdateProgress(query_id_, 0);
-
-}
-
-void QobuzRequest::AddAlbumCoverRequest(Song &song) {
-
- QUrl cover_url(song.art_automatic());
- if (!cover_url.isValid()) return;
-
- if (album_covers_requests_sent_.contains(cover_url)) {
- album_covers_requests_sent_.insertMulti(cover_url, &song);
- return;
- }
-
- AlbumCoverRequest request;
- request.url = cover_url;
- request.filename = app_->album_cover_loader()->CoverFilePath(song.source(), song.effective_albumartist(), song.effective_album(), song.album_id(), QString(), cover_url);
- if (request.filename.isEmpty()) return;
-
- album_covers_requests_sent_.insertMulti(cover_url, &song);
- ++album_covers_requested_;
-
- album_cover_requests_queue_.enqueue(request);
-
-}
-
-void QobuzRequest::FlushAlbumCoverRequests() {
-
- while (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests) {
-
- AlbumCoverRequest request = album_cover_requests_queue_.dequeue();
- ++album_covers_requests_active_;
-
- QNetworkRequest req(request.url);
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
- req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
-#endif
- QNetworkReply *reply = network_->get(req);
- album_cover_replies_ << reply;
- NewClosure(reply, SIGNAL(finished()), this, SLOT(AlbumCoverReceived(QNetworkReply*, const QUrl&, const QString&)), reply, request.url, request.filename);
-
- }
-
-}
-
-void QobuzRequest::AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_url, const QString &filename) {
-
- if (album_cover_replies_.contains(reply)) {
- album_cover_replies_.removeAll(reply);
- reply->deleteLater();
- }
- else {
- AlbumCoverFinishCheck();
- return;
- }
-
- --album_covers_requests_active_;
- ++album_covers_received_;
-
- if (finished_) return;
-
- emit UpdateProgress(query_id_, album_covers_received_);
-
- if (!album_covers_requests_sent_.contains(cover_url)) {
- AlbumCoverFinishCheck();
- return;
- }
-
- if (reply->error() != QNetworkReply::NoError) {
- Error(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
- album_covers_requests_sent_.remove(cover_url);
- AlbumCoverFinishCheck();
- return;
- }
-
- QByteArray data = reply->readAll();
- if (data.isEmpty()) {
- Error(QString("Received empty image data for %1").arg(cover_url.toString()));
- album_covers_requests_sent_.remove(cover_url);
- AlbumCoverFinishCheck();
- return;
- }
-
- QImage image;
- if (image.loadFromData(data)) {
-
- if (image.save(filename, "JPG")) {
- while (album_covers_requests_sent_.contains(cover_url)) {
- Song *song = album_covers_requests_sent_.take(cover_url);
- song->set_art_automatic(QUrl::fromLocalFile(filename));
- }
- }
-
- }
- else {
- album_covers_requests_sent_.remove(cover_url);
- Error(QString("Error decoding image data from %1").arg(cover_url.toString()));
- }
-
- AlbumCoverFinishCheck();
-
-}
-
-void QobuzRequest::AlbumCoverFinishCheck() {
-
- if (!album_cover_requests_queue_.isEmpty() && album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests)
- FlushAlbumCoverRequests();
-
- FinishCheck();
-
-}
-
-void QobuzRequest::FinishCheck() {
-
- if (
- !finished_ &&
- albums_requests_queue_.isEmpty() &&
- artists_requests_queue_.isEmpty() &&
- songs_requests_queue_.isEmpty() &&
- artist_albums_requests_queue_.isEmpty() &&
- album_songs_requests_queue_.isEmpty() &&
- album_cover_requests_queue_.isEmpty() &&
- artist_albums_requests_pending_.isEmpty() &&
- album_songs_requests_pending_.isEmpty() &&
- album_covers_requests_sent_.isEmpty() &&
- artists_requests_active_ <= 0 &&
- albums_requests_active_ <= 0 &&
- songs_requests_active_ <= 0 &&
- artist_albums_requests_active_ <= 0 &&
- artist_albums_received_ >= artist_albums_requested_ &&
- album_songs_requests_active_ <= 0 &&
- album_songs_received_ >= album_songs_requested_ &&
- album_covers_requests_active_ <= 0 &&
- album_covers_received_ >= album_covers_requested_
- ) {
- finished_ = true;
- if (no_results_ && songs_.isEmpty()) {
- if (IsSearch())
- emit Results(query_id_, SongList(), tr("No match."));
- else
- emit Results(query_id_, SongList(), QString());
- }
- else {
- if (songs_.isEmpty() && errors_.isEmpty())
- emit Results(query_id_, songs_, tr("Unknown error"));
- else
- emit Results(query_id_, songs_, ErrorsToHTML(errors_));
- }
- }
-
-}
-
-void QobuzRequest::Error(const QString &error, const QVariant &debug) {
-
- if (!error.isEmpty()) {
- errors_ << error;
- qLog(Error) << "Qobuz:" << error;
- }
- if (debug.isValid()) qLog(Debug) << debug;
- FinishCheck();
-
-}
-
-void QobuzRequest::Warn(const QString &error, const QVariant &debug) {
-
- qLog(Error) << "Qobuz:" << error;
- if (debug.isValid()) qLog(Debug) << debug;
-
-}
-
diff --git a/src/qobuz/qobuzrequest.h b/src/qobuz/qobuzrequest.h
deleted file mode 100644
index ec9a74769..000000000
--- a/src/qobuz/qobuzrequest.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZREQUEST_H
-#define QOBUZREQUEST_H
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/song.h"
-#include "qobuzbaserequest.h"
-
-class QNetworkReply;
-class Application;
-class NetworkAccessManager;
-class QobuzService;
-class QobuzUrlHandler;
-
-class QobuzRequest : public QobuzBaseRequest {
- Q_OBJECT
-
- public:
-
- QobuzRequest(QobuzService *service, QobuzUrlHandler *url_handler, Application *app, NetworkAccessManager *network, QueryType type, QObject *parent);
- ~QobuzRequest();
-
- void ReloadSettings();
-
- void Process();
- void Search(const int search_id, const QString &search_text);
-
- signals:
- void Login();
- void Login(const QString &username, const QString &password, const QString &token);
- void LoginSuccess();
- void LoginFailure(QString failure_reason);
- void Results(const int id, const SongList &songs, const QString &error);
- void UpdateStatus(const int id, const QString &text);
- void ProgressSetMaximum(const int id, const int max);
- void UpdateProgress(const int id, const int max);
- void StreamURLFinished(const QUrl original_url, const QUrl url, const Song::FileType, QString error = QString());
-
- private slots:
-
- void ArtistsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested);
-
- void AlbumsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested);
- void AlbumsReceived(QNetworkReply *reply, const qint64 artist_id_requested, const int limit_requested, const int offset_requested);
-
- void SongsReplyReceived(QNetworkReply *reply, const int limit_requested, const int offset_requested);
- void SongsReceived(QNetworkReply *reply, const qint64 artist_id_requested, const QString &album_id_requested, const int limit_requested, const int offset_requested, const QString &album_artist_requested = QString(), const QString &album_requested = QString());
-
- void ArtistAlbumsReplyReceived(QNetworkReply *reply, const qint64 artist_id, const int offset_requested);
- void AlbumSongsReplyReceived(QNetworkReply *reply, const qint64 artist_id, const QString &album_id, const int offset_requested, const QString &album_artist, const QString &album);
- void AlbumCoverReceived(QNetworkReply *reply, const QUrl &cover_url, const QString &filename);
-
- private:
- typedef QPair Param;
- typedef QList ParamList;
-
- struct Request {
- qint64 artist_id = 0;
- QString album_id = 0;
- qint64 song_id = 0;
- int offset = 0;
- int limit = 0;
- QString album_artist;
- QString album;
- };
- struct AlbumCoverRequest {
- QUrl url;
- QString filename;
- };
-
- bool IsQuery() { return (type_ == QueryType_Artists || type_ == QueryType_Albums || type_ == QueryType_Songs); }
- bool IsSearch() { return (type_ == QueryType_SearchArtists || type_ == QueryType_SearchAlbums || type_ == QueryType_SearchSongs); }
-
- void GetArtists();
- void GetAlbums();
- void GetSongs();
-
- void ArtistsSearch();
- void AlbumsSearch();
- void SongsSearch();
-
- void AddArtistsRequest(const int offset = 0, const int limit = 0);
- void AddArtistsSearchRequest(const int offset = 0);
- void FlushArtistsRequests();
- void AddAlbumsRequest(const int offset = 0, const int limit = 0);
- void AddAlbumsSearchRequest(const int offset = 0);
- void FlushAlbumsRequests();
- void AddSongsRequest(const int offset = 0, const int limit = 0);
- void AddSongsSearchRequest(const int offset = 0);
- void FlushSongsRequests();
-
- void ArtistsFinishCheck(const int limit = 0, const int offset = 0, const int artists_received = 0);
- void AlbumsFinishCheck(const qint64 artist_id, const int limit = 0, const int offset = 0, const int albums_total = 0, const int albums_received = 0);
- void SongsFinishCheck(const qint64 artist_id, const QString &album_id, const int limit, const int offset, const int songs_total, const int songs_received, const QString &album_artist, const QString &album);
-
- void AddArtistAlbumsRequest(const qint64 artist_id, const int offset = 0);
- void FlushArtistAlbumsRequests();
-
- void AddAlbumSongsRequest(const qint64 artist_id, const QString &album_id, const QString &album_artist, const QString &album, const int offset = 0);
- void FlushAlbumSongsRequests();
-
- int ParseSong(Song &song, const QJsonObject &json_obj, qint64 artist_id, QString album_id, QString album_artist, QString album, QUrl cover_url);
-
- QString AlbumCoverFileName(const Song &song);
-
- void GetAlbumCovers();
- void AddAlbumCoverRequest(Song &song);
- void FlushAlbumCoverRequests();
- void AlbumCoverFinishCheck();
-
- void FinishCheck();
- void Warn(const QString &error, const QVariant &debug = QVariant());
- void Error(const QString &error, const QVariant &debug = QVariant());
-
- static const int kMaxConcurrentArtistsRequests;
- static const int kMaxConcurrentAlbumsRequests;
- static const int kMaxConcurrentSongsRequests;
- static const int kMaxConcurrentArtistAlbumsRequests;
- static const int kMaxConcurrentAlbumSongsRequests;
- static const int kMaxConcurrentAlbumCoverRequests;
-
- QobuzService *service_;
- QobuzUrlHandler *url_handler_;
- Application *app_;
- NetworkAccessManager *network_;
-
- QueryType type_;
- int query_id_;
- QString search_text_;
-
- bool finished_;
-
- QQueue artists_requests_queue_;
- QQueue albums_requests_queue_;
- QQueue songs_requests_queue_;
-
- QQueue artist_albums_requests_queue_;
- QQueue album_songs_requests_queue_;
- QQueue album_cover_requests_queue_;
-
- QList artist_albums_requests_pending_;
- QHash album_songs_requests_pending_;
- QMultiMap album_covers_requests_sent_;
-
- int artists_requests_active_;
- int artists_total_;
- int artists_received_;
-
- int albums_requests_active_;
- int songs_requests_active_;
-
- int artist_albums_requests_active_;
- int artist_albums_requested_;
- int artist_albums_received_;
-
- int album_songs_requests_active_;
- int album_songs_requested_;
- int album_songs_received_;
-
- int album_covers_requests_active_;
- int album_covers_requested_;
- int album_covers_received_;
-
- SongList songs_;
- QStringList errors_;
- bool no_results_;
- QList replies_;
- QList album_cover_replies_;
-
-};
-
-#endif // QOBUZREQUEST_H
diff --git a/src/qobuz/qobuzservice.cpp b/src/qobuz/qobuzservice.cpp
deleted file mode 100644
index 930ab7958..000000000
--- a/src/qobuz/qobuzservice.cpp
+++ /dev/null
@@ -1,765 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/application.h"
-#include "core/player.h"
-#include "core/closure.h"
-#include "core/logging.h"
-#include "core/network.h"
-#include "core/database.h"
-#include "core/song.h"
-#include "core/utilities.h"
-#include "internet/internetsearch.h"
-#include "collection/collectionbackend.h"
-#include "collection/collectionmodel.h"
-#include "qobuzservice.h"
-#include "qobuzurlhandler.h"
-#include "qobuzbaserequest.h"
-#include "qobuzrequest.h"
-#include "qobuzfavoriterequest.h"
-#include "qobuzstreamurlrequest.h"
-#include "settings/settingsdialog.h"
-#include "settings/qobuzsettingspage.h"
-
-using std::shared_ptr;
-
-const Song::Source QobuzService::kSource = Song::Source_Qobuz;
-const char *QobuzService::kAuthUrl = "https://www.qobuz.com/api.json/0.2/user/login";
-const int QobuzService::kLoginAttempts = 2;
-const int QobuzService::kTimeResetLoginAttempts = 60000;
-
-const char *QobuzService::kArtistsSongsTable = "qobuz_artists_songs";
-const char *QobuzService::kAlbumsSongsTable = "qobuz_albums_songs";
-const char *QobuzService::kSongsTable = "qobuz_songs";
-
-const char *QobuzService::kArtistsSongsFtsTable = "qobuz_artists_songs_fts";
-const char *QobuzService::kAlbumsSongsFtsTable = "qobuz_albums_songs_fts";
-const char *QobuzService::kSongsFtsTable = "qobuz_songs_fts";
-
-QobuzService::QobuzService(Application *app, QObject *parent)
- : InternetService(Song::Source_Qobuz, "Qobuz", "qobuz", app, parent),
- app_(app),
- network_(new NetworkAccessManager(this)),
- url_handler_(new QobuzUrlHandler(app, this)),
- artists_collection_backend_(nullptr),
- albums_collection_backend_(nullptr),
- songs_collection_backend_(nullptr),
- artists_collection_model_(nullptr),
- albums_collection_model_(nullptr),
- songs_collection_model_(nullptr),
- artists_collection_sort_model_(new QSortFilterProxyModel(this)),
- albums_collection_sort_model_(new QSortFilterProxyModel(this)),
- songs_collection_sort_model_(new QSortFilterProxyModel(this)),
- timer_search_delay_(new QTimer(this)),
- timer_login_attempt_(new QTimer(this)),
- favorite_request_(new QobuzFavoriteRequest(this, network_, this)),
- format_(0),
- search_delay_(1500),
- artistssearchlimit_(1),
- albumssearchlimit_(1),
- songssearchlimit_(1),
- download_album_covers_(true),
- user_id_(-1),
- credential_id_(-1),
- pending_search_id_(0),
- next_pending_search_id_(1),
- search_id_(0),
- login_sent_(false),
- login_attempts_(0)
- {
-
- app->player()->RegisterUrlHandler(url_handler_);
-
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
- network_->setRedirectPolicy(QNetworkRequest::NoLessSafeRedirectPolicy);
-#endif
-
- // Backends
-
- artists_collection_backend_ = new CollectionBackend();
- artists_collection_backend_->moveToThread(app_->database()->thread());
- artists_collection_backend_->Init(app_->database(), Song::Source_Qobuz, kArtistsSongsTable, QString(), QString(), kArtistsSongsFtsTable);
-
- albums_collection_backend_ = new CollectionBackend();
- albums_collection_backend_->moveToThread(app_->database()->thread());
- albums_collection_backend_->Init(app_->database(), Song::Source_Qobuz, kAlbumsSongsTable, QString(), QString(), kAlbumsSongsFtsTable);
-
- songs_collection_backend_ = new CollectionBackend();
- songs_collection_backend_->moveToThread(app_->database()->thread());
- songs_collection_backend_->Init(app_->database(), Song::Source_Qobuz, kSongsTable, QString(), QString(), kSongsFtsTable);
-
- artists_collection_model_ = new CollectionModel(artists_collection_backend_, app_, this);
- albums_collection_model_ = new CollectionModel(albums_collection_backend_, app_, this);
- songs_collection_model_ = new CollectionModel(songs_collection_backend_, app_, this);
-
- artists_collection_sort_model_->setSourceModel(artists_collection_model_);
- artists_collection_sort_model_->setSortRole(CollectionModel::Role_SortText);
- artists_collection_sort_model_->setDynamicSortFilter(true);
- artists_collection_sort_model_->setSortLocaleAware(true);
- artists_collection_sort_model_->sort(0);
-
- albums_collection_sort_model_->setSourceModel(albums_collection_model_);
- albums_collection_sort_model_->setSortRole(CollectionModel::Role_SortText);
- albums_collection_sort_model_->setDynamicSortFilter(true);
- albums_collection_sort_model_->setSortLocaleAware(true);
- albums_collection_sort_model_->sort(0);
-
- songs_collection_sort_model_->setSourceModel(songs_collection_model_);
- songs_collection_sort_model_->setSortRole(CollectionModel::Role_SortText);
- songs_collection_sort_model_->setDynamicSortFilter(true);
- songs_collection_sort_model_->setSortLocaleAware(true);
- songs_collection_sort_model_->sort(0);
-
- // Search
-
- timer_search_delay_->setSingleShot(true);
- connect(timer_search_delay_, SIGNAL(timeout()), SLOT(StartSearch()));
-
- timer_login_attempt_->setSingleShot(true);
- connect(timer_login_attempt_, SIGNAL(timeout()), SLOT(ResetLoginAttempts()));
-
- connect(this, SIGNAL(Login()), SLOT(SendLogin()));
- connect(this, SIGNAL(Login(QString, QString, QString)), SLOT(SendLogin(QString, QString, QString)));
-
- connect(this, SIGNAL(AddArtists(const SongList&)), favorite_request_, SLOT(AddArtists(const SongList&)));
- connect(this, SIGNAL(AddAlbums(const SongList&)), favorite_request_, SLOT(AddAlbums(const SongList&)));
- connect(this, SIGNAL(AddSongs(const SongList&)), favorite_request_, SLOT(AddSongs(const SongList&)));
-
- connect(this, SIGNAL(RemoveArtists(const SongList&)), favorite_request_, SLOT(RemoveArtists(const SongList&)));
- connect(this, SIGNAL(RemoveAlbums(const SongList&)), favorite_request_, SLOT(RemoveAlbums(const SongList&)));
- connect(this, SIGNAL(RemoveSongs(const SongList&)), favorite_request_, SLOT(RemoveSongs(const SongList&)));
-
- connect(favorite_request_, SIGNAL(ArtistsAdded(const SongList&)), artists_collection_backend_, SLOT(AddOrUpdateSongs(const SongList&)));
- connect(favorite_request_, SIGNAL(AlbumsAdded(const SongList&)), albums_collection_backend_, SLOT(AddOrUpdateSongs(const SongList&)));
- connect(favorite_request_, SIGNAL(SongsAdded(const SongList&)), songs_collection_backend_, SLOT(AddOrUpdateSongs(const SongList&)));
-
- connect(favorite_request_, SIGNAL(ArtistsRemoved(const SongList&)), artists_collection_backend_, SLOT(DeleteSongs(const SongList&)));
- connect(favorite_request_, SIGNAL(AlbumsRemoved(const SongList&)), albums_collection_backend_, SLOT(DeleteSongs(const SongList&)));
- connect(favorite_request_, SIGNAL(SongsRemoved(const SongList&)), songs_collection_backend_, SLOT(DeleteSongs(const SongList&)));
-
- ReloadSettings();
-
-}
-
-QobuzService::~QobuzService() {
-
- while (!stream_url_requests_.isEmpty()) {
- QobuzStreamURLRequest *stream_url_req = stream_url_requests_.takeFirst();
- disconnect(stream_url_req, 0, this, 0);
- stream_url_req->deleteLater();
- }
-
- artists_collection_backend_->deleteLater();
- albums_collection_backend_->deleteLater();
- songs_collection_backend_->deleteLater();
-
-}
-
-void QobuzService::Exit() {
-
- wait_for_exit_ << artists_collection_backend_ << albums_collection_backend_ << songs_collection_backend_;
-
- connect(artists_collection_backend_, SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
- connect(albums_collection_backend_, SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
- connect(songs_collection_backend_, SIGNAL(ExitFinished()), this, SLOT(ExitReceived()));
-
- artists_collection_backend_->ExitAsync();
- albums_collection_backend_->ExitAsync();
- songs_collection_backend_->ExitAsync();
-
-}
-
-void QobuzService::ExitReceived() {
-
- QObject *obj = static_cast(sender());
- disconnect(obj, 0, this, 0);
- qLog(Debug) << obj << "successfully exited.";
- wait_for_exit_.removeAll(obj);
- if (wait_for_exit_.isEmpty()) emit ExitFinished();
-
-}
-
-void QobuzService::ShowConfig() {
- app_->OpenSettingsDialogAtPage(SettingsDialog::Page_Qobuz);
-}
-
-void QobuzService::ReloadSettings() {
-
- QSettings s;
- s.beginGroup(QobuzSettingsPage::kSettingsGroup);
-
- app_id_ = s.value("app_id").toString();
- app_secret_ = s.value("app_secret").toString();
-
- username_ = s.value("username").toString();
- QByteArray password = s.value("password").toByteArray();
- if (password.isEmpty()) password_.clear();
- else password_ = QString::fromUtf8(QByteArray::fromBase64(password));
-
- format_ = s.value("format", 27).toInt();
- search_delay_ = s.value("searchdelay", 1500).toInt();
- artistssearchlimit_ = s.value("artistssearchlimit", 4).toInt();
- albumssearchlimit_ = s.value("albumssearchlimit", 10).toInt();
- songssearchlimit_ = s.value("songssearchlimit", 10).toInt();
- download_album_covers_ = s.value("downloadalbumcovers", true).toBool();
-
- user_id_ = s.value("user_id").toInt();
- device_id_ = s.value("device_id").toString();
- user_auth_token_ = s.value("user_auth_token").toString();
-
- s.endGroup();
-
-}
-
-void QobuzService::SendLogin() {
- SendLogin(app_id_, username_, password_);
-}
-
-void QobuzService::SendLogin(const QString &app_id, const QString &username, const QString &password) {
-
- emit UpdateStatus(tr("Authenticating..."));
- login_errors_.clear();
-
- login_sent_ = true;
- ++login_attempts_;
- if (timer_login_attempt_->isActive()) timer_login_attempt_->stop();
- timer_login_attempt_->setInterval(kTimeResetLoginAttempts);
- timer_login_attempt_->start();
-
- const ParamList params = ParamList() << Param("app_id", app_id)
- << Param("username", username)
- << Param("password", password)
- << Param("device_manufacturer_id", Utilities::MacAddress());
-
- QUrlQuery url_query;
- for (const Param ¶m : params) {
- EncodedParam encoded_param(QUrl::toPercentEncoding(param.first), QUrl::toPercentEncoding(param.second));
- url_query.addQueryItem(encoded_param.first, encoded_param.second);
- }
-
- QUrl url(kAuthUrl);
- QNetworkRequest req(url);
-
- req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
-
- QByteArray query = url_query.toString(QUrl::FullyEncoded).toUtf8();
- QNetworkReply *reply = network_->post(req, query);
-
- connect(reply, SIGNAL(sslErrors(QList)), this, SLOT(HandleLoginSSLErrors(QList)));
- NewClosure(reply, SIGNAL(finished()), this, SLOT(HandleAuthReply(QNetworkReply*)), reply);
-
- qLog(Debug) << "Qobuz: Sending request" << url << query;
-
-}
-
-void QobuzService::HandleLoginSSLErrors(QList ssl_errors) {
-
- for (QSslError &ssl_error : ssl_errors) {
- login_errors_ += ssl_error.errorString();
- }
-
-}
-
-void QobuzService::HandleAuthReply(QNetworkReply *reply) {
-
- reply->deleteLater();
-
- login_sent_ = false;
-
- if (reply->error() != QNetworkReply::NoError || reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 200) {
- if (reply->error() != QNetworkReply::NoError && reply->error() < 200) {
- // This is a network error, there is nothing more to do.
- LoginError(QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()));
- return;
- }
- else {
- // See if there is Json data containing "status", "code" and "message" - then use that instead.
- QByteArray data(reply->readAll());
- QJsonParseError json_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
- if (json_error.error == QJsonParseError::NoError && !json_doc.isEmpty() && json_doc.isObject()) {
- QJsonObject json_obj = json_doc.object();
- if (!json_obj.isEmpty() && json_obj.contains("status") && json_obj.contains("code") && json_obj.contains("message")) {
- QString status = json_obj["status"].toString();
- int code = json_obj["code"].toInt();
- QString message = json_obj["message"].toString();
- login_errors_ << QString("%1 (%2)").arg(message).arg(code);
- }
- }
- if (login_errors_.isEmpty()) {
- if (reply->error() != QNetworkReply::NoError) {
- login_errors_ << QString("%1 (%2)").arg(reply->errorString()).arg(reply->error());
- }
- else {
- login_errors_ << QString("Received HTTP code %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt());
- }
- }
- LoginError();
- return;
- }
- }
-
- login_errors_.clear();
-
- QByteArray data(reply->readAll());
- QJsonParseError json_error;
- QJsonDocument json_doc = QJsonDocument::fromJson(data, &json_error);
-
- if (json_error.error != QJsonParseError::NoError) {
- LoginError("Authentication reply from server missing Json data.");
- return;
- }
-
- if (json_doc.isEmpty()) {
- LoginError("Authentication reply from server has empty Json document.");
- return;
- }
-
- if (!json_doc.isObject()) {
- LoginError("Authentication reply from server has Json document that is not an object.", json_doc);
- return;
- }
-
- QJsonObject json_obj = json_doc.object();
- if (json_obj.isEmpty()) {
- LoginError("Authentication reply from server has empty Json object.", json_doc);
- return;
- }
-
- if (!json_obj.contains("user_auth_token")) {
- LoginError("Authentication reply from server is missing user_auth_token", json_obj);
- return;
- }
- user_auth_token_ = json_obj["user_auth_token"].toString();
-
- if (!json_obj.contains("user")) {
- LoginError("Authentication reply from server is missing user", json_obj);
- return;
- }
- QJsonValue json_user = json_obj["user"];
- if (!json_user.isObject()) {
- LoginError("Authentication reply user is not a object", json_obj);
- return;
- }
- QJsonObject json_obj_user = json_user.toObject();
-
- if (!json_obj_user.contains("id")) {
- LoginError("Authentication reply from server is missing user id", json_obj_user);
- return;
- }
- user_id_ = json_obj_user["id"].toInt();
-
- if (!json_obj_user.contains("device")) {
- LoginError("Authentication reply from server is missing user device", json_obj_user);
- return;
- }
- QJsonValue json_device = json_obj_user["device"];
- if (!json_device.isObject()) {
- LoginError("Authentication reply from server user device is not a object", json_device);
- return;
- }
- QJsonObject json_obj_device = json_device.toObject();
-
- if (!json_obj_device.contains("device_manufacturer_id")) {
- LoginError("Authentication reply from server device is missing device_manufacturer_id", json_obj_device);
- return;
- }
- device_id_ = json_obj_device["device_manufacturer_id"].toString();
-
- if (!json_obj_user.contains("credential")) {
- LoginError("Authentication reply from server is missing user credential", json_obj_user);
- return;
- }
- QJsonValue json_credential = json_obj_user["credential"];
- if (!json_credential.isObject()) {
- LoginError("Authentication reply from serve userr credential is not a object", json_device);
- return;
- }
- QJsonObject json_obj_credential = json_credential.toObject();
-
- if (!json_obj_credential.contains("id")) {
- LoginError("Authentication reply user credential from server is missing user credential id", json_obj_device);
- return;
- }
- credential_id_ = json_obj_credential["id"].toInt();
-
- QSettings s;
- s.beginGroup(QobuzSettingsPage::kSettingsGroup);
- s.setValue("user_auth_token", user_auth_token_);
- s.setValue("user_id", user_id_);
- s.setValue("credential_id", credential_id_);
- s.setValue("device_id", device_id_);
- s.endGroup();
-
- qLog(Debug) << "Qobuz: Login successful" << "user id" << user_id_ << "user auth token" << user_auth_token_ << "device id" << device_id_;
-
- login_attempts_ = 0;
- if (timer_login_attempt_->isActive()) timer_login_attempt_->stop();
-
- emit LoginComplete(true);
- emit LoginSuccess();
-
-}
-
-void QobuzService::Logout() {
-
- user_auth_token_.clear();
- device_id_.clear();
- user_id_ = -1;
- credential_id_ = -1;
-
- QSettings s;
- s.beginGroup(QobuzSettingsPage::kSettingsGroup);
- s.remove("user_id");
- s.remove("credential_id");
- s.remove("device_id");
- s.remove("user_auth_token");
- s.endGroup();
-
-}
-
-void QobuzService::ResetLoginAttempts() {
- login_attempts_ = 0;
-}
-
-void QobuzService::TryLogin() {
-
- if (authenticated() || login_sent_) return;
-
- if (login_attempts_ >= kLoginAttempts) {
- emit LoginComplete(false, tr("Maximum number of login attempts reached."));
- return;
- }
- if (app_id_.isEmpty()) {
- emit LoginComplete(false, tr("Missing Qobuz app ID."));
- return;
- }
- if (username_.isEmpty()) {
- emit LoginComplete(false, tr("Missing Qobuz username."));
- return;
- }
- if (password_.isEmpty()) {
- emit LoginComplete(false, tr("Missing Qobuz password."));
- return;
- }
-
- emit Login();
-
-}
-
-void QobuzService::ResetArtistsRequest() {
-
- if (artists_request_.get()) {
- disconnect(artists_request_.get(), 0, this, 0);
- disconnect(this, 0, artists_request_.get(), 0);
- artists_request_.reset();
- }
-
-}
-
-void QobuzService::GetArtists() {
-
- if (app_id().isEmpty()) {
- emit ArtistsResults(SongList(), tr("Missing Qobuz app ID."));
- return;
- }
-
- if (!authenticated()) {
- emit ArtistsResults(SongList(), tr("Not authenticated with Qobuz."));
- return;
- }
-
- ResetArtistsRequest();
-
- artists_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Artists, this));
-
- connect(artists_request_.get(), SIGNAL(Results(const int, const SongList&, const QString&)), SLOT(ArtistsResultsReceived(const int, const SongList&, const QString&)));
- connect(artists_request_.get(), SIGNAL(UpdateStatus(const int, const QString&)), SLOT(ArtistsUpdateStatusReceived(const int, const QString&)));
- connect(artists_request_.get(), SIGNAL(ProgressSetMaximum(const int, const int)), SLOT(ArtistsProgressSetMaximumReceived(const int, const int)));
- connect(artists_request_.get(), SIGNAL(UpdateProgress(const int, const int)), SLOT(ArtistsUpdateProgressReceived(const int, const int)));
-
- artists_request_->Process();
-
-}
-
-void QobuzService::ArtistsResultsReceived(const int id, const SongList &songs, const QString &error) {
- Q_UNUSED(id);
- emit ArtistsResults(songs, error);
-}
-
-void QobuzService::ArtistsUpdateStatusReceived(const int id, const QString &text) {
- Q_UNUSED(id);
- emit ArtistsUpdateStatus(text);
-}
-
-void QobuzService::ArtistsProgressSetMaximumReceived(const int id, const int max) {
- Q_UNUSED(id);
- emit ArtistsProgressSetMaximum(max);
-}
-
-void QobuzService::ArtistsUpdateProgressReceived(const int id, const int progress) {
- Q_UNUSED(id);
- emit ArtistsUpdateProgress(progress);
-}
-
-void QobuzService::ResetAlbumsRequest() {
-
- if (albums_request_.get()) {
- disconnect(albums_request_.get(), 0, this, 0);
- disconnect(this, 0, albums_request_.get(), 0);
- albums_request_.reset();
- }
-
-}
-
-void QobuzService::GetAlbums() {
-
- if (app_id().isEmpty()) {
- emit AlbumsResults(SongList(), tr("Missing Qobuz app ID."));
- return;
- }
-
- if (!authenticated()) {
- emit AlbumsResults(SongList(), tr("Not authenticated with Qobuz."));
- return;
- }
-
- ResetAlbumsRequest();
- albums_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Albums, this));
- connect(albums_request_.get(), SIGNAL(Results(const int, const SongList&, const QString&)), SLOT(AlbumsResultsReceived(const int, const SongList&, const QString&)));
- connect(albums_request_.get(), SIGNAL(UpdateStatus(const int, const QString&)), SLOT(AlbumsUpdateStatusReceived(const int, const QString&)));
- connect(albums_request_.get(), SIGNAL(ProgressSetMaximum(const int, const int)), SLOT(AlbumsProgressSetMaximumReceived(const int, const int)));
- connect(albums_request_.get(), SIGNAL(UpdateProgress(const int, const int)), SLOT(AlbumsUpdateProgressReceived(const int, const int)));
-
- albums_request_->Process();
-
-}
-
-void QobuzService::AlbumsResultsReceived(const int id, const SongList &songs, const QString &error) {
- Q_UNUSED(id);
- emit AlbumsResults(songs, error);
-}
-
-void QobuzService::AlbumsUpdateStatusReceived(const int id, const QString &text) {
- Q_UNUSED(id);
- emit AlbumsUpdateStatus(text);
-}
-
-void QobuzService::AlbumsProgressSetMaximumReceived(const int id, const int max) {
- Q_UNUSED(id);
- emit AlbumsProgressSetMaximum(max);
-}
-
-void QobuzService::AlbumsUpdateProgressReceived(const int id, const int progress) {
- Q_UNUSED(id);
- emit AlbumsUpdateProgress(progress);
-}
-
-void QobuzService::ResetSongsRequest() {
-
- if (songs_request_.get()) {
- disconnect(songs_request_.get(), 0, this, 0);
- disconnect(this, 0, songs_request_.get(), 0);
- songs_request_.reset();
- }
-
-}
-
-void QobuzService::GetSongs() {
-
- if (app_id().isEmpty()) {
- emit SongsResults(SongList(), tr("Missing Qobuz app ID."));
- return;
- }
-
- if (!authenticated()) {
- emit SongsResults(SongList(), tr("Not authenticated with Qobuz."));
- return;
- }
-
- ResetSongsRequest();
- songs_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, QobuzBaseRequest::QueryType_Songs, this));
- connect(songs_request_.get(), SIGNAL(Results(const int, const SongList&, const QString&)), SLOT(SongsResultsReceived(const int, const SongList&, const QString&)));
- connect(songs_request_.get(), SIGNAL(UpdateStatus(const int, const QString&)), SLOT(SongsUpdateStatusReceived(const int, const QString&)));
- connect(songs_request_.get(), SIGNAL(ProgressSetMaximum(const int, const int)), SLOT(SongsProgressSetMaximumReceived(const int, const int)));
- connect(songs_request_.get(), SIGNAL(UpdateProgress(const int, const int)), SLOT(SongsUpdateProgressReceived(const int, const int)));
-
- songs_request_->Process();
-
-}
-
-void QobuzService::SongsResultsReceived(const int id, const SongList &songs, const QString &error) {
- Q_UNUSED(id);
- emit SongsResults(songs, error);
-}
-
-void QobuzService::SongsUpdateStatusReceived(const int id, const QString &text) {
- Q_UNUSED(id);
- emit SongsUpdateStatus(text);
-}
-
-void QobuzService::SongsProgressSetMaximumReceived(const int id, const int max) {
- Q_UNUSED(id);
- emit SongsProgressSetMaximum(max);
-}
-
-void QobuzService::SongsUpdateProgressReceived(const int id, const int progress) {
- Q_UNUSED(id);
- emit SongsUpdateProgress(progress);
-}
-
-int QobuzService::Search(const QString &text, InternetSearch::SearchType type) {
-
- pending_search_id_ = next_pending_search_id_;
- pending_search_text_ = text;
- pending_search_type_ = type;
-
- next_pending_search_id_++;
-
- if (text.isEmpty()) {
- timer_search_delay_->stop();
- return pending_search_id_;
- }
- timer_search_delay_->setInterval(search_delay_);
- timer_search_delay_->start();
-
- return pending_search_id_;
-
-}
-
-void QobuzService::StartSearch() {
-
- search_id_ = pending_search_id_;
- search_text_ = pending_search_text_;
-
- if (app_id_.isEmpty()) { // App ID is the only thing needed to search.
- emit SearchResults(search_id_, SongList(), tr("Missing Qobuz app ID."));
- return;
- }
-
- SendSearch();
-
-}
-
-void QobuzService::CancelSearch() {
-}
-
-void QobuzService::SendSearch() {
-
- QobuzBaseRequest::QueryType type;
-
- switch (pending_search_type_) {
- case InternetSearch::SearchType_Artists:
- type = QobuzBaseRequest::QueryType_SearchArtists;
- break;
- case InternetSearch::SearchType_Albums:
- type = QobuzBaseRequest::QueryType_SearchAlbums;
- break;
- case InternetSearch::SearchType_Songs:
- type = QobuzBaseRequest::QueryType_SearchSongs;
- break;
- default:
- //Error("Invalid search type.");
- return;
- }
-
- search_request_.reset(new QobuzRequest(this, url_handler_, app_, network_, type, this));
-
- connect(search_request_.get(), SIGNAL(Results(const int, const SongList&, const QString&)), SLOT(SearchResultsReceived(const int, const SongList&, const QString&)));
- connect(search_request_.get(), SIGNAL(UpdateStatus(const int, const QString&)), SIGNAL(SearchUpdateStatus(const int, const QString&)));
- connect(search_request_.get(), SIGNAL(ProgressSetMaximum(const int, const int)), SIGNAL(SearchProgressSetMaximum(const int, const int)));
- connect(search_request_.get(), SIGNAL(UpdateProgress(const int, const int)), SIGNAL(SearchUpdateProgress(const int, const int)));
-
- search_request_->Search(search_id_, search_text_);
- search_request_->Process();
-
-}
-
-void QobuzService::SearchResultsReceived(const int id, const SongList &songs, const QString &error) {
- emit SearchResults(id, songs, error);
-}
-
-void QobuzService::GetStreamURL(const QUrl &url) {
-
- if (app_id().isEmpty() || app_secret().isEmpty()) { // Don't check for login here, because we allow automatic login.
- emit StreamURLFinished(url, url, Song::FileType_Stream, -1, -1, -1, tr("Missing Qobuz app ID or secret."));
- return;
- }
-
- QobuzStreamURLRequest *stream_url_req = new QobuzStreamURLRequest(this, network_, url, this);
- stream_url_requests_ << stream_url_req;
-
- connect(stream_url_req, SIGNAL(TryLogin()), this, SLOT(TryLogin()));
- connect(stream_url_req, SIGNAL(StreamURLFinished(const QUrl&, const QUrl&, const Song::FileType, const int, const int, const qint64, QString)), this, SLOT(HandleStreamURLFinished(const QUrl&, const QUrl&, const Song::FileType, const int, const int, const qint64, QString)));
- connect(this, SIGNAL(LoginComplete(const bool, QString)), stream_url_req, SLOT(LoginComplete(const bool, QString)));
-
- stream_url_req->Process();
-
-}
-
-void QobuzService::HandleStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, QString error) {
-
- QobuzStreamURLRequest *stream_url_req = qobject_cast(sender());
- if (!stream_url_req || !stream_url_requests_.contains(stream_url_req)) return;
- stream_url_req->deleteLater();
- stream_url_requests_.removeAll(stream_url_req);
-
- emit StreamURLFinished(original_url, stream_url, filetype, samplerate, bit_depth, duration, error);
-
-}
-
-void QobuzService::LoginError(const QString &error, const QVariant &debug) {
-
- if (!error.isEmpty()) login_errors_ << error;
-
- QString error_html;
- for (const QString &error : login_errors_) {
- qLog(Error) << "Qobuz:" << error;
- error_html += error + "
";
- }
- if (debug.isValid()) qLog(Debug) << debug;
-
- emit LoginFailure(error_html);
- emit LoginComplete(false, error_html);
-
- login_errors_.clear();
-
-}
diff --git a/src/qobuz/qobuzservice.h b/src/qobuz/qobuzservice.h
deleted file mode 100644
index d45343dfa..000000000
--- a/src/qobuz/qobuzservice.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZSERVICE_H
-#define QOBUZSERVICE_H
-
-#include "config.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/song.h"
-#include "internet/internetservice.h"
-#include "internet/internetsearch.h"
-
-class QTimer;
-class QNetworkReply;
-class QSortFilterProxyModel;
-class Application;
-class NetworkAccessManager;
-class QobuzUrlHandler;
-class QobuzRequest;
-class QobuzFavoriteRequest;
-class QobuzStreamURLRequest;
-class CollectionBackend;
-class CollectionModel;
-
-using std::shared_ptr;
-
-class QobuzService : public InternetService {
- Q_OBJECT
-
- public:
- QobuzService(Application *app, QObject *parent);
- ~QobuzService();
-
- static const Song::Source kSource;
-
- void Exit();
- void ReloadSettings();
-
- void Logout();
- int Search(const QString &query, InternetSearch::SearchType type);
- void CancelSearch();
-
- int max_login_attempts() { return kLoginAttempts; }
-
- Application *app() { return app_; }
- QString app_id() { return app_id_; }
- QString app_secret() { return app_secret_; }
- QString username() { return username_; }
- QString password() { return password_; }
- int format() { return format_; }
- int search_delay() { return search_delay_; }
- int artistssearchlimit() { return artistssearchlimit_; }
- int albumssearchlimit() { return albumssearchlimit_; }
- int songssearchlimit() { return songssearchlimit_; }
- bool download_album_covers() { return download_album_covers_; }
-
- QString user_auth_token() { return user_auth_token_; }
- qint64 user_id() { return user_id_; }
- QString device_id() { return device_id_; }
- qint64 credential_id() { return credential_id_; }
-
- bool authenticated() { return (!app_id_.isEmpty() && !app_secret_.isEmpty() && !user_auth_token_.isEmpty()); }
- bool login_sent() { return login_sent_; }
- bool login_attempts() { return login_attempts_; }
-
- void GetStreamURL(const QUrl &url);
-
- CollectionBackend *artists_collection_backend() { return artists_collection_backend_; }
- CollectionBackend *albums_collection_backend() { return albums_collection_backend_; }
- CollectionBackend *songs_collection_backend() { return songs_collection_backend_; }
-
- CollectionModel *artists_collection_model() { return artists_collection_model_; }
- CollectionModel *albums_collection_model() { return albums_collection_model_; }
- CollectionModel *songs_collection_model() { return songs_collection_model_; }
-
- QSortFilterProxyModel *artists_collection_sort_model() { return artists_collection_sort_model_; }
- QSortFilterProxyModel *albums_collection_sort_model() { return albums_collection_sort_model_; }
- QSortFilterProxyModel *songs_collection_sort_model() { return songs_collection_sort_model_; }
-
- enum QueryType {
- QueryType_Artists,
- QueryType_Albums,
- QueryType_Songs,
- QueryType_SearchArtists,
- QueryType_SearchAlbums,
- QueryType_SearchSongs,
- };
-
- signals:
-
- public slots:
- void ShowConfig();
- void TryLogin();
- void SendLogin(const QString &app_id, const QString &username, const QString &password);
- void GetArtists();
- void GetAlbums();
- void GetSongs();
- void ResetArtistsRequest();
- void ResetAlbumsRequest();
- void ResetSongsRequest();
-
- private slots:
- void ExitReceived();
- void SendLogin();
- void HandleLoginSSLErrors(QList ssl_errors);
- void HandleAuthReply(QNetworkReply *reply);
- void ResetLoginAttempts();
- void StartSearch();
- void ArtistsResultsReceived(const int id, const SongList &songs, const QString &error);
- void AlbumsResultsReceived(const int id, const SongList &songs, const QString &error);
- void SongsResultsReceived(const int id, const SongList &songs, const QString &error);
- void SearchResultsReceived(const int id, const SongList &songs, const QString &error);
- void ArtistsUpdateStatusReceived(const int id, const QString &text);
- void AlbumsUpdateStatusReceived(const int id, const QString &text);
- void SongsUpdateStatusReceived(const int id, const QString &text);
- void ArtistsProgressSetMaximumReceived(const int id, const int max);
- void AlbumsProgressSetMaximumReceived(const int id, const int max);
- void SongsProgressSetMaximumReceived(const int id, const int max);
- void ArtistsUpdateProgressReceived(const int id, const int progress);
- void AlbumsUpdateProgressReceived(const int id, const int progress);
- void SongsUpdateProgressReceived(const int id, const int progress);
- void HandleStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, QString error);
-
- private:
- typedef QPair Param;
- typedef QList ParamList;
-
- typedef QPair EncodedParam;
- typedef QList EncodedParamList;
-
- void SendSearch();
- void LoginError(const QString &error = QString(), const QVariant &debug = QVariant());
-
- static const char *kAuthUrl;
- static const int kLoginAttempts;
- static const int kTimeResetLoginAttempts;
-
- static const char *kArtistsSongsTable;
- static const char *kAlbumsSongsTable;
- static const char *kSongsTable;
-
- static const char *kArtistsSongsFtsTable;
- static const char *kAlbumsSongsFtsTable;
- static const char *kSongsFtsTable;
-
- Application *app_;
- NetworkAccessManager *network_;
- QobuzUrlHandler *url_handler_;
-
- CollectionBackend *artists_collection_backend_;
- CollectionBackend *albums_collection_backend_;
- CollectionBackend *songs_collection_backend_;
-
- CollectionModel *artists_collection_model_;
- CollectionModel *albums_collection_model_;
- CollectionModel *songs_collection_model_;
-
- QSortFilterProxyModel *artists_collection_sort_model_;
- QSortFilterProxyModel *albums_collection_sort_model_;
- QSortFilterProxyModel *songs_collection_sort_model_;
-
- QTimer *timer_search_delay_;
- QTimer *timer_login_attempt_;
-
- std::shared_ptr artists_request_;
- std::shared_ptr albums_request_;
- std::shared_ptr songs_request_;
- std::shared_ptr search_request_;
- QobuzFavoriteRequest *favorite_request_;
-
- QString app_id_;
- QString app_secret_;
- QString username_;
- QString password_;
- int format_;
- int search_delay_;
- int artistssearchlimit_;
- int albumssearchlimit_;
- int songssearchlimit_;
- bool download_album_covers_;
-
- qint64 user_id_;
- QString user_auth_token_;
- QString device_id_;
- qint64 credential_id_;
-
- int pending_search_id_;
- int next_pending_search_id_;
- QString pending_search_text_;
- InternetSearch::SearchType pending_search_type_;
-
- int search_id_;
- QString search_text_;
- bool login_sent_;
- int login_attempts_;
-
- QList stream_url_requests_;
-
- QStringList login_errors_;
-
- QList wait_for_exit_;
-
-};
-
-#endif // QOBUZSERVICE_H
diff --git a/src/qobuz/qobuzstreamurlrequest.cpp b/src/qobuz/qobuzstreamurlrequest.cpp
deleted file mode 100644
index b8b342541..000000000
--- a/src/qobuz/qobuzstreamurlrequest.cpp
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/logging.h"
-#include "core/network.h"
-#include "core/song.h"
-#include "core/timeconstants.h"
-#include "qobuzservice.h"
-#include "qobuzbaserequest.h"
-#include "qobuzstreamurlrequest.h"
-
-QobuzStreamURLRequest::QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, QObject *parent)
- : QobuzBaseRequest(service, network, parent),
- service_(service),
- reply_(nullptr),
- original_url_(original_url),
- song_id_(original_url.path().toInt()),
- tries_(0),
- need_login_(false) {}
-
-QobuzStreamURLRequest::~QobuzStreamURLRequest() {
-
- if (reply_) {
- disconnect(reply_, 0, this, 0);
- if (reply_->isRunning()) reply_->abort();
- reply_->deleteLater();
- }
-
-}
-
-void QobuzStreamURLRequest::LoginComplete(const bool success, const QString &error) {
-
- if (!need_login_) return;
- need_login_ = false;
-
- if (!success) {
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, error);
- return;
- }
-
- Process();
-
-}
-
-void QobuzStreamURLRequest::Process() {
-
- if (app_id().isEmpty() || app_secret().isEmpty()) {
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Missing Qobuz app ID or secret."));
- return;
- }
-
- if (!authenticated()) {
- need_login_ = true;
- emit TryLogin();
- return;
- }
- GetStreamURL();
-
-}
-
-void QobuzStreamURLRequest::Cancel() {
-
- if (reply_ && reply_->isRunning()) {
- reply_->abort();
- }
- else {
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, tr("Cancelled."));
- }
-
-}
-
-void QobuzStreamURLRequest::GetStreamURL() {
-
- ++tries_;
-
- if (reply_) {
- disconnect(reply_, 0, this, 0);
- if (reply_->isRunning()) reply_->abort();
- reply_->deleteLater();
- }
-
- QByteArray appid = app_id().toUtf8();
- QByteArray secret_decoded = QByteArray::fromBase64(app_secret().toUtf8());
- QString secret;
- for (int x = 0, y = 0; x < secret_decoded.length(); ++x , ++y) {
- if (y == appid.length()) y = 0;
- secret.append(QChar(secret_decoded[x] ^ appid[y]));
- }
-
- quint64 timestamp = QDateTime::currentDateTime().toTime_t();
-
- ParamList params_to_sign = ParamList() << Param("format_id", QString::number(format()))
- << Param("track_id", QString::number(song_id_));
-
- std::sort(params_to_sign.begin(), params_to_sign.end());
-
- QString data_to_sign;
- data_to_sign += "trackgetFileUrl";
- for (const Param ¶m : params_to_sign) {
- data_to_sign += param.first + param.second;
- }
- data_to_sign += QString::number(timestamp);
- data_to_sign += secret.toUtf8();
-
- QByteArray const digest = QCryptographicHash::hash(data_to_sign.toUtf8(), QCryptographicHash::Md5);
- QString signature = QString::fromLatin1(digest.toHex()).rightJustified(32, '0').toLower();
-
- ParamList params = params_to_sign;
- params << Param("request_ts", QString::number(timestamp));
- params << Param("request_sig", signature);
- params << Param("user_auth_token", user_auth_token());
-
- std::sort(params.begin(), params.end());
-
- reply_ = CreateRequest(QString("track/getFileUrl"), params);
- connect(reply_, SIGNAL(finished()), this, SLOT(StreamURLReceived()));
-
-}
-
-void QobuzStreamURLRequest::StreamURLReceived() {
-
- if (!reply_) return;
-
- QByteArray data = GetReplyData(reply_);
-
- disconnect(reply_, 0, this, 0);
- reply_->deleteLater();
- reply_ = nullptr;
-
- if (data.isEmpty()) {
- if (!authenticated() && login_sent() && tries_ <= 1) {
- need_login_ = true;
- return;
- }
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
- return;
- }
-
- QJsonObject json_obj = ExtractJsonObj(data);
- if (json_obj.isEmpty()) {
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
- return;
- }
-
- if (!json_obj.contains("track_id")) {
- Error("Invalid Json reply, stream url is missing track_id.", json_obj);
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
- return;
- }
-
- int track_id = json_obj["track_id"].toInt();
- if (track_id != song_id_) {
- Error("Incorrect track ID returned.", json_obj);
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
- return;
- }
-
- if (!json_obj.contains("mime_type") || !json_obj.contains("url")) {
- Error("Invalid Json reply, stream url is missing url or mime_type.", json_obj);
- emit StreamURLFinished(original_url_, original_url_, Song::FileType_Stream, -1, -1, -1, errors_.first());
- return;
- }
-
- QUrl url(json_obj["url"].toString());
- QString mimetype = json_obj["mime_type"].toString();
-
- Song::FileType filetype(Song::FileType_Unknown);
- QMimeDatabase mimedb;
- for (QString suffix : mimedb.mimeTypeForName(mimetype.toUtf8()).suffixes()) {
- filetype = Song::FiletypeByExtension(suffix);
- if (filetype != Song::FileType_Unknown) break;
- }
- if (filetype == Song::FileType_Unknown) {
- qLog(Debug) << "Qobuz: Unknown mimetype" << mimetype;
- filetype = Song::FileType_Stream;
- }
-
- if (!url.isValid()) {
- Error("Returned stream url is invalid.", json_obj);
- emit StreamURLFinished(original_url_, original_url_, filetype, -1, -1, -1, errors_.first());
- return;
- }
-
- qint64 duration = -1;
- if (json_obj.contains("duration")) {
- duration = json_obj["duration"].toDouble() * kNsecPerSec;
- }
- int samplerate = -1;
- if (json_obj.contains("sampling_rate")) {
- samplerate = json_obj["sampling_rate"].toDouble() * 1000;
- }
- int bit_depth = -1;
- if (json_obj.contains("bit_depth")) {
- bit_depth = json_obj["bit_depth"].toDouble();
- }
-
- emit StreamURLFinished(original_url_, url, filetype, samplerate, bit_depth, duration);
-
-}
-
-void QobuzStreamURLRequest::Error(const QString &error, const QVariant &debug) {
-
- if (!error.isEmpty()) {
- qLog(Error) << "Qobuz:" << error;
- errors_ << error;
- }
- if (debug.isValid()) qLog(Debug) << debug;
-
-}
-
diff --git a/src/qobuz/qobuzstreamurlrequest.h b/src/qobuz/qobuzstreamurlrequest.h
deleted file mode 100644
index 568d7f537..000000000
--- a/src/qobuz/qobuzstreamurlrequest.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZSTREAMURLREQUEST_H
-#define QOBUZSTREAMURLREQUEST_H
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "core/song.h"
-#include "qobuzbaserequest.h"
-
-class QNetworkReply;
-class NetworkAccessManager;
-class QobuzService;
-
-class QobuzStreamURLRequest : public QobuzBaseRequest {
- Q_OBJECT
-
- public:
- QobuzStreamURLRequest(QobuzService *service, NetworkAccessManager *network, const QUrl &original_url, QObject *parent);
- ~QobuzStreamURLRequest();
-
- void GetStreamURL();
- void Process();
- void NeedLogin() { need_login_ = true; }
- void Cancel();
-
- QUrl original_url() { return original_url_; }
- int song_id() { return song_id_; }
- bool need_login() { return need_login_; }
-
- signals:
- void TryLogin();
- void StreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, QString error = QString());
-
- private slots:
- void LoginComplete(const bool success, const QString &error = QString());
- void StreamURLReceived();
-
- private:
- void Error(const QString &error, const QVariant &debug = QVariant());
-
- QobuzService *service_;
- QNetworkReply *reply_;
- QUrl original_url_;
- int song_id_;
- int tries_;
- bool need_login_;
- QStringList errors_;
-
-};
-
-#endif // QOBUZSTREAMURLREQUEST_H
diff --git a/src/qobuz/qobuzurlhandler.cpp b/src/qobuz/qobuzurlhandler.cpp
deleted file mode 100644
index e4a3d27c9..000000000
--- a/src/qobuz/qobuzurlhandler.cpp
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 "core/application.h"
-#include "core/taskmanager.h"
-#include "core/song.h"
-#include "qobuz/qobuzservice.h"
-#include "qobuzurlhandler.h"
-
-QobuzUrlHandler::QobuzUrlHandler(Application *app, QobuzService *service) :
- UrlHandler(service),
- app_(app),
- service_(service),
- task_id_(-1)
- {
-
- connect(service, SIGNAL(StreamURLFinished(const QUrl&, const QUrl&, const Song::FileType, const int, const int, const qint64, QString)), this, SLOT(GetStreamURLFinished(const QUrl&, const QUrl&, const Song::FileType, const int, const int, const qint64, QString)));
-
-}
-
-UrlHandler::LoadResult QobuzUrlHandler::StartLoading(const QUrl &url) {
-
- LoadResult ret(url);
- if (task_id_ != -1) return ret;
- task_id_ = app_->task_manager()->StartTask(QString("Loading %1 stream...").arg(url.scheme()));
- service_->GetStreamURL(url);
- ret.type_ = LoadResult::WillLoadAsynchronously;
- return ret;
-
-}
-
-void QobuzUrlHandler::GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, QString error) {
-
- if (task_id_ == -1) return;
- CancelTask();
- if (error.isEmpty())
- emit AsyncLoadComplete(LoadResult(original_url, LoadResult::TrackAvailable, stream_url, filetype, samplerate, bit_depth, duration));
- else
- emit AsyncLoadComplete(LoadResult(original_url, LoadResult::Error, stream_url, filetype, -1, -1, -1, error));
-
-}
-
-void QobuzUrlHandler::CancelTask() {
- app_->task_manager()->SetTaskFinished(task_id_);
- task_id_ = -1;
-}
diff --git a/src/qobuz/qobuzurlhandler.h b/src/qobuz/qobuzurlhandler.h
deleted file mode 100644
index 2650f5a23..000000000
--- a/src/qobuz/qobuzurlhandler.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 QOBUZURLHANDLER_H
-#define QOBUZURLHANDLER_H
-
-#include
-#include
-#include
-#include
-
-#include "core/urlhandler.h"
-#include "core/song.h"
-#include "qobuz/qobuzservice.h"
-
-class Application;
-
-class QobuzUrlHandler : public UrlHandler {
- Q_OBJECT
-
- public:
- QobuzUrlHandler(Application *app, QobuzService *service);
-
- QString scheme() const { return service_->url_scheme(); }
- LoadResult StartLoading(const QUrl &url);
-
- void CancelTask();
-
- private slots:
- void GetStreamURLFinished(const QUrl &original_url, const QUrl &stream_url, const Song::FileType filetype, const int samplerate, const int bit_depth, const qint64 duration, QString error = QString());
-
- private:
- Application *app_;
- QobuzService *service_;
- int task_id_;
-
-};
-
-#endif
diff --git a/src/settings/qobuzsettingspage.cpp b/src/settings/qobuzsettingspage.cpp
deleted file mode 100644
index 846df5d2e..000000000
--- a/src/settings/qobuzsettingspage.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "settingsdialog.h"
-#include "qobuzsettingspage.h"
-#include "ui_qobuzsettingspage.h"
-#include "core/application.h"
-#include "core/iconloader.h"
-#include "widgets/loginstatewidget.h"
-#include "internet/internetservices.h"
-#include "qobuz/qobuzservice.h"
-
-const char *QobuzSettingsPage::kSettingsGroup = "Qobuz";
-
-QobuzSettingsPage::QobuzSettingsPage(SettingsDialog *parent)
- : SettingsPage(parent),
- ui_(new Ui::QobuzSettingsPage),
- service_(dialog()->app()->internet_services()->Service()) {
-
- ui_->setupUi(this);
- setWindowIcon(IconLoader::Load("qobuz"));
-
- connect(ui_->button_login, SIGNAL(clicked()), SLOT(LoginClicked()));
- connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(LogoutClicked()));
-
- connect(this, SIGNAL(Login(QString, QString, QString)), service_, SLOT(SendLogin(QString, QString, QString)));
-
- connect(service_, SIGNAL(LoginFailure(QString)), SLOT(LoginFailure(QString)));
- connect(service_, SIGNAL(LoginSuccess()), SLOT(LoginSuccess()));
-
- dialog()->installEventFilter(this);
-
- ui_->format->addItem("MP3 320", 5);
- ui_->format->addItem("FLAC Lossless", 6);
- ui_->format->addItem("FLAC Hi-Res <= 96kHz", 7);
- ui_->format->addItem("FLAC Hi-Res > 96kHz", 27);
-
-}
-
-QobuzSettingsPage::~QobuzSettingsPage() { delete ui_; }
-
-void QobuzSettingsPage::Load() {
-
- QSettings s;
-
- s.beginGroup(kSettingsGroup);
- ui_->enable->setChecked(s.value("enabled", false).toBool());
- ui_->app_id->setText(s.value("app_id").toString());
- ui_->app_secret->setText(s.value("app_secret").toString());
-
- ui_->username->setText(s.value("username").toString());
- QByteArray password = s.value("password").toByteArray();
- if (password.isEmpty()) ui_->password->clear();
- else ui_->password->setText(QString::fromUtf8(QByteArray::fromBase64(password)));
-
- dialog()->ComboBoxLoadFromSettings(s, ui_->format, "format", 27);
- ui_->searchdelay->setValue(s.value("searchdelay", 1500).toInt());
- ui_->artistssearchlimit->setValue(s.value("artistssearchlimit", 4).toInt());
- ui_->albumssearchlimit->setValue(s.value("albumssearchlimit", 10).toInt());
- ui_->songssearchlimit->setValue(s.value("songssearchlimit", 10).toInt());
- ui_->checkbox_download_album_covers->setChecked(s.value("downloadalbumcovers", true).toBool());
-
- s.endGroup();
-
- if (service_->authenticated()) ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
-
-}
-
-void QobuzSettingsPage::Save() {
-
- QSettings s;
- s.beginGroup(kSettingsGroup);
- s.setValue("enabled", ui_->enable->isChecked());
- s.setValue("app_id", ui_->app_id->text());
- s.setValue("app_secret", ui_->app_secret->text());
-
- s.setValue("username", ui_->username->text());
- s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64()));
-
- s.setValue("format", ui_->format->itemData(ui_->format->currentIndex()));
- s.setValue("searchdelay", ui_->searchdelay->value());
- s.setValue("artistssearchlimit", ui_->artistssearchlimit->value());
- s.setValue("albumssearchlimit", ui_->albumssearchlimit->value());
- s.setValue("songssearchlimit", ui_->songssearchlimit->value());
- s.setValue("downloadalbumcovers", ui_->checkbox_download_album_covers->isChecked());
- s.endGroup();
-
- service_->ReloadSettings();
-
-}
-
-void QobuzSettingsPage::LoginClicked() {
-
- if (ui_->app_id->text().isEmpty() || ui_->username->text().isEmpty() || ui_->password->text().isEmpty()) {
- QMessageBox::critical(this, tr("Configuration incomplete"), tr("Missing app id, username or password."));
- return;
- }
- emit Login(ui_->app_id->text(), ui_->username->text(), ui_->password->text());
- ui_->button_login->setEnabled(false);
-
-}
-
-bool QobuzSettingsPage::eventFilter(QObject *object, QEvent *event) {
-
- if (object == dialog() && event->type() == QEvent::Enter) {
- ui_->button_login->setEnabled(true);
- return false;
- }
-
- return SettingsPage::eventFilter(object, event);
-
-}
-
-void QobuzSettingsPage::LogoutClicked() {
- service_->Logout();
- ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedOut);
- ui_->button_login->setEnabled(true);
-}
-
-void QobuzSettingsPage::LoginSuccess() {
- if (!this->isVisible()) return;
- ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
- ui_->button_login->setEnabled(true);
-}
-
-void QobuzSettingsPage::LoginFailure(QString failure_reason) {
- if (!this->isVisible()) return;
- QMessageBox::warning(this, tr("Authentication failed"), failure_reason);
-}
diff --git a/src/settings/qobuzsettingspage.h b/src/settings/qobuzsettingspage.h
deleted file mode 100644
index 21db0a4f6..000000000
--- a/src/settings/qobuzsettingspage.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2019, 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 QOBUZSETTINGSPAGE_H
-#define QOBUZSETTINGSPAGE_H
-
-#include
-#include
-
-#include "settings/settingspage.h"
-
-class QEvent;
-class SettingsDialog;
-class QobuzService;
-class Ui_QobuzSettingsPage;
-
-class QobuzSettingsPage : public SettingsPage {
- Q_OBJECT
-
- public:
- explicit QobuzSettingsPage(SettingsDialog* parent = nullptr);
- ~QobuzSettingsPage();
-
- static const char *kSettingsGroup;
-
- void Load();
- void Save();
-
- bool eventFilter(QObject *object, QEvent *event);
-
- signals:
- void Login();
- void Login(const QString &username, const QString &password, const QString &token);
-
- private slots:
- void LoginClicked();
- void LogoutClicked();
- void LoginSuccess();
- void LoginFailure(QString failure_reason);
-
- private:
- Ui_QobuzSettingsPage* ui_;
- QobuzService *service_;
-};
-
-#endif
diff --git a/src/settings/qobuzsettingspage.ui b/src/settings/qobuzsettingspage.ui
deleted file mode 100644
index 6967b321e..000000000
--- a/src/settings/qobuzsettingspage.ui
+++ /dev/null
@@ -1,293 +0,0 @@
-
-
- QobuzSettingsPage
-
-
-
- 0
- 0
- 715
- 836
-
-
-
- Qobuz
-
-
- -
-
-
- Enable
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
- Authentication
-
-
-
-
-
-
-
- 150
- 0
-
-
-
- App ID
-
-
-
- -
-
-
- -
-
-
- Username
-
-
-
- -
-
-
-
-
-
-
-
- -
-
-
- Password
-
-
-
- -
-
-
- QLineEdit::Password
-
-
-
- -
-
-
- App Secret
-
-
-
- -
-
-
-
-
-
- -
-
-
- Login
-
-
-
- -
-
-
- -
-
-
- Preferences
-
-
-
-
-
-
- Audio format
-
-
-
- -
-
-
- -
-
-
- Search delay
-
-
-
- -
-
-
- ms
-
-
- 0
-
-
- 10000
-
-
- 50
-
-
- 1500
-
-
-
- -
-
-
- Artists search limit
-
-
-
- -
-
-
- 1
-
-
- 100
-
-
- 50
-
-
-
- -
-
-
- Albums search limit
-
-
-
- -
-
-
- 1
-
-
- 1000
-
-
- 50
-
-
-
- -
-
-
- Songs search limit
-
-
-
- -
-
-
- 1
-
-
- 1000
-
-
- 50
-
-
-
- -
-
-
- Download album covers
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 30
-
-
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 64
- 64
-
-
-
-
- 64
- 64
-
-
-
- :/icons/64x64/qobuz.png
-
-
-
-
-
-
-
-
-
- LoginStateWidget
- QWidget
- widgets/loginstatewidget.h
- 1
-
-
-
- enable
- app_id
- app_secret
- username
- password
- button_login
- format
- searchdelay
- artistssearchlimit
- albumssearchlimit
- songssearchlimit
- checkbox_download_album_covers
-
-
-
-
-
-
-
diff --git a/src/settings/settingsdialog.cpp b/src/settings/settingsdialog.cpp
index c68c9c5d7..09eac1f88 100644
--- a/src/settings/settingsdialog.cpp
+++ b/src/settings/settingsdialog.cpp
@@ -67,12 +67,6 @@
#ifdef HAVE_MOODBAR
# include "moodbarsettingspage.h"
#endif
-#ifdef HAVE_TIDAL
-# include "tidalsettingspage.h"
-#endif
-#ifdef HAVE_QOBUZ
-# include "qobuzsettingspage.h"
-#endif
#ifdef HAVE_SUBSONIC
# include "subsonicsettingspage.h"
#endif
@@ -149,15 +143,9 @@ SettingsDialog::SettingsDialog(Application *app, QWidget *parent)
AddPage(Page_Moodbar, new MoodbarSettingsPage(this), iface);
#endif
-#if defined(HAVE_TIDAL) || defined(HAVE_SUBSONIC) || defined(HAVE_QOBUZ)
+#if defined(HAVE_SUBSONIC)
QTreeWidgetItem *streaming = AddCategory(tr("Streaming"));
#endif
-#ifdef HAVE_TIDAL
- AddPage(Page_Tidal, new TidalSettingsPage(this), streaming);
-#endif
-#ifdef HAVE_QOBUZ
- AddPage(Page_Qobuz, new QobuzSettingsPage(this), streaming);
-#endif
#ifdef HAVE_SUBSONIC
AddPage(Page_Subsonic, new SubsonicSettingsPage(this), streaming);
#endif
diff --git a/src/settings/settingsdialog.h b/src/settings/settingsdialog.h
index 993bfc303..5de9c55b7 100644
--- a/src/settings/settingsdialog.h
+++ b/src/settings/settingsdialog.h
@@ -84,9 +84,7 @@ class SettingsDialog : public QDialog {
Page_Proxy,
Page_Scrobbler,
Page_Moodbar,
- Page_Tidal,
- Page_Subsonic,
- Page_Qobuz,
+ Page_Subsonic
};
enum Role {
diff --git a/src/settings/tidalsettingspage.cpp b/src/settings/tidalsettingspage.cpp
deleted file mode 100644
index 841cacea7..000000000
--- a/src/settings/tidalsettingspage.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "settingsdialog.h"
-#include "tidalsettingspage.h"
-#include "ui_tidalsettingspage.h"
-#include "core/application.h"
-#include "core/iconloader.h"
-#include "internet/internetservices.h"
-#include "tidal/tidalservice.h"
-#include "widgets/loginstatewidget.h"
-
-const char *TidalSettingsPage::kSettingsGroup = "Tidal";
-
-TidalSettingsPage::TidalSettingsPage(SettingsDialog *parent)
- : SettingsPage(parent),
- ui_(new Ui::TidalSettingsPage),
- service_(dialog()->app()->internet_services()->Service()) {
-
- ui_->setupUi(this);
- setWindowIcon(IconLoader::Load("tidal"));
-
- connect(ui_->button_login, SIGNAL(clicked()), SLOT(LoginClicked()));
- connect(ui_->login_state, SIGNAL(LogoutClicked()), SLOT(LogoutClicked()));
- connect(ui_->oauth, SIGNAL(toggled(bool)), SLOT(OAuthClicked(bool)));
-
- connect(this, SIGNAL(Login()), service_, SLOT(StartAuthorisation()));
- connect(this, SIGNAL(Login(const QString&, const QString&, const QString&)), service_, SLOT(SendLogin(const QString&, const QString&, const QString&)));
-
- connect(service_, SIGNAL(LoginFailure(const QString&)), SLOT(LoginFailure(const QString&)));
- connect(service_, SIGNAL(LoginSuccess()), SLOT(LoginSuccess()));
-
- dialog()->installEventFilter(this);
-
- ui_->quality->addItem("Low", "LOW");
- ui_->quality->addItem("High", "HIGH");
- ui_->quality->addItem("Lossless", "LOSSLESS");
- ui_->quality->addItem("Hi resolution", "HI_RES");
-
- ui_->coversize->addItem("160x160", "160x160");
- ui_->coversize->addItem("320x320", "320x320");
- ui_->coversize->addItem("640x640", "640x640");
- ui_->coversize->addItem("750x750", "750x750");
- ui_->coversize->addItem("1280x1280", "1280x1280");
-
- ui_->streamurl->addItem("streamurl", StreamUrlMethod_StreamUrl);
- ui_->streamurl->addItem("urlpostpaywall", StreamUrlMethod_UrlPostPaywall);
- ui_->streamurl->addItem("playbackinfopostpaywall", StreamUrlMethod_PlaybackInfoPostPaywall);
-
-}
-
-TidalSettingsPage::~TidalSettingsPage() { delete ui_; }
-
-void TidalSettingsPage::Load() {
-
- QSettings s;
-
- s.beginGroup(kSettingsGroup);
- ui_->enable->setChecked(s.value("enabled", false).toBool());
- ui_->oauth->setChecked(s.value("oauth", false).toBool());
-
- ui_->client_id->setText(s.value("client_id").toString());
- ui_->api_token->setText(s.value("api_token").toString());
-
- ui_->username->setText(s.value("username").toString());
- QByteArray password = s.value("password").toByteArray();
- if (password.isEmpty()) ui_->password->clear();
- else ui_->password->setText(QString::fromUtf8(QByteArray::fromBase64(password)));
-
- dialog()->ComboBoxLoadFromSettings(s, ui_->quality, "quality", "HIGH");
- ui_->searchdelay->setValue(s.value("searchdelay", 1500).toInt());
- ui_->artistssearchlimit->setValue(s.value("artistssearchlimit", 4).toInt());
- ui_->albumssearchlimit->setValue(s.value("albumssearchlimit", 10).toInt());
- ui_->songssearchlimit->setValue(s.value("songssearchlimit", 10).toInt());
- ui_->checkbox_fetchalbums->setChecked(s.value("fetchalbums", false).toBool());
- ui_->checkbox_download_album_covers->setChecked(s.value("downloadalbumcovers", true).toBool());
- dialog()->ComboBoxLoadFromSettings(s, ui_->coversize, "coversize", "320x320");
-
- StreamUrlMethod stream_url = static_cast(s.value("streamurl").toInt());
- int i = ui_->streamurl->findData(stream_url);
- if (i == -1) i = ui_->streamurl->findData(StreamUrlMethod_StreamUrl);
- ui_->streamurl->setCurrentIndex(i);
-
- s.endGroup();
-
- OAuthClicked(ui_->oauth->isChecked());
- if (service_->authenticated()) ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
-
-}
-
-void TidalSettingsPage::Save() {
-
- QSettings s;
- s.beginGroup(kSettingsGroup);
- s.setValue("enabled", ui_->enable->isChecked());
- s.setValue("oauth", ui_->oauth->isChecked());
- s.setValue("client_id", ui_->client_id->text());
- s.setValue("api_token", ui_->api_token->text());
-
- s.setValue("username", ui_->username->text());
- s.setValue("password", QString::fromUtf8(ui_->password->text().toUtf8().toBase64()));
-
- s.setValue("quality", ui_->quality->itemData(ui_->quality->currentIndex()));
- s.setValue("searchdelay", ui_->searchdelay->value());
- s.setValue("artistssearchlimit", ui_->artistssearchlimit->value());
- s.setValue("albumssearchlimit", ui_->albumssearchlimit->value());
- s.setValue("songssearchlimit", ui_->songssearchlimit->value());
- s.setValue("fetchalbums", ui_->checkbox_fetchalbums->isChecked());
- s.setValue("downloadalbumcovers", ui_->checkbox_download_album_covers->isChecked());
- s.setValue("coversize", ui_->coversize->itemData(ui_->coversize->currentIndex()));
- s.setValue("streamurl", ui_->streamurl->itemData(ui_->streamurl->currentIndex()));
- s.endGroup();
-
- service_->ReloadSettings();
-
-}
-
-void TidalSettingsPage::LoginClicked() {
-
- if (ui_->oauth->isChecked()) {
- if (ui_->client_id->text().isEmpty()) {
- QMessageBox::critical(this, tr("Configuration incomplete"), tr("Missing Tidal client ID."));
- return;
- }
- emit Login();
- }
- else {
- if (ui_->username->text().isEmpty() || ui_->password->text().isEmpty()) {
- QMessageBox::critical(this, tr("Configuration incomplete"), tr("Missing username or password."));
- return;
- }
- emit Login(ui_->api_token->text(), ui_->username->text(), ui_->password->text());
- }
- ui_->button_login->setEnabled(false);
-
-}
-
-bool TidalSettingsPage::eventFilter(QObject *object, QEvent *event) {
-
- if (object == dialog() && event->type() == QEvent::Enter) {
- ui_->button_login->setEnabled(true);
- return false;
- }
-
- return SettingsPage::eventFilter(object, event);
-
-}
-
-void TidalSettingsPage::OAuthClicked(const bool enabled) {
-
- ui_->client_id->setEnabled(enabled);
- ui_->api_token->setEnabled(!enabled);
- ui_->username->setEnabled(!enabled);
- ui_->password->setEnabled(!enabled);
-
-}
-
-void TidalSettingsPage::LogoutClicked() {
- service_->Logout();
- ui_->button_login->setEnabled(true);
- ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedOut);
-}
-
-void TidalSettingsPage::LoginSuccess() {
- if (!this->isVisible()) return;
- ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn);
- ui_->button_login->setEnabled(true);
-}
-
-void TidalSettingsPage::LoginFailure(const QString &failure_reason) {
- if (!this->isVisible()) return;
- QMessageBox::warning(this, tr("Authentication failed"), failure_reason);
- ui_->button_login->setEnabled(true);
-}
diff --git a/src/settings/tidalsettingspage.h b/src/settings/tidalsettingspage.h
deleted file mode 100644
index 87cd6a6cf..000000000
--- a/src/settings/tidalsettingspage.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Strawberry Music Player
- * Copyright 2018, 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 TIDALSETTINGSPAGE_H
-#define TIDALSETTINGSPAGE_H
-
-#include "config.h"
-
-#include
-#include
-
-#include "settings/settingspage.h"
-
-class QEvent;
-class TidalService;
-class SettingsDialog;
-class Ui_TidalSettingsPage;
-
-class TidalSettingsPage : public SettingsPage {
- Q_OBJECT
-
- public:
- explicit TidalSettingsPage(SettingsDialog* parent = nullptr);
- ~TidalSettingsPage();
-
- static const char *kSettingsGroup;
-
- enum StreamUrlMethod {
- StreamUrlMethod_StreamUrl,
- StreamUrlMethod_UrlPostPaywall,
- StreamUrlMethod_PlaybackInfoPostPaywall,
- };
-
- void Load();
- void Save();
-
- bool eventFilter(QObject *object, QEvent *event);
-
- signals:
- void Login();
- void Login(const QString &api_token, const QString &username, const QString &password);
-
- private slots:
- void OAuthClicked(const bool enabled);
- void LoginClicked();
- void LogoutClicked();
- void LoginSuccess();
- void LoginFailure(const QString &failure_reason);
-
- private:
- Ui_TidalSettingsPage* ui_;
- TidalService *service_;
-};
-
-#endif
diff --git a/src/settings/tidalsettingspage.ui b/src/settings/tidalsettingspage.ui
deleted file mode 100644
index 2541762e8..000000000
--- a/src/settings/tidalsettingspage.ui
+++ /dev/null
@@ -1,344 +0,0 @@
-
-
- TidalSettingsPage
-
-
-
-