Compare commits

..

2 Commits
v1.1 ... main

Author SHA1 Message Date
EinTim23 c35416c928 feat: odesli/song.link integration 2025-01-16 13:56:29 +01:00
EinTim23 be3a50d42a updated readme images 2025-01-12 21:31:18 +01:00
5 changed files with 72 additions and 23 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -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);

View File

@ -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"];