From eff4abe65a2d647a61303606b5d3b4b5c10dcee7 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 7 Apr 2019 21:59:53 -0700 Subject: [PATCH] Initial lyrics lookup support using auddio. Need a real API key though... --- CHANGELOG.txt | 2 +- src/core/CMakeLists.txt | 1 + src/core/support/Auddio.cpp | 96 +++++++++++ src/core/support/Auddio.h | 44 +++++ src/core/support/Common.cpp | 22 +++ src/core/support/Common.h | 3 + src/core/support/LastFm.cpp | 6 +- src/musikcube/CMakeLists.txt | 1 + src/musikcube/app/layout/ConsoleLayout.cpp | 34 ++++ src/musikcube/app/layout/ConsoleLayout.h | 34 ++++ src/musikcube/app/layout/LyricsLayout.cpp | 182 +++++++++++++++++++++ src/musikcube/app/layout/LyricsLayout.h | 45 +++++ src/musikcube/app/layout/MainLayout.cpp | 9 + src/musikcube/app/layout/MainLayout.h | 1 + src/musikcube/app/util/Hotkeys.cpp | 2 + src/musikcube/app/util/Hotkeys.h | 3 +- src/musikcube/app/util/Messages.h | 9 +- src/musikcube/data/locales/en_US.json | 6 + 18 files changed, 491 insertions(+), 9 deletions(-) create mode 100644 src/core/support/Auddio.cpp create mode 100644 src/core/support/Auddio.h create mode 100644 src/musikcube/app/layout/LyricsLayout.cpp create mode 100644 src/musikcube/app/layout/LyricsLayout.h diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 6c58911a4..fbfaee1f5 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -205,7 +205,7 @@ musikdroid: * updated to compile against Android Studio 3.1.4 server: -* fixed a crash while querying play queue tracks that have been removed from +* fixed a crash while querying play queue tracks that have b`een removed from the library. sdk: diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 200150970..f937cb33c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,6 +46,7 @@ set(CORE_SOURCES ./plugin/Plugins.cpp ./runtime/Message.cpp ./runtime/MessageQueue.cpp + ./support/Auddio.cpp ./support/Duration.cpp ./support/Common.cpp ./support/LastFm.cpp diff --git a/src/core/support/Auddio.cpp b/src/core/support/Auddio.cpp new file mode 100644 index 000000000..650a76a3c --- /dev/null +++ b/src/core/support/Auddio.cpp @@ -0,0 +1,96 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.hpp" +#include "Auddio.h" +#include "Common.h" +#include +#include +#include +#include + +/* https://api.audd.io/findLyrics/?q=the%20beatles%20sgt%20pepper%20reprise */ + +using namespace musik::core; + +using AuddioClient = musik::core::sdk::HttpClient; +const std::string apiToken = ""; + +static std::shared_ptr createClient() { + return AuddioClient::Create(std::stringstream()); +} + +static std::string encode(std::string value) { + static CURL* curl = curl_easy_init(); + if (curl && value.c_str()) { + char* encoded = curl_easy_escape(curl, value.c_str(), value.size()); + if (encoded) { + value = encoded; + curl_free(encoded); + } + } + return value; +} + +namespace musik { namespace core { namespace auddio { + void FindLyrics(TrackPtr track, LyricsCallback callback) { + std::string artist = encode(track->GetString("artist")); + std::string title = encode(track->GetString("title")); + std::string url = + "https://api.audd.io/findLyrics/?q=" + + artist + "%20" + title + + "&api_token=" + apiToken; + + auto client = createClient(); + client->Url(url) + .Mode(AuddioClient::Thread::Background) + .Run([track, callback](AuddioClient* client, int statusCode, CURLcode curlCode) { + std::string lyrics; + if (statusCode == 200) { + try { + std::string response = client->Stream().str(); + auto json = nlohmann::json::parse(response); + if (json.value("status", "") == "success") { + lyrics = json["result"][0]["lyrics"]; + } + } + catch (...) { + /* not much we can do... */ + } + } + + callback(track, lyrics); + }); + } +} } } \ No newline at end of file diff --git a/src/core/support/Auddio.h b/src/core/support/Auddio.h new file mode 100644 index 000000000..cc2ca2dc3 --- /dev/null +++ b/src/core/support/Auddio.h @@ -0,0 +1,44 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +namespace musik { namespace core { namespace auddio { + using LyricsCallback = std::function; + + void FindLyrics(musik::core::TrackPtr track, LyricsCallback callback); +} } } \ No newline at end of file diff --git a/src/core/support/Common.cpp b/src/core/support/Common.cpp index 7b82ccafd..064dae6bc 100644 --- a/src/core/support/Common.cpp +++ b/src/core/support/Common.cpp @@ -309,6 +309,28 @@ namespace musik { namespace core { } } + std::string Trim(const std::string& str) { + std::string s(str); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), + std::not1(std::ptr_fun(std::isspace)))); + s.erase(std::find_if(s.rbegin(), s.rend(), + std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + return s; + } + + std::vector Split( + const std::string& in, const std::string& delim) + { + std::vector result; + size_t last = 0, next = 0; + while ((next = in.find(delim, last)) != std::string::npos) { + result.push_back(std::move(Trim(in.substr(last, next - last)))); + last = next + 1; + } + result.push_back(std::move(Trim(in.substr(last)))); + return result; + } + void OpenFile(const std::string& path) { #ifdef WIN32 ShellExecuteA(nullptr, nullptr, path.c_str(), nullptr, nullptr, SW_SHOWNORMAL); diff --git a/src/core/support/Common.h b/src/core/support/Common.h index b551faf22..1034bfb6a 100644 --- a/src/core/support/Common.h +++ b/src/core/support/Common.h @@ -35,6 +35,7 @@ #pragma once #include +#include #include namespace musik { namespace core { @@ -50,6 +51,8 @@ namespace musik { namespace core { int64_t Checksum(char *data,unsigned int bytes); size_t CopyString(const std::string& src, char* dst, size_t size); void ReplaceAll(std::string& input, const std::string& find, const std::string& replace); + std::vector Split(const std::string& in, const std::string& delim); + std::string Trim(const std::string& str); bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate = false); /* file-migration stuff. */ diff --git a/src/core/support/LastFm.cpp b/src/core/support/LastFm.cpp index b9913bb92..7d1e441b1 100644 --- a/src/core/support/LastFm.cpp +++ b/src/core/support/LastFm.cpp @@ -66,9 +66,9 @@ static std::shared_ptr createClient() { static void validate(musik::core::lastfm::Session& session) { session.valid = - session.sessionId.size() && - session.username.size() && - session.token.size(); + session.sessionId.size() && + session.username.size() && + session.token.size(); } static std::string encode(std::string value) { diff --git a/src/musikcube/CMakeLists.txt b/src/musikcube/CMakeLists.txt index 0f34faf58..86cefd245 100644 --- a/src/musikcube/CMakeLists.txt +++ b/src/musikcube/CMakeLists.txt @@ -7,6 +7,7 @@ set (CUBE_SRCS ./app/layout/HotkeysLayout.cpp ./app/layout/SettingsLayout.cpp ./app/layout/LibraryLayout.cpp + ./app/layout/LyricsLayout.cpp ./app/layout/MainLayout.cpp ./app/layout/NowPlayingLayout.cpp ./app/layout/CategorySearchLayout.cpp diff --git a/src/musikcube/app/layout/ConsoleLayout.cpp b/src/musikcube/app/layout/ConsoleLayout.cpp index 272531ef5..bc3fa8d1f 100755 --- a/src/musikcube/app/layout/ConsoleLayout.cpp +++ b/src/musikcube/app/layout/ConsoleLayout.cpp @@ -1,3 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + #include #include #include diff --git a/src/musikcube/app/layout/ConsoleLayout.h b/src/musikcube/app/layout/ConsoleLayout.h index b7e176f3d..de1a6ed56 100755 --- a/src/musikcube/app/layout/ConsoleLayout.h +++ b/src/musikcube/app/layout/ConsoleLayout.h @@ -1,3 +1,37 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + #pragma once #include diff --git a/src/musikcube/app/layout/LyricsLayout.cpp b/src/musikcube/app/layout/LyricsLayout.cpp new file mode 100644 index 000000000..7410d8c1b --- /dev/null +++ b/src/musikcube/app/layout/LyricsLayout.cpp @@ -0,0 +1,182 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2004-2019 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace musik::cube; +using namespace musik::core; +using namespace musik::core::runtime; +using namespace musik::core::sdk; +using namespace cursespp; + +LyricsLayout::LyricsLayout(musik::core::audio::PlaybackService& playback) +: LayoutBase() +, currentTrackId(-1LL) +, playback(playback) { + this->playback.TrackChanged.connect(this, &LyricsLayout::OnTrackChanged); + + this->adapter = std::make_shared(); + this->adapter->SetSelectable(true); + + this->listView = std::make_shared(this->adapter); + this->AddWindow(this->listView); + this->listView->SetFocusOrder(0); + + this->infoText = std::make_shared("", text::AlignCenter); + this->AddWindow(this->infoText); + + this->LoadLyricsForCurrentTrack(); +} + +void LyricsLayout::OnLayout() { + LayoutBase::OnLayout(); + int cx = this->GetContentWidth(); + int cy = this->GetContentHeight(); + this->listView->MoveAndResize(0, 0, cx, cy); + this->infoText->MoveAndResize(1, cy / 2, cx - 2, 1); +} + +void LyricsLayout::OnTrackChanged(size_t index, TrackPtr track) { + this->LoadLyricsForCurrentTrack(); +} + +bool LyricsLayout::KeyPress(const std::string& kn) { + return LayoutBase::KeyPress(kn); +} + +void LyricsLayout::LoadLyricsForCurrentTrack() { + auto track = playback.GetPlaying(); + if (track && track->GetId() != this->currentTrackId) { + this->currentTrackId = track->GetId(); + this->SetState(State::Loading); + auddio::FindLyrics(track, [this](TrackPtr track, std::string& lyrics) { + if (this->currentTrackId == track->GetId()) { + if (lyrics.size()) { + this->UpdateAdapter(lyrics); + this->listView->SetFrameTitle(u8fmt( + _TSTR("lyrics_list_title"), + track->GetString("title").c_str())); + } + else { + this->SetState(State::Failed); + } + } + }); + } + else if (!track) { + this->currentTrackId = -1LL; + this->SetState(State::NotPlaying); + } +} + +void LyricsLayout::UpdateAdapter(const std::string& lyrics) { + std::string fixed = lyrics; + ReplaceAll(fixed, "\r\n", "\n"); + ReplaceAll(fixed, "\r", "\n"); + auto items = Split(fixed, "\n"); + this->adapter->Clear(); + for (auto& text : items) { + this->adapter->AddEntry(std::make_shared(text)); + } + this->SetState(State::Loaded); +} + +void LyricsLayout::SetState(State state) { + switch (state) { + case State::NotPlaying: { + this->listView->Hide(); + this->infoText->Show(); + this->infoText->SetText(_TSTR("lyrics_not_playing")); + this->currentTrackId = -1LL; + } + break; + case State::Loading: { + this->listView->Hide(); + this->infoText->Show(); + this->infoText->SetText(_TSTR("lyrics_loading")); + } + break; + case State::Loaded: { + this->infoText->Hide(); + this->listView->Show(); + if (this->IsVisible()) { + this->listView->Focus(); + } + } + break; + case State::Failed: { + this->listView->Hide(); + this->infoText->Show(); + this->infoText->SetText(_TSTR("lyrics_lookup_failed")); + this->currentTrackId = -1LL; + } + break; + } +} + +void LyricsLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) { + if (shortcuts) { + shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateLyrics), _TSTR("shortcuts_lyrics")); + shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateLibrary), _TSTR("shortcuts_library")); + shortcuts->AddShortcut(Hotkeys::Get(Hotkeys::NavigateSettings), _TSTR("shortcuts_settings")); + shortcuts->AddShortcut(App::Instance().GetQuitKey(), _TSTR("shortcuts_quit")); + + shortcuts->SetChangedCallback([this](std::string key) { + if (Hotkeys::Is(Hotkeys::NavigateSettings, key)) { + this->Broadcast(message::JumpToSettings); + } + if (Hotkeys::Is(Hotkeys::NavigateLibrary, key)) { + this->Broadcast(message::JumpToLibrary); + } + else if (key == App::Instance().GetQuitKey()) { + App::Instance().Quit(); + } + else { + this->KeyPress(key); + } + }); + + shortcuts->SetActive(Hotkeys::Get(Hotkeys::NavigateLyrics)); + } +} diff --git a/src/musikcube/app/layout/LyricsLayout.h b/src/musikcube/app/layout/LyricsLayout.h new file mode 100644 index 000000000..d0c314a99 --- /dev/null +++ b/src/musikcube/app/layout/LyricsLayout.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace musik { namespace cube { + + class LyricsLayout: + public cursespp::LayoutBase, + public cursespp::ITopLevelLayout, + public sigslot::has_slots<> + { + public: + LyricsLayout(musik::core::audio::PlaybackService& playback); + + virtual void OnLayout() override; + virtual void SetShortcutsWindow(cursespp::ShortcutsWindow* w) override; + virtual bool KeyPress(const std::string& kn) override; + + private: + enum class State: int { NotPlaying, Loading, Loaded, Failed }; + + void OnAdapterChanged(cursespp::SimpleScrollAdapter* adapter); + void OnSelectionChanged(cursespp::ListWindow* window, size_t index, size_t prev); + void OnPlaybackEvent(int playbackEvent); + void OnTrackChanged(size_t index, musik::core::TrackPtr track); + + void SetState(State state); + void LoadLyricsForCurrentTrack(); + void UpdateAdapter(const std::string& lyrics); + + State state { State::NotPlaying }; + musik::core::audio::PlaybackService& playback; + std::shared_ptr adapter; + std::shared_ptr listView; + std::shared_ptr infoText; + cursespp::ShortcutsWindow* shortcuts; + int64_t currentTrackId; + }; + +} } \ No newline at end of file diff --git a/src/musikcube/app/layout/MainLayout.cpp b/src/musikcube/app/layout/MainLayout.cpp index 72bcd5b7f..4dcaaf81c 100755 --- a/src/musikcube/app/layout/MainLayout.cpp +++ b/src/musikcube/app/layout/MainLayout.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -97,6 +98,7 @@ MainLayout::MainLayout( library->Indexer()->Progress.connect(this, &MainLayout::OnIndexerProgress); this->libraryLayout = std::make_shared(playback, library); + this->lyricsLayout = std::make_shared(playback); this->consoleLayout = std::make_shared(logger); this->settingsLayout = std::make_shared(app, library, playback); this->hotkeysLayout = std::make_shared(); @@ -144,6 +146,10 @@ bool MainLayout::KeyPress(const std::string& key) { this->SetLayout(consoleLayout); return true; } + else if (Hotkeys::Is(Hotkeys::NavigateLyrics, key)) { + this->Broadcast(message::JumpToLyrics); + return true; + } else if (Hotkeys::Is(Hotkeys::NavigateHotkeys, key)) { this->SetLayout(hotkeysLayout); return true; @@ -181,6 +187,9 @@ void MainLayout::ProcessMessage(musik::core::runtime::IMessage &message) { else if (type == message::JumpToSettings) { this->SetLayout(settingsLayout); } + else if (type == message::JumpToLyrics) { + this->SetLayout(lyricsLayout); + } else if (type == message::JumpToHotkeys) { this->SetLayout(hotkeysLayout); } diff --git a/src/musikcube/app/layout/MainLayout.h b/src/musikcube/app/layout/MainLayout.h index 7c283b1af..b87acfb4f 100755 --- a/src/musikcube/app/layout/MainLayout.h +++ b/src/musikcube/app/layout/MainLayout.h @@ -83,6 +83,7 @@ namespace musik { std::shared_ptr libraryLayout; std::shared_ptr settingsLayout; std::shared_ptr hotkeysLayout; + std::shared_ptr lyricsLayout; musik::core::ILibraryPtr library; bool shortcutsFocused; int syncUpdateCount; diff --git a/src/musikcube/app/util/Hotkeys.cpp b/src/musikcube/app/util/Hotkeys.cpp index 2995e7412..f2c208315 100755 --- a/src/musikcube/app/util/Hotkeys.cpp +++ b/src/musikcube/app/util/Hotkeys.cpp @@ -80,6 +80,7 @@ static std::unordered_map NAME_TO_ID = { { "navigate_library_play_queue", Id::NavigateLibraryPlayQueue }, { "navigate_settings", Id::NavigateSettings }, { "navigate_console", Id::NavigateConsole }, + { "navigate_lyrics", Id::NavigateLyrics }, { "navigate_hotkeys", Id::NavigateHotkeys}, { "navigate_jump_to_playing", Id::NavigateJumpToPlaying }, @@ -151,6 +152,7 @@ static std::unordered_map ID_TO_DEFAULT = { { Id::NavigateLibraryPlayQueue, "n" }, { Id::NavigateSettings, "s" }, { Id::NavigateConsole, "`" }, + { Id::NavigateLyrics, "^L" }, { Id::NavigateHotkeys, "?" }, { Id::NavigateJumpToPlaying, "x" }, diff --git a/src/musikcube/app/util/Hotkeys.h b/src/musikcube/app/util/Hotkeys.h index 02a9c64bc..16066d723 100755 --- a/src/musikcube/app/util/Hotkeys.h +++ b/src/musikcube/app/util/Hotkeys.h @@ -66,10 +66,11 @@ namespace musik { NavigateLibraryFilter, NavigateLibraryTracks, NavigateLibraryPlayQueue, - NavigateSettings, NavigateConsole, + NavigateLyrics, NavigateHotkeys, NavigateJumpToPlaying, + NavigateSettings, /* views */ ViewRefresh, diff --git a/src/musikcube/app/util/Messages.h b/src/musikcube/app/util/Messages.h index 621e14724..5e69653aa 100644 --- a/src/musikcube/app/util/Messages.h +++ b/src/musikcube/app/util/Messages.h @@ -60,10 +60,11 @@ namespace musik { static const int JumpToConsole = First + 9; static const int JumpToLibrary = First + 10; static const int JumpToSettings = First + 11; - static const int JumpToHotkeys = First + 12; - static const int SetLastFmState = First + 13; - static const int UpdateEqualizer = First + 14; - static const int DebugLog = First + 15; + static const int JumpToLyrics = First + 12; + static const int JumpToHotkeys = First + 13; + static const int SetLastFmState = First + 14; + static const int UpdateEqualizer = First + 15; + static const int DebugLog = First + 16; } } } diff --git a/src/musikcube/data/locales/en_US.json b/src/musikcube/data/locales/en_US.json index f23951e31..51220a79b 100644 --- a/src/musikcube/data/locales/en_US.json +++ b/src/musikcube/data/locales/en_US.json @@ -174,6 +174,7 @@ "shortcuts_settings": "settings", "shortcuts_library": "library", + "shortcuts_lyrics": "lyrics", "shortcuts_console": "logs", "shortcuts_quit": "quit", "shortcuts_browse": "browse", @@ -203,6 +204,11 @@ "main_syncing_banner_start": "syncing metadata...", "main_syncing_banner": "syncing metadata (%d tracks processed)", + "lyrics_list_title": "lyrics for '%s'", + "lyrics_not_playing": "nothing is currently playing!", + "lyrics_loading": "looking up lyrics...", + "lyrics_lookup_failed": "lyrics lookup failed. press 'r' to retry.", + "update_check_dialog_title": "new version available!", "update_check_dialog_message": "musikcube version %s is now available for download. a changelog and binaries are available at:\n\n%s", "update_check_no_updates_title": "update check",