diff --git a/src/GroovePlayer.cpp b/src/GroovePlayer.cpp index 693b71dac613f64ea072ab6f29041421eebaa14a..f250c383069de2a75f3db3a2af427c88c6ae3ad1 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 e41f86e2d0ed702000fdc11e83a2b3f04d82c960..5ee15d0f7a18438e2365295529e26a9b5d6e5f81 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 31904ce0d198f5472bd1bf0c6b5fe9019dbfef54..d62a3f09189ecf6a91e25d3bd8b165674af691f8 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 e9f514c47669d15405e92ce66dec01971906583d..080f387f61da11dfda8324059fbb857436f0e927 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;