/* Vimpc Copyright (C) 2010 - 2013 Nathan Sweetman This program 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. This program 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 this program. If not, see . mpdclient.cpp - provides interaction with the music player daemon */ #include "clientstate.hpp" #include "mode/mode.hpp" #include "mpdclient.hpp" #include "assert.hpp" #include "buffers.hpp" #include "events.hpp" #include "screen.hpp" #include "settings.hpp" #include "vimpc.hpp" using namespace Mpc; // Mpc::Client Implementation ClientState::ClientState(Main::Vimpc * vimpc, Main::Settings & settings, Ui::Screen & screen) : vimpc_ (vimpc), settings_ (settings), screen_ (screen), connected_ (false), hostname_ (""), port_ (0), timeSinceUpdate_ (0), timeSinceSong_ (0), volume_ (-1), mute_ (false), updating_ (false), random_ (false), repeat_ (false), single_ (false), consume_ (false), crossfade_ (false), running_ (true), newSong_ (false), scrollingStatus_ (false), crossfadeTime_ (0), elapsed_ (0), titlePos_ (0), waitTime_ (150), currentSong_ (NULL), currentSongId_ (-1), totalNumberOfSongs_ (0), currentState_ ("Disconnected"), lastTitleStr_ ("") { Main::Vimpc::EventHandler(Event::Connected, [this] (EventData const & Data) { this->connected_ = true; DisplaySongInformation(); }); Main::Vimpc::EventHandler(Event::Disconnected, [this] (EventData const & Data) { this->connected_ = false; this->volume_ = -1; this->mute_ = false; this->updating_ = false; this->random_ = false; this->repeat_ = false; this->single_ = false; this->consume_ = false; this->crossfade_ = false; this->crossfadeTime_ = 0; this->currentSongId_ = -1; this->currentSongURI_ = ""; this->totalNumberOfSongs_ = 0; if (currentSong_ != NULL) { mpd_song_free(currentSong_); currentSong_ = NULL; } DisplaySongInformation(); EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::ClearDatabase, [this] (EventData const & Data) { DisplaySongInformation(); }); Main::Vimpc::EventHandler(Event::DisplaySongInfo, [this] (EventData const & Data) { DisplaySongInformation(); }); Main::Vimpc::EventHandler(Event::ChangeHost, [this] (EventData const & Data) { this->hostname_ = Data.hostname; this->port_ = Data.port; }); Main::Vimpc::EventHandler(Event::CurrentSongId, [this] (EventData const & Data) { this->currentSongId_ = Data.id; DisplaySongInformation(); Main::Vimpc::CreateEvent(Event::Repaint, Data); }); Main::Vimpc::EventHandler(Event::Elapsed, [this] (EventData const & Data) { this->elapsed_ = Data.value; DisplaySongInformation(); }); Main::Vimpc::EventHandler(Event::CurrentSong, [this] (EventData const & Data) { if (currentSong_ != NULL) { mpd_song_free(currentSong_); currentSong_ = NULL; } currentSong_ = Data.currentSong; currentSongURI_ = (currentSong_ != NULL) ? mpd_song_get_uri(currentSong_) : ""; DisplaySongInformation(); Main::Vimpc::CreateEvent(Event::Repaint, Data); }); Main::Vimpc::EventHandler(Event::Random, [this] (EventData const & Data) { this->random_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Consume, [this] (EventData const & Data) { this->consume_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Repeat, [this] (EventData const & Data) { this->repeat_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Single, [this] (EventData const & Data) { this->single_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Mute, [this] (EventData const & Data) { this->mute_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Crossfade, [this] (EventData const & Data) { this->crossfade_ = Data.state; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::CrossfadeTime, [this] (EventData const & Data) { this->crossfadeTime_ = Data.value; }); Main::Vimpc::EventHandler(Event::TotalSongCount, [this] (EventData const & Data) { this->totalNumberOfSongs_ = Data.count; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Update, [this] (EventData const & Data) { this->updating_ = true; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::UpdateComplete, [this] (EventData const & Data) { this->updating_ = false; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::Volume, [this] (EventData const & Data) { this->volume_ = Data.value; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); Main::Vimpc::EventHandler(Event::CurrentState, [this] (EventData const & Data) { this->currentState_ = Data.clientstate; EventData EData; Main::Vimpc::CreateEvent(Event::StatusUpdate, EData); }); updateThread_ = std::thread([this]() { while (this->running_) { std::this_thread::sleep_for(std::chrono::milliseconds(this->waitTime_)); if (this->newSong_) { this->titlePos_ = 0; if (this->scrollingStatus_ == true) { this->waitTime_ = 2500; } this->newSong_ = false; } else if (this->CurrentState() != "Stopped") { if (this->scrollingStatus_ == true) { this->titlePos_++; EventData EData; Main::Vimpc::CreateEvent(Event::DisplaySongInfo, EData); } this->waitTime_ = 150; } else { this->titlePos_ = 0; this->waitTime_ = 150; } } }); } ClientState::~ClientState() { running_ = false; updateThread_.join(); } std::string ClientState::Hostname() { return hostname_; } uint16_t ClientState::Port() { return port_; } bool ClientState::Connected() const { return connected_; } bool ClientState::IsSocketFile() const { return ((hostname_.length() > 1) && (hostname_[0] == '/')); } bool ClientState::Random() const { return random_; } bool ClientState::Single() const { return single_; } bool ClientState::Consume() const { return consume_; } bool ClientState::Repeat() const { return repeat_; } int32_t ClientState::Crossfade() const { if (crossfade_ == true) { return crossfadeTime_; } return 0; } int32_t ClientState::Volume() const { return volume_; } bool ClientState::Mute() const { return mute_; } bool ClientState::IsUpdating() const { return updating_; } std::string ClientState::CurrentState() const { return currentState_; } std::string ClientState::GetCurrentSongURI() const { return currentSongURI_; } int32_t ClientState::GetCurrentSongPos() { if (currentState_ != "Stopped") { return currentSongId_; } else { return -1; } } uint32_t ClientState::TotalNumberOfSongs() { return totalNumberOfSongs_; } void ClientState::DisplaySongInformation() { static char durationStr[128]; static char titleStr[512]; static char statusStr[1536]; screen_.HideCursor(); if ((Connected() == true) && (CurrentState() != "Stopped")) { if (currentSong_ != NULL) { char const * const cartist = mpd_song_get_tag(currentSong_, MPD_TAG_ARTIST, 0); char const * const ctitle = mpd_song_get_tag(currentSong_, MPD_TAG_TITLE, 0); char const * const curi = mpd_song_get_uri(currentSong_); uint32_t const duration = mpd_song_get_duration(currentSong_); uint32_t const elapsed = elapsed_; uint32_t const remain = (duration > elapsed) ? duration - elapsed : 0; std::string const artist = (cartist != NULL) ? cartist : "Unknown"; std::string const title = (ctitle != NULL) ? ctitle : ""; std::string const uri = (curi != NULL) ? curi : ""; if (title != "") { snprintf(titleStr, 512, "%s - %s", artist.c_str(), title.c_str()); } else { snprintf(titleStr, 512, "%s", uri.c_str()); } if (settings_.Get(Setting::TimeRemaining) == false) { snprintf(durationStr, 127, " [%d:%.2d/%d:%.2d]", SecondsToMinutes(elapsed), RemainingSeconds(elapsed), SecondsToMinutes(duration), RemainingSeconds(duration)); } else { snprintf(durationStr, 127, " [-%d:%.2d/%d:%.2d]", SecondsToMinutes(remain), RemainingSeconds(remain), SecondsToMinutes(duration), RemainingSeconds(duration)); } if ((strlen(titleStr) >= screen_.MaxColumns() - 7 - strlen(durationStr)) && (settings_.Get(Setting::ScrollStatus) == true)) { snprintf(statusStr, 1536, "%s | %s", titleStr, titleStr); scrollingStatus_ = true; } else { titlePos_ = 0; scrollingStatus_ = false; snprintf(statusStr, 512, "%s", titleStr); } std::string const currentTitle = titleStr; if (lastTitleStr_ != currentTitle) { if (scrollingStatus_ == true) { newSong_ = true; } titlePos_ = 0; } lastTitleStr_ = currentTitle; screen_.SetStatusLine("[%5u] %s", GetCurrentSongPos() + 1, &statusStr[titlePos_]); screen_.MoveSetStatus(screen_.MaxColumns() - strlen(durationStr), "%s", durationStr); screen_.SetProgress(static_cast(elapsed) / duration); if (settings_.Get(Setting::ScrollStatus) == true) { titlePos_ %= (strlen(titleStr) + strlen(" | ")); } } else { screen_.SetProgress(0); } } else { screen_.SetStatusLine("%s",""); screen_.SetProgress(0); } if (settings_.Get(Setting::ProgressBar) == true) { screen_.UpdateProgressWindow(); } if (screen_.PagerIsVisible() == false) { vimpc_->CurrentMode().Refresh(); } } long ClientState::TimeSinceUpdate() { return timeSinceUpdate_; } /* vim: set sw=3 ts=3: */