Finished linux backend
This commit is contained in:
parent
42255b6569
commit
03ac2df3cf
|
@ -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),
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
DBusConnection* conn = nullptr;
|
DBusConnection* conn = nullptr;
|
||||||
|
|
||||||
std::string getExecutablePath() {
|
std::string getExecutablePath() {
|
||||||
char result[PATH_MAX];
|
char result[PATH_MAX]{};
|
||||||
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
|
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
|
||||||
return (count != -1) ? std::string(result, count) : std::string();
|
return (count != -1) ? std::string(result, count) : std::string();
|
||||||
}
|
}
|
||||||
|
@ -64,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";
|
||||||
|
@ -95,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);
|
||||||
|
|
||||||
|
@ -133,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() {
|
||||||
|
@ -223,12 +194,14 @@ 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);
|
||||||
std::cout << "isPaused: " << isPlayerPaused(conn, player) << " \n";
|
ret.paused = isPlayerPaused(conn, player);
|
||||||
return nullptr;
|
ret.playbackSource = player;
|
||||||
|
return std::make_shared<MediaInfo>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool backend::toggleAutostart(bool enabled) {
|
bool backend::toggleAutostart(bool enabled) {
|
||||||
|
@ -254,10 +227,12 @@ bool backend::toggleAutostart(bool enabled) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string formattedPlist = "[Desktop Entry]\nType=Application\nName=PlayerLink\nExec=" + getExecutablePath() +
|
// 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";
|
"\nX-GNOME-Autostart-enabled=true\n";
|
||||||
std::ofstream o(desktopPath);
|
std::ofstream o(desktopPath);
|
||||||
o.write(formattedPlist.c_str(), formattedPlist.size());
|
o.write(formattedDesktop.c_str(), formattedDesktop.size());
|
||||||
o.close();
|
o.close();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue