Fixed subsonic scrobble command + internal scrobbler: do not record listen that have been played for less than 5s

This commit is contained in:
emeric
2021-04-08 14:11:09 +02:00
parent 4cf60f7b8b
commit 42e9403b55
9 changed files with 45 additions and 47 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ namespace Scrobbling
virtual ~IScrobbler() = default; virtual ~IScrobbler() = default;
virtual void listenStarted(const Listen& listen) = 0; virtual void listenStarted(const Listen& listen) = 0;
virtual void listenFinished(const Listen& listen, std::chrono::seconds duration) = 0; virtual void listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration) = 0;
virtual void addListen(const Listen& listen, const Wt::WDateTime& timePoint) = 0; virtual void addListen(const Listen& listen, const Wt::WDateTime& timePoint) = 0;
+1 -1
View File
@@ -50,7 +50,7 @@ namespace Scrobbling
} }
void void
Scrobbling::listenFinished(const Listen& listen, std::chrono::seconds duration) Scrobbling::listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration)
{ {
if (auto scrobbler {getUserScrobbler(listen.userId)}) if (auto scrobbler {getUserScrobbler(listen.userId)})
_scrobblers[*scrobbler]->listenFinished(listen, duration); _scrobblers[*scrobbler]->listenFinished(listen, duration);
+1 -1
View File
@@ -35,7 +35,7 @@ namespace Scrobbling
private: private:
void listenStarted(const Listen& listen) override; void listenStarted(const Listen& listen) override;
void listenFinished(const Listen& listen, std::chrono::seconds duration) override; void listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration) override;
void addListen(const Listen& listen, Wt::WDateTime timePoint) override; void addListen(const Listen& listen, Wt::WDateTime timePoint) override;
std::vector<Wt::Dbo::ptr<Database::Artist>> getRecentArtists(Database::Session& session, std::vector<Wt::Dbo::ptr<Database::Artist>> getRecentArtists(Database::Session& session,
@@ -35,15 +35,19 @@ namespace Scrobbling
{} {}
void void
InternalScrobbler::listenStarted(const Listen& listen) InternalScrobbler::listenStarted(const Listen& /*listen*/)
{ {
addListen(listen, Wt::WDateTime::currentDateTime()); // nothing to do
} }
void void
InternalScrobbler::listenFinished(const Listen& /*event*/, std::chrono::seconds /* duration */) InternalScrobbler::listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration)
{ {
// nothing to do // record tracks that have been played for at least of few seconds...
if (duration && *duration < std::chrono::seconds {5})
return;
addListen(listen, Wt::WDateTime::currentDateTime());
} }
void void
@@ -30,7 +30,7 @@ namespace Scrobbling
private: private:
void listenStarted(const Listen& listen) override; void listenStarted(const Listen& listen) override;
void listenFinished(const Listen& listen, std::chrono::seconds duration) override; void listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration) override;
void addListen(const Listen& listen, const Wt::WDateTime& timePoint) override; void addListen(const Listen& listen, const Wt::WDateTime& timePoint) override;
@@ -214,13 +214,13 @@ namespace Scrobbling
} }
void void
ListenBrainzScrobbler::listenFinished(const Listen& listen, std::chrono::seconds duration) ListenBrainzScrobbler::listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration)
{ {
if (!canBeScrobbled(_db.getTLSSession(), listen.trackId, duration)) if (duration && !canBeScrobbled(_db.getTLSSession(), listen.trackId, *duration))
return; return;
Listen timedListen {listen}; Listen timedListen {listen};
const Wt::WDateTime now {Wt::WDateTime::currentDateTime().addSecs(-duration.count())}; const Wt::WDateTime now {Wt::WDateTime::currentDateTime()};
_ioService.post([=] _ioService.post([=]
{ {
@@ -50,7 +50,7 @@ namespace Scrobbling
private: private:
void listenStarted(const Listen& listen) override; void listenStarted(const Listen& listen) override;
void listenFinished(const Listen& listen, std::chrono::seconds duration) override; void listenFinished(const Listen& listen, std::optional<std::chrono::seconds> duration) override;
void addListen(const Listen& listen, const Wt::WDateTime& timePoint) override; void addListen(const Listen& listen, const Wt::WDateTime& timePoint) override;
Wt::Dbo::ptr<Database::TrackList> getListensTrackList(Database::Session& session, Wt::Dbo::ptr<Database::User> user) override; Wt::Dbo::ptr<Database::TrackList> getListensTrackList(Database::Session& session, Wt::Dbo::ptr<Database::User> user) override;
@@ -49,7 +49,7 @@ namespace Scrobbling
// Scrobbling // Scrobbling
virtual void listenStarted(const Listen& listen) = 0; virtual void listenStarted(const Listen& listen) = 0;
virtual void listenFinished(const Listen& listen, std::chrono::seconds duration) = 0; virtual void listenFinished(const Listen& listen, std::optional<std::chrono::seconds> playedDuration = std::nullopt) = 0;
virtual void addListen(const Listen& listen, Wt::WDateTime timePoint) = 0; virtual void addListen(const Listen& listen, Wt::WDateTime timePoint) = 0;
+28 -34
View File
@@ -1644,52 +1644,46 @@ Response
handleScrobble(RequestContext& context) handleScrobble(RequestContext& context)
{ {
const std::vector<Id> ids {getMandatoryMultiParametersAs<Id>(context.parameters, "id")}; const std::vector<Id> ids {getMandatoryMultiParametersAs<Id>(context.parameters, "id")};
const std::vector<unsigned long> times {getMandatoryMultiParametersAs<unsigned long>(context.parameters, "time")}; const std::vector<unsigned long> times {getMultiParametersAs<unsigned long>(context.parameters, "time")};
const bool submission{getParameterAs<bool>(context.parameters, "submission").value_or(true)};
// only for tracks
if (!std::all_of(std::cbegin(ids), std::cend(ids), [](const Id& id) { return id.type == Id::Type::Track; })) if (!std::all_of(std::cbegin(ids), std::cend(ids), [](const Id& id) { return id.type == Id::Type::Track; }))
throw BadParameterGenericError {"id"}; throw BadParameterGenericError {"id"};
if (ids.size() != times.size()) // playing now => no time to be provided
if (!submission && !times.empty())
throw BadParameterGenericError {"time"}; throw BadParameterGenericError {"time"};
struct Scrobble // playing now => only one at a time
if (!submission && ids.size() > 1)
throw BadParameterGenericError {"id"};
// if multiple submissions, must have times
if (ids.size() > 1 && ids.size() != times.size())
throw BadParameterGenericError {"time"};
if (!submission)
{ {
Scrobbling::Listen listen; Service<Scrobbling::IScrobbling>::get()->listenStarted({context.userId, ids.front().value});
Wt::WDateTime timePoint; }
}; else
std::vector<Scrobble> scrobbles;
scrobbles.reserve(ids.size());
{ {
auto transaction {context.dbSession.createSharedTransaction()}; if (times.empty())
User::pointer user {User::getById(context.dbSession, context.userId)};
if (!user)
throw RequestedDataNotFoundError {};
Scrobble scrobble;
scrobble.listen.userId = context.userId;
for (std::size_t i {}; i < ids.size(); ++i)
{ {
const Id id {ids[i]}; Service<Scrobbling::IScrobbling>::get()->listenFinished({context.userId, ids.front().value});
const unsigned long time {times[i]}; }
else
const Track::pointer track {Track::getById(context.dbSession, id.value)}; {
if (!track) for (std::size_t i {}; i < ids.size(); ++i)
continue; {
const Database::IdType trackId {ids[i].value};
scrobble.listen.trackId = id.value; const unsigned long time {times[i]};
scrobble.timePoint.setTime_t(static_cast<std::time_t>(time / 1000)); Service<Scrobbling::IScrobbling>::get()->addListen({context.userId, trackId}, Wt::WDateTime::fromTime_t(static_cast<std::time_t>(time / 1000)));
}
scrobbles.emplace_back(scrobble);
} }
} }
for (const Scrobble& scrobble : scrobbles)
Service<Scrobbling::IScrobbling>::get()->addListen(scrobble.listen, scrobble.timePoint);
return Response::createOkResponse(context); return Response::createOkResponse(context);
} }