Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
|
c35416c928 | |
|
be3a50d42a |
BIN
img/linux.png
BIN
img/linux.png
Binary file not shown.
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 42 KiB |
BIN
img/macos.png
BIN
img/macos.png
Binary file not shown.
Before Width: | Height: | Size: 248 KiB After Width: | Height: | Size: 135 KiB |
BIN
img/windows.png
BIN
img/windows.png
Binary file not shown.
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 53 KiB |
53
src/main.cpp
53
src/main.cpp
|
@ -16,6 +16,7 @@
|
||||||
std::string lastPlayingSong = "";
|
std::string lastPlayingSong = "";
|
||||||
std::string lastMediaSource = "";
|
std::string lastMediaSource = "";
|
||||||
std::string currentSongTitle = "";
|
std::string currentSongTitle = "";
|
||||||
|
utils::SongInfo songInfo;
|
||||||
LastFM* lastfm = nullptr;
|
LastFM* lastfm = nullptr;
|
||||||
|
|
||||||
void handleRPCTasks() {
|
void handleRPCTasks() {
|
||||||
|
@ -59,6 +60,7 @@ void handleMediaTasks() {
|
||||||
while (true) {
|
while (true) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
auto mediaInformation = backend::getMediaInformation();
|
auto mediaInformation = backend::getMediaInformation();
|
||||||
|
auto settings = utils::getSettings();
|
||||||
if (!mediaInformation) {
|
if (!mediaInformation) {
|
||||||
currentSongTitle = "";
|
currentSongTitle = "";
|
||||||
Discord_ClearPresence(); // Nothing is playing rn, clear presence
|
Discord_ClearPresence(); // Nothing is playing rn, clear presence
|
||||||
|
@ -112,15 +114,15 @@ void handleMediaTasks() {
|
||||||
activity.details = mediaInformation->songTitle.c_str();
|
activity.details = mediaInformation->songTitle.c_str();
|
||||||
activity.state = activityState.c_str();
|
activity.state = activityState.c_str();
|
||||||
activity.smallImageText = serviceName.c_str();
|
activity.smallImageText = serviceName.c_str();
|
||||||
std::string artworkURL = utils::getArtworkURL(mediaInformation->songTitle + " " + mediaInformation->songArtist +
|
songInfo = utils::getSongInfo(mediaInformation->songTitle + " " + mediaInformation->songArtist + " " +
|
||||||
" " + mediaInformation->songAlbum);
|
mediaInformation->songAlbum);
|
||||||
|
|
||||||
activity.smallImageKey = "appicon";
|
activity.smallImageKey = "appicon";
|
||||||
if (artworkURL == "") {
|
if (songInfo.artworkURL == "") {
|
||||||
activity.smallImageKey = "";
|
activity.smallImageKey = "";
|
||||||
activity.largeImageKey = "appicon";
|
activity.largeImageKey = "appicon";
|
||||||
} else {
|
} else {
|
||||||
activity.largeImageKey = artworkURL.c_str();
|
activity.largeImageKey = songInfo.artworkURL.c_str();
|
||||||
}
|
}
|
||||||
activity.largeImageText = mediaInformation->songAlbum.c_str();
|
activity.largeImageText = mediaInformation->songAlbum.c_str();
|
||||||
|
|
||||||
|
@ -140,6 +142,12 @@ void handleMediaTasks() {
|
||||||
activity.button1link = buttonText.c_str();
|
activity.button1link = buttonText.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string odesliUrl = utils::getOdesliURL(songInfo);
|
||||||
|
if(settings.odesli && songInfo.artworkURL != "") {
|
||||||
|
activity.button2name = "Show on Song.link";
|
||||||
|
activity.button2link = odesliUrl.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
Discord_UpdatePresence(&activity);
|
Discord_UpdatePresence(&activity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,6 +160,8 @@ public:
|
||||||
settingsFrame->Raise();
|
settingsFrame->Raise();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnCopyOdesliURL(wxCommandEvent& evt) { utils::copyToClipboard(utils::getOdesliURL(songInfo)); }
|
||||||
|
|
||||||
void OnMenuExit(wxCommandEvent& evt) { settingsFrame->Close(true); }
|
void OnMenuExit(wxCommandEvent& evt) { settingsFrame->Close(true); }
|
||||||
|
|
||||||
void OnMenuAbout(wxCommandEvent& evt) {
|
void OnMenuAbout(wxCommandEvent& evt) {
|
||||||
|
@ -164,10 +174,14 @@ protected:
|
||||||
menu->Append(10004, currentSongTitle == "" ? _("Not Playing") : wxString::FromUTF8(currentSongTitle));
|
menu->Append(10004, currentSongTitle == "" ? _("Not Playing") : wxString::FromUTF8(currentSongTitle));
|
||||||
menu->Enable(10004, false);
|
menu->Enable(10004, false);
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
|
menu->Append(10005, _("Copy Odesli URL"));
|
||||||
|
if (songInfo.artworkURL == "" || currentSongTitle == "")
|
||||||
|
menu->Enable(10005, false);
|
||||||
menu->Append(10001, _("Settings"));
|
menu->Append(10001, _("Settings"));
|
||||||
menu->Append(10003, _("About PlayerLink"));
|
menu->Append(10003, _("About PlayerLink"));
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
menu->Append(10002, _("Quit PlayerLink..."));
|
menu->Append(10002, _("Quit PlayerLink..."));
|
||||||
|
Bind(wxEVT_MENU, &PlayerLinkIcon::OnCopyOdesliURL, this, 10005);
|
||||||
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuOpen, this, 10001);
|
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuOpen, this, 10001);
|
||||||
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuExit, this, 10002);
|
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuExit, this, 10002);
|
||||||
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuAbout, this, 10003);
|
Bind(wxEVT_MENU, &PlayerLinkIcon::OnMenuAbout, this, 10003);
|
||||||
|
@ -188,7 +202,6 @@ public:
|
||||||
placeholder(""),
|
placeholder(""),
|
||||||
showPlaceholder(true),
|
showPlaceholder(true),
|
||||||
isPassword((style & wxTE_PASSWORD) != 0) {
|
isPassword((style & wxTE_PASSWORD) != 0) {
|
||||||
|
|
||||||
Bind(wxEVT_SET_FOCUS, &wxTextCtrlWithPlaceholder::OnFocus, this);
|
Bind(wxEVT_SET_FOCUS, &wxTextCtrlWithPlaceholder::OnFocus, this);
|
||||||
Bind(wxEVT_KILL_FOCUS, &wxTextCtrlWithPlaceholder::OnBlur, this);
|
Bind(wxEVT_KILL_FOCUS, &wxTextCtrlWithPlaceholder::OnBlur, this);
|
||||||
}
|
}
|
||||||
|
@ -230,13 +243,9 @@ private:
|
||||||
SetValue(placeholder);
|
SetValue(placeholder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStyleToPassword() {
|
void SetStyleToPassword() { SetWindowStyle(GetWindowStyle() | wxTE_PASSWORD); }
|
||||||
SetWindowStyle(GetWindowStyle() | wxTE_PASSWORD);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetStyleToNormal() {
|
void SetStyleToNormal() { SetWindowStyle(GetWindowStyle() & ~wxTE_PASSWORD); }
|
||||||
SetWindowStyle(GetWindowStyle() & ~wxTE_PASSWORD);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerLinkFrame : public wxFrame {
|
class PlayerLinkFrame : public wxFrame {
|
||||||
|
@ -387,11 +396,14 @@ public:
|
||||||
mainContainer->Add(appsDivider, 0, wxEXPAND | wxALL, 5);
|
mainContainer->Add(appsDivider, 0, wxEXPAND | wxALL, 5);
|
||||||
|
|
||||||
wxBoxSizer* settingsContainer;
|
wxBoxSizer* settingsContainer;
|
||||||
settingsContainer = new wxBoxSizer(wxHORIZONTAL);
|
settingsContainer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
wxBoxSizer* startupContainer;
|
||||||
|
startupContainer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
auto startupText = new wxStaticText(this, wxID_ANY, _("Startup:"), wxDefaultPosition, wxDefaultSize, 0);
|
auto startupText = new wxStaticText(this, wxID_ANY, _("Startup:"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
startupText->Wrap(-1);
|
startupText->Wrap(-1);
|
||||||
settingsContainer->Add(startupText, 0, wxALL, 5);
|
startupContainer->Add(startupText, 0, wxALL, 5);
|
||||||
|
|
||||||
auto autostartCheckbox =
|
auto autostartCheckbox =
|
||||||
new wxCheckBox(this, wxID_ANY, _("Launch at login"), wxDefaultPosition, wxDefaultSize, 0);
|
new wxCheckBox(this, wxID_ANY, _("Launch at login"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
|
@ -404,8 +416,21 @@ public:
|
||||||
utils::saveSettings(settings);
|
utils::saveSettings(settings);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
auto odesliCheckbox =
|
||||||
|
new wxCheckBox(this, wxID_ANY, _("Odesli integration"), wxDefaultPosition, wxDefaultSize, 0);
|
||||||
|
odesliCheckbox->SetValue(settings.odesli);
|
||||||
|
odesliCheckbox->Bind(wxEVT_CHECKBOX, [](wxCommandEvent& event) {
|
||||||
|
bool isChecked = event.IsChecked();
|
||||||
|
auto settings = utils::getSettings();
|
||||||
|
settings.odesli = isChecked;
|
||||||
|
utils::saveSettings(settings);
|
||||||
|
});
|
||||||
|
|
||||||
settingsContainer->Add(autostartCheckbox, 0, wxALL, 5);
|
settingsContainer->Add(autostartCheckbox, 0, wxALL, 5);
|
||||||
mainContainer->Add(settingsContainer, 0, wxEXPAND, 5);
|
settingsContainer->Add(odesliCheckbox, 0, wxALL, 5);
|
||||||
|
startupContainer->Add(settingsContainer);
|
||||||
|
mainContainer->Add(startupContainer, 0, wxEXPAND, 5);
|
||||||
|
|
||||||
// settings end
|
// settings end
|
||||||
this->SetSizerAndFit(mainContainer);
|
this->SetSizerAndFit(mainContainer);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <curl/include/curl/curl.h>
|
#include <curl/include/curl/curl.h>
|
||||||
#include <wx/mstream.h>
|
#include <wx/mstream.h>
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
|
#include <wx/clipbrd.h>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -35,12 +36,26 @@ namespace utils {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Settings {
|
struct Settings {
|
||||||
|
bool odesli;
|
||||||
bool autoStart;
|
bool autoStart;
|
||||||
bool anyOtherEnabled;
|
bool anyOtherEnabled;
|
||||||
LastFMSettings lastfm;
|
LastFMSettings lastfm;
|
||||||
std::vector<App> apps;
|
std::vector<App> apps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SongInfo {
|
||||||
|
std::string artworkURL;
|
||||||
|
int64_t trackId;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void copyToClipboard(const wxString& text) {
|
||||||
|
if (wxTheClipboard->Open()) {
|
||||||
|
wxTheClipboard->Clear();
|
||||||
|
wxTheClipboard->SetData(new wxTextDataObject(text));
|
||||||
|
wxTheClipboard->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) {
|
inline wxIcon loadIconFromMemory(const unsigned char* data, size_t size) {
|
||||||
wxMemoryInputStream stream(data, size);
|
wxMemoryInputStream stream(data, size);
|
||||||
wxImage img(stream, wxBITMAP_TYPE_PNG);
|
wxImage img(stream, wxBITMAP_TYPE_PNG);
|
||||||
|
@ -125,15 +140,21 @@ namespace utils {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string getArtworkURL(std::string query) {
|
inline SongInfo getSongInfo(std::string query) {
|
||||||
|
SongInfo ret{};
|
||||||
std::string response =
|
std::string response =
|
||||||
httpRequest("https://itunes.apple.com/search?media=music&entity=song&term=" + urlEncode(query));
|
httpRequest("https://itunes.apple.com/search?media=music&entity=song&term=" + urlEncode(query));
|
||||||
nlohmann::json j = nlohmann::json::parse(response);
|
nlohmann::json j = nlohmann::json::parse(response);
|
||||||
auto results = j["results"];
|
auto results = j["results"];
|
||||||
if (results.size() > 0) {
|
if (results.size() > 0) {
|
||||||
return results[0]["artworkUrl100"].get<std::string>();
|
ret.artworkURL = results[0]["artworkUrl100"].get<std::string>();
|
||||||
|
ret.trackId = results[0]["trackId"].get<int64_t>();
|
||||||
}
|
}
|
||||||
return "";
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string getOdesliURL(SongInfo& song) {
|
||||||
|
return std::string("https://song.link/i/" + std::to_string(song.trackId));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void saveSettings(const App* newApp) {
|
inline void saveSettings(const App* newApp) {
|
||||||
|
@ -189,6 +210,7 @@ namespace utils {
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
j["autostart"] = settings.autoStart;
|
j["autostart"] = settings.autoStart;
|
||||||
j["any_other"] = settings.anyOtherEnabled;
|
j["any_other"] = settings.anyOtherEnabled;
|
||||||
|
j["odesli"] = settings.odesli;
|
||||||
|
|
||||||
j["lastfm"]["enabled"] = settings.lastfm.enabled;
|
j["lastfm"]["enabled"] = settings.lastfm.enabled;
|
||||||
j["lastfm"]["api_key"] = settings.lastfm.api_key;
|
j["lastfm"]["api_key"] = settings.lastfm.api_key;
|
||||||
|
@ -218,6 +240,7 @@ namespace utils {
|
||||||
if (!std::filesystem::exists(CONFIG_FILENAME)) {
|
if (!std::filesystem::exists(CONFIG_FILENAME)) {
|
||||||
ret.anyOtherEnabled = true;
|
ret.anyOtherEnabled = true;
|
||||||
ret.autoStart = false;
|
ret.autoStart = false;
|
||||||
|
ret.odesli = false;
|
||||||
saveSettings(ret);
|
saveSettings(ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +252,7 @@ namespace utils {
|
||||||
|
|
||||||
ret.autoStart = j.value("autostart", false);
|
ret.autoStart = j.value("autostart", false);
|
||||||
ret.anyOtherEnabled = j.value("any_other", false);
|
ret.anyOtherEnabled = j.value("any_other", false);
|
||||||
|
ret.odesli = j.value("odesli", false);
|
||||||
|
|
||||||
if (j.contains("lastfm")) {
|
if (j.contains("lastfm")) {
|
||||||
auto lastfm = j["lastfm"];
|
auto lastfm = j["lastfm"];
|
||||||
|
|
Loading…
Reference in New Issue