This commit is contained in:
EinTim23 2024-11-06 11:36:35 +01:00
commit 29684eb97c
2 changed files with 118 additions and 102 deletions

View File

@ -14,6 +14,7 @@ struct MediaInfo {
int64_t songDuration; int64_t songDuration;
int64_t songElapsedTime; int64_t songElapsedTime;
std::string playbackSource; std::string playbackSource;
MediaInfo() {}
MediaInfo(bool p, std::string title, std::string artist, std::string album, std::string source, MediaInfo(bool p, std::string title, std::string artist, std::string album, std::string source,
std::string thumbnail, int duration, int elapsed) std::string thumbnail, int duration, int elapsed)
: paused(p), : paused(p),

View File

@ -1,12 +1,20 @@
#if !defined(_WIN32) && !defined(__APPLE__) #if !defined(_WIN32) && !defined(__APPLE__)
#include <dbus/dbus.h> #include <dbus/dbus.h>
#include <filesystem>
#include <fstream>
#include <iostream> #include <iostream>
#include "../backend.hpp" #include "../backend.hpp"
DBusConnection* conn = nullptr; DBusConnection* conn = nullptr;
std::string getExecutablePath() {
char result[PATH_MAX]{};
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return (count != -1) ? std::string(result, count) : std::string();
}
std::string getActivePlayer(DBusConnection* conn) { std::string getActivePlayer(DBusConnection* conn) {
DBusMessage* msg; DBusMessage* msg;
DBusMessageIter args; DBusMessageIter args;
@ -56,10 +64,8 @@ bool isPlayerPaused(DBusConnection* conn, const std::string& player) {
msg = dbus_message_new_method_call(player.c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", msg = dbus_message_new_method_call(player.c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties",
"Get"); "Get");
if (!msg) { if (!msg)
std::cerr << "Message Null" << std::endl;
return false; return false;
}
const char* interface = "org.mpris.MediaPlayer2.Player"; const char* interface = "org.mpris.MediaPlayer2.Player";
const char* property = "PlaybackStatus"; const char* property = "PlaybackStatus";
@ -87,33 +93,31 @@ bool isPlayerPaused(DBusConnection* conn, const std::string& player) {
return isPaused; return isPaused;
} }
void getNowPlaying(DBusConnection* conn, const std::string& player) { void getNowPlaying(DBusConnection* conn, const std::string& player, MediaInfo& mediaInfo) {
DBusMessage* msg;
DBusMessageIter args;
DBusError err; DBusError err;
dbus_error_init(&err); dbus_error_init(&err);
msg = dbus_message_new_method_call(player.c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", auto sendDBusMessage = [&](const char* property) -> DBusMessage* {
"Get"); DBusMessage* msg = dbus_message_new_method_call(player.c_str(), "/org/mpris/MediaPlayer2",
"org.freedesktop.DBus.Properties", "Get");
const char* iface = "org.mpris.MediaPlayer2.Player"; const char* iface = "org.mpris.MediaPlayer2.Player";
const char* prop = "Metadata"; dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID);
dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID);
DBusMessage* reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); DBusMessage* reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg); dbus_message_unref(msg);
return reply;
};
if (!reply) { auto processMetadata = [&](DBusMessage* reply) {
std::cerr << "Failed to get metadata: " << (err.message ? err.message : "Unknown error") << std::endl; if (!reply) return;
dbus_error_free(&err);
return;
}
DBusMessageIter args;
dbus_message_iter_init(reply, &args); dbus_message_iter_init(reply, &args);
if (dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_VARIANT) { if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) return;
DBusMessageIter variant; DBusMessageIter variant;
dbus_message_iter_recurse(&args, &variant); dbus_message_iter_recurse(&args, &variant);
if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY) return;
if (dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY) {
DBusMessageIter array_iter; DBusMessageIter array_iter;
dbus_message_iter_recurse(&variant, &array_iter); dbus_message_iter_recurse(&variant, &array_iter);
@ -125,81 +129,56 @@ void getNowPlaying(DBusConnection* conn, const std::string& player) {
dbus_message_iter_get_basic(&dict_entry, &key); dbus_message_iter_get_basic(&dict_entry, &key);
dbus_message_iter_next(&dict_entry); dbus_message_iter_next(&dict_entry);
if (std::string(key) == "xesam:title") {
DBusMessageIter value_variant; DBusMessageIter value_variant;
dbus_message_iter_recurse(&dict_entry, &value_variant); dbus_message_iter_recurse(&dict_entry, &value_variant);
if (dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_STRING) { if (std::string(key) == "xesam:title" && dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_STRING) {
const char* title; const char* title;
dbus_message_iter_get_basic(&value_variant, &title); dbus_message_iter_get_basic(&value_variant, &title);
std::cout << "Title: " << title << std::endl; mediaInfo.songTitle = title;
} } else if (std::string(key) == "xesam:album" && dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_STRING) {
} else if (std::string(key) == "xesam:artist") { const char* album;
DBusMessageIter value_variant; dbus_message_iter_get_basic(&value_variant, &album);
dbus_message_iter_recurse(&dict_entry, &value_variant); mediaInfo.songAlbum = album;
} else if (std::string(key) == "xesam:artist" && dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_ARRAY) {
if (dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_ARRAY) {
DBusMessageIter artist_array; DBusMessageIter artist_array;
dbus_message_iter_recurse(&value_variant, &artist_array); dbus_message_iter_recurse(&value_variant, &artist_array);
if (dbus_message_iter_get_arg_type(&artist_array) == DBUS_TYPE_STRING) {
std::cout << "Artist(s): ";
bool first = true;
while (dbus_message_iter_get_arg_type(&artist_array) == DBUS_TYPE_STRING) {
const char* artist; const char* artist;
dbus_message_iter_get_basic(&artist_array, &artist); dbus_message_iter_get_basic(&artist_array, &artist);
if (!first) mediaInfo.songArtist = artist;
std::cout << ", ";
std::cout << artist;
first = false;
dbus_message_iter_next(&artist_array);
} }
std::cout << std::endl; } else if (std::string(key) == "mpris:length" &&
} (dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_INT64 || dbus_message_iter_get_arg_type(&value_variant) == DBUS_TYPE_UINT64)) {
} else if (std::string(key) == "mpris:length") {
DBusMessageIter value_variant;
dbus_message_iter_recurse(&dict_entry, &value_variant);
int arg_type = dbus_message_iter_get_arg_type(&value_variant);
if (arg_type == DBUS_TYPE_INT64 || arg_type == DBUS_TYPE_UINT64) {
int64_t length; int64_t length;
dbus_message_iter_get_basic(&value_variant, &length); dbus_message_iter_get_basic(&value_variant, &length);
std::cout << "Length (Duration): " << length / 1000000.0 << " seconds" << std::endl; mediaInfo.songDuration = length / 1000;
} }
}
dbus_message_iter_next(&array_iter); dbus_message_iter_next(&array_iter);
} }
} };
} else {
std::cerr << "Unexpected reply type for Metadata" << std::endl;
}
dbus_message_unref(reply); DBusMessage* metadataReply = sendDBusMessage("Metadata");
msg = dbus_message_new_method_call(player.c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", processMetadata(metadataReply);
"Get"); dbus_message_unref(metadataReply);
prop = "Position";
dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID);
reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err); DBusMessage* positionReply = sendDBusMessage("Position");
dbus_message_unref(msg); if (positionReply) {
DBusMessageIter args;
if (!reply) { dbus_message_iter_init(positionReply, &args);
std::cerr << "Failed to get position: " << (err.message ? err.message : "Unknown error") << std::endl;
dbus_error_free(&err);
return;
}
dbus_message_iter_init(reply, &args);
if (dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_VARIANT) { if (dbus_message_iter_get_arg_type(&args) == DBUS_TYPE_VARIANT) {
DBusMessageIter variant; DBusMessageIter variant;
dbus_message_iter_recurse(&args, &variant); dbus_message_iter_recurse(&args, &variant);
int arg_type = dbus_message_iter_get_arg_type(&variant); if (dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_INT64 || dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_UINT64) {
if (arg_type == DBUS_TYPE_INT64 || arg_type == DBUS_TYPE_UINT64) {
int64_t position; int64_t position;
dbus_message_iter_get_basic(&variant, &position); dbus_message_iter_get_basic(&variant, &position);
std::cout << "Current Position: " << position / 1000000.0 << " seconds" << std::endl; mediaInfo.songElapsedTime = position / 1000;
} }
} }
dbus_message_unref(reply); dbus_message_unref(positionReply);
}
dbus_error_free(&err);
} }
bool backend::init() { bool backend::init() {
@ -215,12 +194,48 @@ bool backend::init() {
} }
std::shared_ptr<MediaInfo> backend::getMediaInformation() { std::shared_ptr<MediaInfo> backend::getMediaInformation() {
MediaInfo ret;
std::string player = getActivePlayer(conn); std::string player = getActivePlayer(conn);
if (player == "") if (player == "")
return nullptr; return nullptr;
getNowPlaying(conn, player); getNowPlaying(conn, player, ret);
return nullptr; ret.paused = isPlayerPaused(conn, player);
ret.playbackSource = player;
return std::make_shared<MediaInfo>(ret);
} }
bool backend::toggleAutostart(bool enabled) { return false; } bool backend::toggleAutostart(bool enabled) {
const char* xdgHome = std::getenv("XDG_CONFIG_HOME");
const char* home = std::getenv("HOME");
if (!xdgHome && !home)
return false;
std::string realxdgHome = xdgHome ? xdgHome : home;
std::filesystem::path xdgAutostartPath = realxdgHome;
if (!xdgHome)
xdgAutostartPath = xdgAutostartPath / ".config";
xdgAutostartPath = xdgAutostartPath / "autostart";
std::filesystem::create_directories(xdgAutostartPath);
std::filesystem::path desktopPath = xdgAutostartPath / "PlayerLink.desktop";
if (!enabled && std::filesystem::exists(desktopPath)) {
std::filesystem::remove(desktopPath);
return true;
}
// I would like to use std::format here, but a lot of modern linux distributions like Debian 12 still use clang 14
// which doesnt support std::format
std::string formattedDesktop = "[Desktop Entry]\nType=Application\nName=PlayerLink\nExec=" + getExecutablePath() +
"\nX-GNOME-Autostart-enabled=true\n";
std::ofstream o(desktopPath);
o.write(formattedDesktop.c_str(), formattedDesktop.size());
o.close();
return true;
}
#undef XDG_AUTOSTART_TEMPLATE
#endif #endif