From 301ca055bdf82877df275762ebdeb72d553e98c5 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Wed, 26 Dec 2018 01:17:17 +0100 Subject: [PATCH] Fix submit and error handling --- src/scrobbler/audioscrobbler.cpp | 6 +- src/scrobbler/listenbrainzscrobbler.cpp | 17 +++- src/scrobbler/listenbrainzscrobbler.h | 1 + src/scrobbler/scrobblercache.h | 1 + src/scrobbler/scrobblerservice.h | 1 + src/scrobbler/scrobblingapi20.cpp | 127 ++++++++++++++++++++---- src/scrobbler/scrobblingapi20.h | 1 + 7 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/scrobbler/audioscrobbler.cpp b/src/scrobbler/audioscrobbler.cpp index 61b313307..7edec606b 100644 --- a/src/scrobbler/audioscrobbler.cpp +++ b/src/scrobbler/audioscrobbler.cpp @@ -150,11 +150,7 @@ void AudioScrobbler::Love(const Song &song) { void AudioScrobbler::Submit() { for (ScrobblerService *service : scrobbler_services_->List()) { if (!service->IsEnabled() || !service->IsAuthenticated() || service->IsSubmitted()) continue; - int msec = 300; - if (submit_delay_ != 0) msec = (submit_delay_ * kMsecPerSec); - DoAfter(this, SLOT(Submit()), msec); - service->Submitted(); - DoInAMinuteOrSo(service, SLOT(Submit())); + service->DoSubmit(); } } diff --git a/src/scrobbler/listenbrainzscrobbler.cpp b/src/scrobbler/listenbrainzscrobbler.cpp index 0332ef037..2c62acc60 100644 --- a/src/scrobbler/listenbrainzscrobbler.cpp +++ b/src/scrobbler/listenbrainzscrobbler.cpp @@ -407,13 +407,24 @@ void ListenBrainzScrobbler::Scrobble(const Song &song) { Submit(); } else { - int msec = (app_->scrobbler()->SubmitDelay() * kMsecPerSec); + qint64 msec = (app_->scrobbler()->SubmitDelay() * 60 * kMsecPerSec); DoAfter(this, SLOT(Submit()), msec); } } } +void ListenBrainzScrobbler::DoSubmit() { + + if (!submitted_ && cache_->Count() > 0) { + submitted_ = true; + qint64 msec = 30000ll; + if (app_->scrobbler()->SubmitDelay() != 0) msec = (app_->scrobbler()->SubmitDelay() * 60 * kMsecPerSec); + DoAfter(this, SLOT(Submit()), msec); + } + +} + void ListenBrainzScrobbler::Submit() { qLog(Debug) << __PRETTY_FUNCTION__; @@ -461,12 +472,14 @@ void ListenBrainzScrobbler::ScrobbleRequestFinished(QNetworkReply *reply, QList< QByteArray data = GetReplyData(reply); if (data.isEmpty()) { cache_->ClearSent(list); + DoSubmit(); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { cache_->ClearSent(list); + DoSubmit(); return; } @@ -475,6 +488,7 @@ void ListenBrainzScrobbler::ScrobbleRequestFinished(QNetworkReply *reply, QList< QString error_desc = json_obj["error_description"].toString(); Error(error_desc); cache_->ClearSent(list); + DoSubmit(); return; } @@ -484,6 +498,7 @@ void ListenBrainzScrobbler::ScrobbleRequestFinished(QNetworkReply *reply, QList< } cache_->Flush(list); + DoSubmit(); } diff --git a/src/scrobbler/listenbrainzscrobbler.h b/src/scrobbler/listenbrainzscrobbler.h index 1a2556aa0..d5b5837eb 100644 --- a/src/scrobbler/listenbrainzscrobbler.h +++ b/src/scrobbler/listenbrainzscrobbler.h @@ -89,6 +89,7 @@ class ListenBrainzScrobbler : public ScrobblerService { void RequestSession(QUrl url, QString token); void AuthError(QString error); void Error(QString error, QVariant debug = QVariant()); + void DoSubmit(); static const char *kAuthUrl; static const char *kAuthTokenUrl; diff --git a/src/scrobbler/scrobblercache.h b/src/scrobbler/scrobblercache.h index 0d68a6844..c9365476e 100644 --- a/src/scrobbler/scrobblercache.h +++ b/src/scrobbler/scrobblercache.h @@ -47,6 +47,7 @@ class ScrobblerCache : public QObject { ScrobblerCacheItem *Get(const quint64 hash); void Remove(const quint64 hash); void Remove(ScrobblerCacheItem &item); + int Count() const { return scrobbler_cache_.size(); }; QList List() const { return scrobbler_cache_.values(); } void ClearSent(const QList list); void Flush(const QList list); diff --git a/src/scrobbler/scrobblerservice.h b/src/scrobbler/scrobblerservice.h index f211e81b9..62cfe65ca 100644 --- a/src/scrobbler/scrobblerservice.h +++ b/src/scrobbler/scrobblerservice.h @@ -52,6 +52,7 @@ class ScrobblerService : public QObject { virtual void Love(const Song &song) = 0; virtual void Error(QString error, QVariant debug = QVariant()) = 0; + virtual void DoSubmit() = 0; virtual void Submitted() = 0; virtual bool IsSubmitted() const { return false; } diff --git a/src/scrobbler/scrobblingapi20.cpp b/src/scrobbler/scrobblingapi20.cpp index a2d3f2dc4..656e19628 100644 --- a/src/scrobbler/scrobblingapi20.cpp +++ b/src/scrobbler/scrobblingapi20.cpp @@ -340,8 +340,8 @@ QByteArray ScrobblingAPI20::GetReplyData(QNetworkReply *reply) { QJsonObject json_obj = json_doc.object(); if (json_obj.contains("error") && json_obj.contains("message")) { error_code = json_obj["error"].toInt(); - QString message = json_obj["message"].toString(); - error_reason = QString("%1 (%2)").arg(message).arg(error_code); + QString error_message = json_obj["message"].toString(); + error_reason = QString("%1 (%2)").arg(error_message).arg(error_code); } else { error_reason = QString("%1 (%2)").arg(reply->errorString()).arg(reply->error()); @@ -424,13 +424,24 @@ void ScrobblingAPI20::Scrobble(const Song &song) { Submit(); } else { - int msec = (app_->scrobbler()->SubmitDelay() * kMsecPerSec); + qint64 msec = (app_->scrobbler()->SubmitDelay() * 60 * kMsecPerSec); DoAfter(this, SLOT(Submit()), msec); } } } +void ScrobblingAPI20::DoSubmit() { + + if (!submitted_ && cache()->Count() > 0) { + submitted_ = true; + qint64 msec = 30000ll; + if (app_->scrobbler()->SubmitDelay() != 0) msec = (app_->scrobbler()->SubmitDelay() * 60 * kMsecPerSec); + DoAfter(this, SLOT(Submit()), msec); + } + +} + void ScrobblingAPI20::Submit() { qLog(Debug) << __PRETTY_FUNCTION__ << name_; @@ -474,22 +485,31 @@ void ScrobblingAPI20::ScrobbleRequestFinished(QNetworkReply *reply, QListClearSent(list); + DoSubmit(); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { cache()->ClearSent(list); + DoSubmit(); + return; + } + + if (json_obj.contains("error") && json_obj.contains("message")) { + int error_code = json_obj["error"].toInt(); + QString error_message = json_obj["message"].toString(); + QString error_reason = QString("%1 (%2)").arg(error_message).arg(error_code); + Error(error_reason); + cache()->ClearSent(list); + DoSubmit(); return; } if (!json_obj.contains("scrobbles")) { - if (json_obj.contains("error")) { - int error = json_obj["error"].toInt(); - Error(QString("Error: %1: %2").arg(QString::number(error)).arg(error)); - } - Error("Json reply from server is missing scrobbles."); + Error("Json reply from server is missing scrobbles.", json_obj); cache()->ClearSent(list); + DoSubmit(); return; } @@ -498,30 +518,36 @@ void ScrobblingAPI20::ScrobbleRequestFinished(QNetworkReply *reply, QListGet(timestamp); if (!item) { Error(QString("Received reply for non-existing cache entry %1.").arg(timestamp)); + DoSubmit(); return; } QByteArray data = GetReplyData(reply); if (data.isEmpty()) { + item->sent_ = false; + DoSubmit(); return; } QJsonObject json_obj = ExtractJsonObj(data); if (json_obj.isEmpty()) { + item->sent_ = false; + DoSubmit(); + return; + } + + if (json_obj.contains("error") && json_obj.contains("message")) { + int error_code = json_obj["error"].toInt(); + QString error_message = json_obj["message"].toString(); + QString error_reason = QString("%1 (%2)").arg(error_message).arg(error_code); + Error(error_reason); + item->sent_ = false; + DoSubmit(); return; } if (!json_obj.contains("scrobbles")) { - if (json_obj.contains("error")) { - int error = json_obj["error"].toInt(); - Error(QString("Error: %1: %2").arg(QString::number(error)).arg(error)); - } - Error("Json reply from server is missing scrobbles."); + Error("Json reply from server is missing scrobbles.", json_obj); + item->sent_ = false; + DoSubmit(); return; } + cache()->Remove(timestamp); + item = nullptr; + QJsonValue json_scrobbles = json_obj["scrobbles"]; if (!json_scrobbles.isObject()) { Error("Json scrobbles is not an object.", json_obj); + DoSubmit(); return; } json_obj = json_scrobbles.toObject(); if (json_obj.isEmpty()) { Error("Json scrobbles object is empty.", json_scrobbles); + DoSubmit(); return; } if (!json_obj.contains("@attr") || !json_obj.contains("scrobble")) { Error("Json scrobbles object is missing values.", json_obj); + DoSubmit(); return; } QJsonValue json_attr = json_obj["@attr"]; if (!json_attr.isObject()) { Error("Json scrobbles attr is not an object.", json_attr); + DoSubmit(); return; } QJsonObject json_obj_attr = json_attr.toObject(); if (json_obj_attr.isEmpty()) { Error("Json scrobbles attr is empty.", json_attr); + DoSubmit(); return; } QJsonValue json_scrobble = json_obj["scrobble"]; if (!json_scrobble.isObject()) { Error("Json scrobbles scrobble is not an object.", json_scrobble); + DoSubmit(); return; } QJsonObject json_obj_scrobble = json_scrobble.toObject(); if (json_obj_scrobble.isEmpty()) { Error("Json scrobbles scrobble is empty.", json_scrobble); + DoSubmit(); return; } if (!json_obj_attr.contains("accepted") || !json_obj_attr.contains("ignored")) { Error("Json scrobbles attr is missing values.", json_obj_attr); + DoSubmit(); return; } if (!json_obj_scrobble.contains("artist") || !json_obj_scrobble.contains("album") || !json_obj_scrobble.contains("albumArtist") || !json_obj_scrobble.contains("track") || !json_obj_scrobble.contains("timestamp")) { Error("Json scrobbles scrobble is missing values.", json_obj_scrobble); + DoSubmit(); return; } - int accepted = json_obj_attr["accepted"].toVariant().toInt(); - if (accepted == 1) { - qLog(Debug) << name_ << "Scrobble for" << item->song_ << "accepted"; - } - else { - Error(QString("Scrobble for \"%1\" not accepted").arg(item->song_)); + QJsonValue json_value_artist = json_obj_scrobble["artist"]; + QJsonValue json_value_album = json_obj_scrobble["album"]; + QJsonValue json_value_song = json_obj_scrobble["track"]; + + if (!json_value_artist.isObject() || !json_value_album.isObject() || !json_value_song.isObject()) { + Error("Json scrobbles scrobble values are not objects.", json_obj_scrobble); + DoSubmit(); + return; } - cache()->Remove(timestamp); + QJsonObject json_obj_artist = json_value_artist.toObject(); + QJsonObject json_obj_album = json_value_album.toObject(); + QJsonObject json_obj_song = json_value_song.toObject(); + + if (json_obj_artist.isEmpty() || json_obj_album.isEmpty() || json_obj_song.isEmpty()) { + Error("Json scrobbles scrobble values objects are empty.", json_obj_scrobble); + DoSubmit(); + return; + } + + if (!json_obj_artist.contains("#text") || !json_obj_album.contains("#text") || !json_obj_song.contains("#text")) { + Error("Json scrobbles scrobble values objects are missing #text.", json_obj_artist); + DoSubmit(); + return; + } + + QString artist = json_obj_artist["#text"].toString(); + QString album = json_obj_album["#text"].toString(); + QString song = json_obj_song["#text"].toString(); + + int accepted = json_obj_attr["accepted"].toVariant().toInt(); + if (accepted == 1) { + qLog(Debug) << name_ << "Scrobble for" << song << "accepted"; + } + else { + Error(QString("Scrobble for \"%1\" not accepted").arg(song)); + } + + DoSubmit(); } diff --git a/src/scrobbler/scrobblingapi20.h b/src/scrobbler/scrobblingapi20.h index e3acc3a79..1eb9a7993 100644 --- a/src/scrobbler/scrobblingapi20.h +++ b/src/scrobbler/scrobblingapi20.h @@ -134,6 +134,7 @@ class ScrobblingAPI20 : public ScrobblerService { void SendSingleScrobble(ScrobblerCacheItem *item); void Error(QString error, QVariant debug = QVariant()); QString ErrorString(ScrobbleErrorCode error) const; + void DoSubmit(); QString name_; QString settings_group_;