mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Initial lyrics lookup support using auddio. Need a real API key
though...
This commit is contained in:
parent
efb2ec300b
commit
eff4abe65a
@ -205,7 +205,7 @@ musikdroid:
|
|||||||
* updated to compile against Android Studio 3.1.4
|
* updated to compile against Android Studio 3.1.4
|
||||||
|
|
||||||
server:
|
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.
|
the library.
|
||||||
|
|
||||||
sdk:
|
sdk:
|
||||||
|
@ -46,6 +46,7 @@ set(CORE_SOURCES
|
|||||||
./plugin/Plugins.cpp
|
./plugin/Plugins.cpp
|
||||||
./runtime/Message.cpp
|
./runtime/Message.cpp
|
||||||
./runtime/MessageQueue.cpp
|
./runtime/MessageQueue.cpp
|
||||||
|
./support/Auddio.cpp
|
||||||
./support/Duration.cpp
|
./support/Duration.cpp
|
||||||
./support/Common.cpp
|
./support/Common.cpp
|
||||||
./support/LastFm.cpp
|
./support/LastFm.cpp
|
||||||
|
96
src/core/support/Auddio.cpp
Normal file
96
src/core/support/Auddio.cpp
Normal file
@ -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 <core/sdk/HttpClient.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <sstream>
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
|
/* https://api.audd.io/findLyrics/?q=the%20beatles%20sgt%20pepper%20reprise */
|
||||||
|
|
||||||
|
using namespace musik::core;
|
||||||
|
|
||||||
|
using AuddioClient = musik::core::sdk::HttpClient<std::stringstream>;
|
||||||
|
const std::string apiToken = "";
|
||||||
|
|
||||||
|
static std::shared_ptr<AuddioClient> 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} } }
|
44
src/core/support/Auddio.h
Normal file
44
src/core/support/Auddio.h
Normal file
@ -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 <functional>
|
||||||
|
#include <core/library/track/Track.h>
|
||||||
|
|
||||||
|
namespace musik { namespace core { namespace auddio {
|
||||||
|
using LyricsCallback = std::function<void(musik::core::TrackPtr track, std::string&)>;
|
||||||
|
|
||||||
|
void FindLyrics(musik::core::TrackPtr track, LyricsCallback callback);
|
||||||
|
} } }
|
@ -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<int, int>(std::isspace))));
|
||||||
|
s.erase(std::find_if(s.rbegin(), s.rend(),
|
||||||
|
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Split(
|
||||||
|
const std::string& in, const std::string& delim)
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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) {
|
void OpenFile(const std::string& path) {
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
ShellExecuteA(nullptr, nullptr, path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
ShellExecuteA(nullptr, nullptr, path.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
#include <core/config.h>
|
#include <core/config.h>
|
||||||
|
|
||||||
namespace musik { namespace core {
|
namespace musik { namespace core {
|
||||||
@ -50,6 +51,8 @@ namespace musik { namespace core {
|
|||||||
int64_t Checksum(char *data,unsigned int bytes);
|
int64_t Checksum(char *data,unsigned int bytes);
|
||||||
size_t CopyString(const std::string& src, char* dst, size_t size);
|
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);
|
void ReplaceAll(std::string& input, const std::string& find, const std::string& replace);
|
||||||
|
std::vector<std::string> 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);
|
bool FileToByteArray(const std::string& path, char** target, int& size, bool nullTerminate = false);
|
||||||
|
|
||||||
/* file-migration stuff. */
|
/* file-migration stuff. */
|
||||||
|
@ -66,9 +66,9 @@ static std::shared_ptr<LastFmClient> createClient() {
|
|||||||
|
|
||||||
static void validate(musik::core::lastfm::Session& session) {
|
static void validate(musik::core::lastfm::Session& session) {
|
||||||
session.valid =
|
session.valid =
|
||||||
session.sessionId.size() &&
|
session.sessionId.size() &&
|
||||||
session.username.size() &&
|
session.username.size() &&
|
||||||
session.token.size();
|
session.token.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string encode(std::string value) {
|
static std::string encode(std::string value) {
|
||||||
|
@ -7,6 +7,7 @@ set (CUBE_SRCS
|
|||||||
./app/layout/HotkeysLayout.cpp
|
./app/layout/HotkeysLayout.cpp
|
||||||
./app/layout/SettingsLayout.cpp
|
./app/layout/SettingsLayout.cpp
|
||||||
./app/layout/LibraryLayout.cpp
|
./app/layout/LibraryLayout.cpp
|
||||||
|
./app/layout/LyricsLayout.cpp
|
||||||
./app/layout/MainLayout.cpp
|
./app/layout/MainLayout.cpp
|
||||||
./app/layout/NowPlayingLayout.cpp
|
./app/layout/NowPlayingLayout.cpp
|
||||||
./app/layout/CategorySearchLayout.cpp
|
./app/layout/CategorySearchLayout.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 <stdafx.h>
|
#include <stdafx.h>
|
||||||
#include <app/layout/ConsoleLayout.h>
|
#include <app/layout/ConsoleLayout.h>
|
||||||
#include <core/i18n/Locale.h>
|
#include <core/i18n/Locale.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
|
#pragma once
|
||||||
|
|
||||||
#include <cursespp/LayoutBase.h>
|
#include <cursespp/LayoutBase.h>
|
||||||
|
182
src/musikcube/app/layout/LyricsLayout.cpp
Normal file
182
src/musikcube/app/layout/LyricsLayout.cpp
Normal file
@ -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 <stdafx.h>
|
||||||
|
#include <app/layout/LyricsLayout.h>
|
||||||
|
#include <core/i18n/Locale.h>
|
||||||
|
#include <core/support/Auddio.h>
|
||||||
|
#include <core/support/Common.h>
|
||||||
|
#include <cursespp/App.h>
|
||||||
|
#include <cursespp/Screen.h>
|
||||||
|
#include <cursespp/ToastOverlay.h>
|
||||||
|
#include <cursespp/SingleLineEntry.h>
|
||||||
|
#include <app/util/Hotkeys.h>
|
||||||
|
#include <app/util/Messages.h>
|
||||||
|
|
||||||
|
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<SimpleScrollAdapter>();
|
||||||
|
this->adapter->SetSelectable(true);
|
||||||
|
|
||||||
|
this->listView = std::make_shared<ListWindow>(this->adapter);
|
||||||
|
this->AddWindow(this->listView);
|
||||||
|
this->listView->SetFocusOrder(0);
|
||||||
|
|
||||||
|
this->infoText = std::make_shared<TextLabel>("", 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<SingleLineEntry>(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));
|
||||||
|
}
|
||||||
|
}
|
45
src/musikcube/app/layout/LyricsLayout.h
Normal file
45
src/musikcube/app/layout/LyricsLayout.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cursespp/LayoutBase.h>
|
||||||
|
#include <cursespp/TextLabel.h>
|
||||||
|
#include <cursespp/ListWindow.h>
|
||||||
|
#include <cursespp/ITopLevelLayout.h>
|
||||||
|
#include <cursespp/SimpleScrollAdapter.h>
|
||||||
|
#include <core/audio/PlaybackService.h>
|
||||||
|
|
||||||
|
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<cursespp::SimpleScrollAdapter> adapter;
|
||||||
|
std::shared_ptr<cursespp::ListWindow> listView;
|
||||||
|
std::shared_ptr<cursespp::TextLabel> infoText;
|
||||||
|
cursespp::ShortcutsWindow* shortcuts;
|
||||||
|
int64_t currentTrackId;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
@ -44,6 +44,7 @@
|
|||||||
#include <app/util/PreferenceKeys.h>
|
#include <app/util/PreferenceKeys.h>
|
||||||
#include <app/util/UpdateCheck.h>
|
#include <app/util/UpdateCheck.h>
|
||||||
#include <app/layout/ConsoleLayout.h>
|
#include <app/layout/ConsoleLayout.h>
|
||||||
|
#include <app/layout/LyricsLayout.h>
|
||||||
#include <app/layout/LibraryLayout.h>
|
#include <app/layout/LibraryLayout.h>
|
||||||
#include <app/layout/SettingsLayout.h>
|
#include <app/layout/SettingsLayout.h>
|
||||||
#include <app/layout/HotkeysLayout.h>
|
#include <app/layout/HotkeysLayout.h>
|
||||||
@ -97,6 +98,7 @@ MainLayout::MainLayout(
|
|||||||
library->Indexer()->Progress.connect(this, &MainLayout::OnIndexerProgress);
|
library->Indexer()->Progress.connect(this, &MainLayout::OnIndexerProgress);
|
||||||
|
|
||||||
this->libraryLayout = std::make_shared<LibraryLayout>(playback, library);
|
this->libraryLayout = std::make_shared<LibraryLayout>(playback, library);
|
||||||
|
this->lyricsLayout = std::make_shared<LyricsLayout>(playback);
|
||||||
this->consoleLayout = std::make_shared<ConsoleLayout>(logger);
|
this->consoleLayout = std::make_shared<ConsoleLayout>(logger);
|
||||||
this->settingsLayout = std::make_shared<SettingsLayout>(app, library, playback);
|
this->settingsLayout = std::make_shared<SettingsLayout>(app, library, playback);
|
||||||
this->hotkeysLayout = std::make_shared<HotkeysLayout>();
|
this->hotkeysLayout = std::make_shared<HotkeysLayout>();
|
||||||
@ -144,6 +146,10 @@ bool MainLayout::KeyPress(const std::string& key) {
|
|||||||
this->SetLayout(consoleLayout);
|
this->SetLayout(consoleLayout);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (Hotkeys::Is(Hotkeys::NavigateLyrics, key)) {
|
||||||
|
this->Broadcast(message::JumpToLyrics);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
else if (Hotkeys::Is(Hotkeys::NavigateHotkeys, key)) {
|
else if (Hotkeys::Is(Hotkeys::NavigateHotkeys, key)) {
|
||||||
this->SetLayout(hotkeysLayout);
|
this->SetLayout(hotkeysLayout);
|
||||||
return true;
|
return true;
|
||||||
@ -181,6 +187,9 @@ void MainLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
|
|||||||
else if (type == message::JumpToSettings) {
|
else if (type == message::JumpToSettings) {
|
||||||
this->SetLayout(settingsLayout);
|
this->SetLayout(settingsLayout);
|
||||||
}
|
}
|
||||||
|
else if (type == message::JumpToLyrics) {
|
||||||
|
this->SetLayout(lyricsLayout);
|
||||||
|
}
|
||||||
else if (type == message::JumpToHotkeys) {
|
else if (type == message::JumpToHotkeys) {
|
||||||
this->SetLayout(hotkeysLayout);
|
this->SetLayout(hotkeysLayout);
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,7 @@ namespace musik {
|
|||||||
std::shared_ptr<cursespp::LayoutBase> libraryLayout;
|
std::shared_ptr<cursespp::LayoutBase> libraryLayout;
|
||||||
std::shared_ptr<cursespp::LayoutBase> settingsLayout;
|
std::shared_ptr<cursespp::LayoutBase> settingsLayout;
|
||||||
std::shared_ptr<cursespp::LayoutBase> hotkeysLayout;
|
std::shared_ptr<cursespp::LayoutBase> hotkeysLayout;
|
||||||
|
std::shared_ptr<cursespp::LayoutBase> lyricsLayout;
|
||||||
musik::core::ILibraryPtr library;
|
musik::core::ILibraryPtr library;
|
||||||
bool shortcutsFocused;
|
bool shortcutsFocused;
|
||||||
int syncUpdateCount;
|
int syncUpdateCount;
|
||||||
|
@ -80,6 +80,7 @@ static std::unordered_map<std::string, Id> NAME_TO_ID = {
|
|||||||
{ "navigate_library_play_queue", Id::NavigateLibraryPlayQueue },
|
{ "navigate_library_play_queue", Id::NavigateLibraryPlayQueue },
|
||||||
{ "navigate_settings", Id::NavigateSettings },
|
{ "navigate_settings", Id::NavigateSettings },
|
||||||
{ "navigate_console", Id::NavigateConsole },
|
{ "navigate_console", Id::NavigateConsole },
|
||||||
|
{ "navigate_lyrics", Id::NavigateLyrics },
|
||||||
{ "navigate_hotkeys", Id::NavigateHotkeys},
|
{ "navigate_hotkeys", Id::NavigateHotkeys},
|
||||||
{ "navigate_jump_to_playing", Id::NavigateJumpToPlaying },
|
{ "navigate_jump_to_playing", Id::NavigateJumpToPlaying },
|
||||||
|
|
||||||
@ -151,6 +152,7 @@ static std::unordered_map<Id, std::string, EnumHasher> ID_TO_DEFAULT = {
|
|||||||
{ Id::NavigateLibraryPlayQueue, "n" },
|
{ Id::NavigateLibraryPlayQueue, "n" },
|
||||||
{ Id::NavigateSettings, "s" },
|
{ Id::NavigateSettings, "s" },
|
||||||
{ Id::NavigateConsole, "`" },
|
{ Id::NavigateConsole, "`" },
|
||||||
|
{ Id::NavigateLyrics, "^L" },
|
||||||
{ Id::NavigateHotkeys, "?" },
|
{ Id::NavigateHotkeys, "?" },
|
||||||
{ Id::NavigateJumpToPlaying, "x" },
|
{ Id::NavigateJumpToPlaying, "x" },
|
||||||
|
|
||||||
|
@ -66,10 +66,11 @@ namespace musik {
|
|||||||
NavigateLibraryFilter,
|
NavigateLibraryFilter,
|
||||||
NavigateLibraryTracks,
|
NavigateLibraryTracks,
|
||||||
NavigateLibraryPlayQueue,
|
NavigateLibraryPlayQueue,
|
||||||
NavigateSettings,
|
|
||||||
NavigateConsole,
|
NavigateConsole,
|
||||||
|
NavigateLyrics,
|
||||||
NavigateHotkeys,
|
NavigateHotkeys,
|
||||||
NavigateJumpToPlaying,
|
NavigateJumpToPlaying,
|
||||||
|
NavigateSettings,
|
||||||
|
|
||||||
/* views */
|
/* views */
|
||||||
ViewRefresh,
|
ViewRefresh,
|
||||||
|
@ -60,10 +60,11 @@ namespace musik {
|
|||||||
static const int JumpToConsole = First + 9;
|
static const int JumpToConsole = First + 9;
|
||||||
static const int JumpToLibrary = First + 10;
|
static const int JumpToLibrary = First + 10;
|
||||||
static const int JumpToSettings = First + 11;
|
static const int JumpToSettings = First + 11;
|
||||||
static const int JumpToHotkeys = First + 12;
|
static const int JumpToLyrics = First + 12;
|
||||||
static const int SetLastFmState = First + 13;
|
static const int JumpToHotkeys = First + 13;
|
||||||
static const int UpdateEqualizer = First + 14;
|
static const int SetLastFmState = First + 14;
|
||||||
static const int DebugLog = First + 15;
|
static const int UpdateEqualizer = First + 15;
|
||||||
|
static const int DebugLog = First + 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,6 +174,7 @@
|
|||||||
|
|
||||||
"shortcuts_settings": "settings",
|
"shortcuts_settings": "settings",
|
||||||
"shortcuts_library": "library",
|
"shortcuts_library": "library",
|
||||||
|
"shortcuts_lyrics": "lyrics",
|
||||||
"shortcuts_console": "logs",
|
"shortcuts_console": "logs",
|
||||||
"shortcuts_quit": "quit",
|
"shortcuts_quit": "quit",
|
||||||
"shortcuts_browse": "browse",
|
"shortcuts_browse": "browse",
|
||||||
@ -203,6 +204,11 @@
|
|||||||
"main_syncing_banner_start": "syncing metadata...",
|
"main_syncing_banner_start": "syncing metadata...",
|
||||||
"main_syncing_banner": "syncing metadata (%d tracks processed)",
|
"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_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_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",
|
"update_check_no_updates_title": "update check",
|
||||||
|
Loading…
Reference in New Issue
Block a user