From cb5b2f7ad691b9c91248fc670c9adeafb5030daf Mon Sep 17 00:00:00 2001 From: Kevin Whitaker Date: Sun, 5 Feb 2017 18:20:03 -0500 Subject: [PATCH] Stop using pointers from DB as storage mechanism. Start storing copies of the object itself. Use commits after methods are done with transaction to hopefully help with DB issues. Don't use map because it requires too much about the key object I don't need. Add boolean that prevents vote end from being called constantly during it's 3 second window. --- src/GroovePlayer.cpp | 96 ++++++++++++++++++++++++-------------------- src/GroovePlayer.h | 12 +++--- src/WebInterface.cpp | 12 +++--- src/WebInterface.h | 12 +++--- 4 files changed, 71 insertions(+), 61 deletions(-) diff --git a/src/GroovePlayer.cpp b/src/GroovePlayer.cpp index 693b71d..f250c38 100644 --- a/src/GroovePlayer.cpp +++ b/src/GroovePlayer.cpp @@ -64,7 +64,7 @@ GroovePlayerMgr::GroovePlayerMgr (std::string dbFile) : sqliteConnection(dbFile) //} } -std::list GroovePlayerMgr::getNextVoteBatch(Wt::Dbo::Session* session) +std::list GroovePlayerMgr::getNextVoteBatch(Wt::Dbo::Session* session) { /** * This method will attempt to pick 3 tracks that will be up for selection next. @@ -78,7 +78,7 @@ std::list GroovePlayerMgr::getNextVoteBatch(Wt::Dbo::Session* * The third track will be replaced by a recent request item if one exists. */ - std::list selectedTracks; + std::list selectedTracks; Wt::Dbo::Transaction transaction(*session); //First make sure there are at least 3 tracks to suggest. @@ -90,33 +90,33 @@ std::list GroovePlayerMgr::getNextVoteBatch(Wt::Dbo::Session* } //Determine first track - int trackAlbumCount = session->query("select count(fingerprint) from tracks").where("album = ?").bind(getCurrentTrack(session)->trackAlbumName); - int trackArtistCount = session->query("select count(fingerprint) from tracks").where("artist = ?").bind(getCurrentTrack(session)->trackArtistName); + int trackAlbumCount = session->query("select count(fingerprint) from tracks").where("album = ?").bind(getCurrentTrack(session).trackAlbumName); + int trackArtistCount = session->query("select count(fingerprint) from tracks").where("artist = ?").bind(getCurrentTrack(session).trackArtistName); int computerSlightOfHand = rand() % 10 + 1; if(trackAlbumCount > 0 && computerSlightOfHand > 3) { //Pick item from album - Wt::Dbo::ptr eligibleTrack = session->find().where("album = ?").limit(1).offset(rand() % trackAlbumCount).bind(getCurrentTrack(session)->trackAlbumName); - selectedTracks.push_back(eligibleTrack.get()); + Wt::Dbo::ptr eligibleTrack = session->find().where("album = ?").limit(1).offset(rand() % trackAlbumCount).bind(getCurrentTrack(session).trackAlbumName); + selectedTracks.push_back(*eligibleTrack); } else if(trackArtistCount > 0) { //Pick item from artist - Wt::Dbo::ptr eligibleTrack = session->find().where("artist = ?").limit(1).offset(rand() % trackArtistCount).bind(getCurrentTrack(session)->trackArtistName); - selectedTracks.push_back(eligibleTrack.get()); + Wt::Dbo::ptr eligibleTrack = session->find().where("artist = ?").limit(1).offset(rand() % trackArtistCount).bind(getCurrentTrack(session).trackArtistName); + selectedTracks.push_back(*eligibleTrack); } //Determine second track - int trackGenreCount = session->query("select count(fingerprint) from tracks").where("genre = ?").bind(getCurrentTrack(session)->trackGenre); + int trackGenreCount = session->query("select count(fingerprint) from tracks").where("genre = ?").bind(getCurrentTrack(session).trackGenre); if(trackGenreCount > 0) { //Pick item from genre - Wt::Dbo::ptr eligibleTrack = session->find().where("genre = ?").limit(1).offset(rand() % trackGenreCount).bind(getCurrentTrack(session)->trackGenre); - selectedTracks.push_back(eligibleTrack.get()); + Wt::Dbo::ptr eligibleTrack = session->find().where("genre = ?").limit(1).offset(rand() % trackGenreCount).bind(getCurrentTrack(session).trackGenre); + selectedTracks.push_back(*eligibleTrack); } //Determine third track - int trackNotGenreCount = session->query("select count(fingerprint) from tracks").where("genre != ?").bind(getCurrentTrack(session)->trackGenre); + int trackNotGenreCount = session->query("select count(fingerprint) from tracks").where("genre != ?").bind(getCurrentTrack(session).trackGenre); if(requestQueue.size() > 0) { //There's a request. Pick one up front and put as third item. @@ -125,15 +125,17 @@ std::list GroovePlayerMgr::getNextVoteBatch(Wt::Dbo::Session* else if(trackNotGenreCount > 0) { //Pick from other genre - Wt::Dbo::ptr eligibleTrack = session->find().where("genre != ?").limit(1).offset(rand() % trackNotGenreCount).bind(getCurrentTrack(session)->trackGenre); - selectedTracks.push_back(eligibleTrack.get()); + Wt::Dbo::ptr eligibleTrack = session->find().where("genre != ?").limit(1).offset(rand() % trackNotGenreCount).bind(getCurrentTrack(session).trackGenre); + selectedTracks.push_back(*eligibleTrack); } else { //Pick randomly Wt::Dbo::ptr eligibleTrack = session->find().limit(1).offset(rand() % trackCount); - selectedTracks.push_back(eligibleTrack.get()); + selectedTracks.push_back(*eligibleTrack); } + transaction.commit(); + Wt::log("info") << "Next set of tracks to vote picked: 1=>[" << (*selectedTracks.begin()).trackName << "] 2=>[" << (*std::next(selectedTracks.begin(),1)).trackName << "] 3=>[" << (*std::next(selectedTracks.begin(),2)).trackName << "]"; return selectedTracks; } @@ -160,23 +162,24 @@ void GroovePlayerMgr::grooveEventLoop() //Pick initial track to bootstrap. int tracksPlayedBefore = sqlSession.query("select count(fingerprint) from tracks as t join actions on (actions.action = 3 or actions.action = 2) and actions.track_id = t.id"); - const AudioTrack* selectedTrack; + AudioTrack selectedTrack; if (tracksPlayedBefore > 0) { - selectedTrack = sqlSession.query>("select t from tracks as t join actions on (actions.action = 3 or actions.action = 2) and actions.track_id = t.id").limit(1).offset(rand() % tracksPlayedBefore).resultValue().get(); + selectedTrack = *sqlSession.query>("select t from tracks as t join actions on (actions.action = 3 or actions.action = 2) and actions.track_id = t.id").limit(1).offset(rand() % tracksPlayedBefore).resultValue(); } else { int trackCount = sqlSession.query("select count(fingerprint) from tracks"); - selectedTrack = sqlSession.find().limit(1).offset(rand() % trackCount).resultValue().get(); + selectedTrack = *sqlSession.find().limit(1).offset(rand() % trackCount).resultValue(); } + transaction.commit(); struct GroovePlaylist* playlist = groove_playlist_create(); currentPlaylist = playlist; struct GroovePlayer* player = groove_player_create(); if(!player) {return;} currentPlayer = player; - groove_playlist_insert(playlist, groove_file_open(selectedTrack->trackPath.c_str()),1.0,1.0,nullptr); + groove_playlist_insert(playlist, groove_file_open(selectedTrack.trackPath.c_str()),1.0,1.0,nullptr); //Now boostrap player with initial data groove_player_attach(player, playlist); @@ -185,7 +188,7 @@ void GroovePlayerMgr::grooveEventLoop() Wt::WApplication* app = Wt::WApplication::instance(); if(app != nullptr) { - static_cast(app)->songChangedFromServer(getCurrentTrack(&sqlSession).get()); + static_cast(app)->songChangedFromServer(getCurrentTrack(&sqlSession)); } } ); @@ -203,51 +206,52 @@ void GroovePlayerMgr::grooveEventLoop() { //Pick new batch of tracks to vote on and inform UI of update. currentVoteBatch = getNextVoteBatch(&sqlSession); - currentVoteStatus = std::map(); - std::for_each(currentVoteBatch.begin(),currentVoteBatch.end(),[&](const AudioTrack* item){ - currentVoteStatus.insert(std::pair(item,0)); - }); + currentVoteStatus = std::list>(); + for(auto track : currentVoteBatch) + { + currentVoteStatus.push_back(std::pair(track,0)); + } Wt::WServer::instance()->postAll([&]() { Wt::WApplication* app = Wt::WApplication::instance(); if(app != nullptr) { - static_cast(app)->songChangedFromServer(getCurrentTrack(&sqlSession).get()); + static_cast(app)->songChangedFromServer(getCurrentTrack(&sqlSession)); static_cast(app)->voteTracksUpdatedFromServer(currentVoteBatch); } } ); - Wt::log("info") << "Track playing changed to: " << getCurrentTrack(&sqlSession).get()->trackName; + Wt::log("info") << "Track playing changed to: " << getCurrentTrack(&sqlSession).trackName; } else if(event == VOTING_ENDED) { //Look at votes and add correct track to end of playlist. //If more than one track has highest votes, pick random. TODO:maybe base off of other play data instead. - std::list> trackWinners; - for(std::map::iterator track = currentVoteStatus.begin(); track != currentVoteStatus.end(); track++) + std::list> trackWinners; + for(auto track : currentVoteStatus) { //There nothing yet and there was at least a vote is an initial winner. - if(trackWinners.size() == 0 && track->second > 0) + if(trackWinners.size() == 0 && track.second > 0) { - trackWinners.push_back(std::pair(track->first,track->second)); + trackWinners.push_back(track); continue; } //If there is a winner. Check if higher. If so, clear the list and add this one. If equal, add to list. if(trackWinners.size() > 0) { - if(trackWinners.front().second < track->second) + if(trackWinners.front().second < track.second) { trackWinners.clear(); - trackWinners.push_back(std::pair(track->first, track->second)); + trackWinners.push_back(std::pair(track.first, track.second)); } - else if(trackWinners.front().second == track->second) + else if(trackWinners.front().second == track.second) { - trackWinners.push_back(std::pair(track->first, track->second)); + trackWinners.push_back(std::pair(track.first, track.second)); } } } - const AudioTrack* winner; + AudioTrack winner; //Randomly pick from winners(in case of tie), if there are any. if(trackWinners.size() > 0) { @@ -259,7 +263,7 @@ void GroovePlayerMgr::grooveEventLoop() if(requestQueue.size() > 0) { //If winning track was a request, now you can remove it from request queue. - if(requestQueue.front()->trackFingerprint == winner->trackFingerprint) + if(requestQueue.front().trackFingerprint == winner.trackFingerprint) { requestQueue.pop_front(); } @@ -296,12 +300,12 @@ void GroovePlayerMgr::grooveEventLoop() else { //Third track wins - winner = (*currentVoteBatch.begin()+=2); + winner = (*(currentVoteBatch.begin()++)++); } } } - groove_playlist_insert(currentPlaylist,groove_file_open(winner->trackPath.c_str()),1.0,1.0,nullptr); - Wt::log("info")<< "Voting has ended. Next track is: " << winner->trackName; + groove_playlist_insert(currentPlaylist,groove_file_open(winner.trackPath.c_str()),1.0,1.0,nullptr); + Wt::log("info")<< "Voting has ended. Next track is: " << winner.trackName; } else if(event == VOTE_CAST) { @@ -350,8 +354,9 @@ GroovePlayerMgr::PlayerEvents GroovePlayerMgr::getNextPlayerEvent(Wt::Dbo::Sessi { double timeIntoTrack; groove_player_position(currentPlayer,nullptr,&timeIntoTrack); - if(getCurrentTrack(session).get() != nullptr && getCurrentTrack(session)->trackLengthSeconds-timeIntoTrack < 3) + if(!voteEndedButNotNextTrackYet && getCurrentTrack(session).trackName != std::string() && getCurrentTrack(session).trackLengthSeconds-timeIntoTrack < 3) { + voteEndedButNotNextTrackYet = true; return VOTING_ENDED; } GroovePlayerEvent event; @@ -359,6 +364,7 @@ GroovePlayerMgr::PlayerEvents GroovePlayerMgr::getNextPlayerEvent(Wt::Dbo::Sessi { if(event.type == GROOVE_EVENT_NOWPLAYING) { + voteEndedButNotNextTrackYet = false; return GROOVE_NOWPLAYING; } } @@ -371,17 +377,19 @@ GroovePlayerMgr::PlayerEvents GroovePlayerMgr::getNextPlayerEvent(Wt::Dbo::Sessi return NOTHING; } -Wt::Dbo::ptr GroovePlayerMgr::getCurrentTrack(Wt::Dbo::Session* session) +AudioTrack GroovePlayerMgr::getCurrentTrack(Wt::Dbo::Session* session) { Wt::Dbo::Transaction transaction(*session); GroovePlaylistItem* currentItem; groove_player_position(this->currentPlayer,¤tItem,nullptr); if(currentItem != nullptr) { - Wt::Dbo::ptr track = session->find().where("path = ?").bind(currentItem->file->filename); + AudioTrack track = *session->find().where("path = ?").bind(currentItem->file->filename).resultValue(); + transaction.commit(); return track; } - return Wt::Dbo::ptr(); + transaction.commit(); + return AudioTrack(); } @@ -436,6 +444,7 @@ bool GroovePlayerMgr::addFileToTrackDBIfTagged(Wt::Dbo::Session* session, std::f newTrack->trackFingerprint = fingerprint; newTrack->trackPath = file.string(); session->add(newTrack); + transaction.commit(); groove_file_close(gfile); return true; } @@ -453,6 +462,7 @@ void GroovePlayerMgr::removeOrphanedTracks(Wt::Dbo::Session* session) item.remove(); } } + transaction.commit(); } diff --git a/src/GroovePlayer.h b/src/GroovePlayer.h index e41f86e..5ee15d0 100644 --- a/src/GroovePlayer.h +++ b/src/GroovePlayer.h @@ -24,7 +24,6 @@ #include #include #include -#include #include #include "db/User.h" #include "db/AudioTrack.h" @@ -48,8 +47,9 @@ public: struct GroovePlaylist* currentPlaylist; struct GroovePlayer* currentPlayer; - std::list currentVoteBatch; - std::map currentVoteStatus; + std::list currentVoteBatch; + std::list> currentVoteStatus; + bool voteEndedButNotNextTrackYet = false; private: enum PlayerEvents {NOTHING, GROOVE_NOWPLAYING, VOTING_ENDED, VOTE_CAST, PLAYING_PAUSED, PLAYING_RESUMED, SKIP_REQUESTED, SKIP_VOTE_CAST, SKIP_VOTING_ENDED, ADMIN_FORCE_SKIP}; @@ -59,19 +59,19 @@ private: bool continueEventLoop = true; bool finishedLaunchScan = false; - std::list requestQueue; + std::list requestQueue; std::list lastInternalEvents; std::thread* grooveEvents; void grooveEventLoop(); - std::list getNextVoteBatch(Wt::Dbo::Session* session); + std::list getNextVoteBatch(Wt::Dbo::Session* session); std::thread* grooveAudioScanner; void grooveAudioScannerLoop(); PlayerEvents getNextPlayerEvent(Wt::Dbo::Session* session); bool addFileToTrackDBIfTagged(Wt::Dbo::Session* session, std::filesystem::path file); void removeOrphanedTracks(Wt::Dbo::Session* session); - Wt::Dbo::ptr getCurrentTrack(Wt::Dbo::Session* session); + AudioTrack getCurrentTrack(Wt::Dbo::Session* session); }; diff --git a/src/WebInterface.cpp b/src/WebInterface.cpp index 31904ce..d62a3f0 100644 --- a/src/WebInterface.cpp +++ b/src/WebInterface.cpp @@ -57,31 +57,31 @@ void WebInterface::loginCompleted() //TODO: request current player state. } -void WebInterface::playPauseActionFromServer(User* userPausing) +void WebInterface::playPauseActionFromServer(User userPausing) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"play"); triggerUpdate(); } -void WebInterface::songChangedFromServer(const AudioTrack* nextTrack) +void WebInterface::songChangedFromServer(AudioTrack nextTrack) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"change"); triggerUpdate(); } -void WebInterface::skipVotedFromServer(User* userRequestingToSkipCurrentTrack) +void WebInterface::skipVotedFromServer(User userRequestingToSkipCurrentTrack) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"skip"); triggerUpdate(); } -void WebInterface::voteUpdateFromServer(User* userVoting, bool forSkip) +void WebInterface::voteUpdateFromServer(User userVoting, bool forSkip) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"vote"); triggerUpdate(); } -void WebInterface::voteNextSongFromServer(User* userVoting, const AudioTrack* trackVoted) +void WebInterface::voteNextSongFromServer(User userVoting, AudioTrack trackVoted) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"nextvote"); triggerUpdate(); @@ -93,7 +93,7 @@ void WebInterface::voteNextPollClosedFromServer() triggerUpdate(); } -void WebInterface::voteTracksUpdatedFromServer(std::list voteableTracks) +void WebInterface::voteTracksUpdatedFromServer(std::list voteableTracks) { priv_int->playerUI->tempText->setText(priv_int->playerUI->tempText->text()+"votechanged"); triggerUpdate(); diff --git a/src/WebInterface.h b/src/WebInterface.h index e9f514c..080f387 100644 --- a/src/WebInterface.h +++ b/src/WebInterface.h @@ -31,12 +31,12 @@ public: WebInterface(const Wt::WEnvironment& env); ~WebInterface(); void loginCompleted(); - void playPauseActionFromServer(User* userPausing); - void songChangedFromServer(const AudioTrack* nextTrack); - void voteTracksUpdatedFromServer(std::list voteableTracks); - void skipVotedFromServer(User* userRequestingToSkipCurrentTrack); - void voteUpdateFromServer(User* userVoting, bool forSkip); - void voteNextSongFromServer(User* userVoting, const AudioTrack* trackVoted); + void playPauseActionFromServer(User userPausing); + void songChangedFromServer(AudioTrack nextTrack); + void voteTracksUpdatedFromServer(std::list voteableTracks); + void skipVotedFromServer(User userRequestingToSkipCurrentTrack); + void voteUpdateFromServer(User userVoting, bool forSkip); + void voteNextSongFromServer(User userVoting, AudioTrack trackVoted); void voteNextPollClosedFromServer(); private: struct internal; -- GitLab