From 0916258c8746f6e9aa6dcf56de4b0e63bddffd6f Mon Sep 17 00:00:00 2001 From: Linus Dierheimer Date: Tue, 22 Mar 2022 18:59:04 +0100 Subject: [PATCH] Greatly improved detection of media player name --- CMakeLists.txt | 6 +- src/detection/media.c | 174 ++++++++++++++++++++++++++++++++---------- src/fastfetch.c | 11 ++- src/fastfetch.h | 5 +- src/modules/player.c | 8 +- src/modules/song.c | 5 +- 6 files changed, 155 insertions(+), 54 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f67963eff..934cd8da3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 3.1.0) # Threads::Threads project(fastfetch - VERSION 1.0.0 + VERSION 1.1.0 LANGUAGES C ) -#e.g. -alpha or -beta or +1 +#e.g. +1 #This allows to track builds between versions, without GitHub creating a new release -set(PROJECT_VERSION_EXTRA "+1") +set(PROJECT_VERSION_EXTRA "") include(GNUInstallDirs) diff --git a/src/detection/media.c b/src/detection/media.c index 9dd63ee0e..408dfd6e1 100644 --- a/src/detection/media.c +++ b/src/detection/media.c @@ -1,5 +1,6 @@ #include "fastfetch.h" +#include #include #include @@ -53,20 +54,25 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data) return true; } - if(argType != DBUS_TYPE_ARRAY) + if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) return false; - DBusMessageIter arrayIter; - data->ffdbus_message_iter_recurse(iter, &arrayIter); + DBusMessageIter subIter; + data->ffdbus_message_iter_recurse(iter, &subIter); + + if(argType == DBUS_TYPE_VARIANT) + return getValue(&subIter, result, data); + + //At this point we have an array bool foundAValue = false; while(true) { - if((foundAValue = getValue(&arrayIter, result, data))) + if((foundAValue = getValue(&subIter, result, data))) ffStrbufAppendS(result, ", "); - FF_DBUS_ITER_CONTINUE(arrayIter); + FF_DBUS_ITER_CONTINUE(subIter); } if(foundAValue) @@ -75,51 +81,87 @@ static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data) return foundAValue; } -static bool detectSong(const char* player, FFMediaResult* result, DBusData* data) +static DBusMessage* getProperty(const char* busName, const char* objectPath, const char* interface, const char* property, DBusData* data) { - DBusMessage* message = data->ffdbus_message_new_method_call(player, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"); + DBusMessage* message = data->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get"); if(message == NULL) - return false; + return NULL; DBusMessageIter requestIterator; data->ffdbus_message_iter_init_append(message, &requestIterator); - const char* arg1 = "org.mpris.MediaPlayer2.Player"; - if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &arg1)) + if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface)) { data->ffdbus_message_unref(message); - return false; + return NULL; } - const char* arg2 = "Metadata"; - if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &arg2)) + if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property)) { data->ffdbus_message_unref(message); - return false; + return NULL; } DBusPendingCall* pending; bool sendSuccessfull = data->ffdbus_connection_send_with_reply(data->connection, message, &pending, DBUS_TIMEOUT_USE_DEFAULT); data->ffdbus_message_unref(message); if(pending == NULL || !sendSuccessfull) - return false; + return NULL; data->ffdbus_connection_flush(data->connection); data->ffdbus_pending_call_block(pending); DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pending); + data->ffdbus_pending_call_unref(pending); + + return reply; +} + +static void getPropertyString(const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result, DBusData* data) +{ + DBusMessage* reply = getProperty(busName, objectPath, interface, property, data); + if(reply == NULL) + return; + + DBusMessageIter rootIterator; + if(!data->ffdbus_message_iter_init(reply, &rootIterator)) + { + data->ffdbus_message_unref(reply); + return; + } + + getValue(&rootIterator, result, data); + + data->ffdbus_message_unref(reply); +} + +static bool getBusProperties(const char* busName, FFMediaResult* result, DBusData* data) +{ + DBusMessage* reply = getProperty(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata", data); if(reply == NULL) return false; DBusMessageIter rootIterator; - if(!data->ffdbus_message_iter_init(reply, &rootIterator) || data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) + if(!data->ffdbus_message_iter_init(reply, &rootIterator)) + { + data->ffdbus_message_unref(reply); + return false; + } + + if(data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) + { + data->ffdbus_message_unref(reply); return false; + } DBusMessageIter variantIterator; data->ffdbus_message_iter_recurse(&rootIterator, &variantIterator); if(data->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY) + { + data->ffdbus_message_unref(reply); return false; + } DBusMessageIter arrayIterator; data->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator); @@ -143,18 +185,14 @@ static bool detectSong(const char* player, FFMediaResult* result, DBusData* data data->ffdbus_message_iter_next(&dictIterator); - if(data->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_VARIANT) - FF_DBUS_ITER_CONTINUE(arrayIterator) - - DBusMessageIter valueIter; - data->ffdbus_message_iter_recurse(&dictIterator, &valueIter); - if(strcmp(key, "xesam:title") == 0) - getValue(&valueIter, &result->song, data); + getValue(&dictIterator, &result->song, data); else if(strcmp(key, "xesam:album") == 0) - getValue(&valueIter, &result->album, data); + getValue(&dictIterator, &result->album, data); else if(strcmp(key, "xesam:artist") == 0) - getValue(&valueIter, &result->artist, data); + getValue(&dictIterator, &result->artist, data); + else if(strcmp(key, "xesam:url") == 0) + getValue(&dictIterator, &result->url, data); if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0) break; @@ -162,6 +200,8 @@ static bool detectSong(const char* player, FFMediaResult* result, DBusData* data FF_DBUS_ITER_CONTINUE(arrayIterator) } + data->ffdbus_message_unref(reply); + if(result->song.length == 0) { ffStrbufClear(&result->artist); @@ -169,29 +209,36 @@ static bool detectSong(const char* player, FFMediaResult* result, DBusData* data return false; } + //We found a song, get the player name + + getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player, data); + + if(result->player.length == 0) + getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player, data); + return true; } -static void getCustomPlayer(FFinstance* instance, FFMediaResult* result, DBusData* data) +static void getCustomBus(FFinstance* instance, FFMediaResult* result, DBusData* data) { if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX)) { - detectSong(instance->config.playerName.chars, result, data); - ffStrbufAppendS(&result->player, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + ffStrbufAppendS(&result->busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + getBusProperties(instance->config.playerName.chars, result, data); return; } + ffStrbufAppend(&result->busNameShort, &instance->config.playerName); + FFstrbuf busName; ffStrbufInit(&busName); ffStrbufAppendS(&busName, FF_DBUS_MPRIS_PREFIX); ffStrbufAppend(&busName, &instance->config.playerName); - detectSong(busName.chars, result, data); + getBusProperties(busName.chars, result, data); ffStrbufDestroy(&busName); - - ffStrbufAppend(&result->player, &instance->config.playerName); } -static void getBestPlayer(FFMediaResult* result, DBusData* data) +static void getBestBus(FFMediaResult* result, DBusData* data) { DBusMessage* message = data->ffdbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"); if(message == NULL) @@ -223,20 +270,22 @@ static void getBestPlayer(FFMediaResult* result, DBusData* data) if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING) FF_DBUS_ITER_CONTINUE(arrayIterator) - const char* name; - data->ffdbus_message_iter_get_basic(&arrayIterator, &name); + const char* busName; + data->ffdbus_message_iter_get_basic(&arrayIterator, &busName); - if(strncmp(name, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0) + if(strncmp(busName, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0) FF_DBUS_ITER_CONTINUE(arrayIterator) - if(detectSong(name, result, data)) + if(getBusProperties(busName, result, data)) { - ffStrbufAppendS(&result->player, name + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + ffStrbufAppendS(&result->busNameShort, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); break; } FF_DBUS_ITER_CONTINUE(arrayIterator) } + + data->ffdbus_message_unref(reply); } static void getMedia(FFinstance* instance, FFMediaResult* result) @@ -269,9 +318,9 @@ static void getMedia(FFinstance* instance, FFMediaResult* result) } if(instance->config.playerName.length > 0) - getCustomPlayer(instance, result, &data); + getCustomBus(instance, result, &data); else - getBestPlayer(result, &data); + getBestBus(result, &data); dlclose(dbus); } @@ -292,23 +341,66 @@ const FFMediaResult* ffDetectMedia(FFinstance* instance) } init = true; + ffStrbufInit(&result.busNameShort); ffStrbufInit(&result.player); + ffStrbufInit(&result.playerPretty); ffStrbufInit(&result.song); ffStrbufInit(&result.artist); ffStrbufInit(&result.album); + ffStrbufInit(&result.url); #ifdef FF_HAVE_DBUS getMedia(instance, &result); #endif + //Set busNameShort if a custom player was given, but loading dbus failed if(instance->config.playerName.length > 0 && result.player.length == 0) { if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX)) - ffStrbufAppendS(&result.player, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + ffStrbufAppendS(&result.busNameShort, instance->config.playerName.chars + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); else - ffStrbufAppend(&result.player, &instance->config.playerName); + ffStrbufAppend(&result.busNameShort, &instance->config.playerName); + } + + //Set player to busNameShort, if detection failed + if(result.player.length == 0) + ffStrbufAppend(&result.player, &result.busNameShort); + + //If we are on a website, prepend the website name + if(ffStrbufStartsWithS(&result.url, "https://www.")) { + ffStrbufAppendS(&result.playerPretty, result.url.chars + 12); + } + else if(ffStrbufStartsWithS(&result.url, "http://www.")) { + ffStrbufAppendS(&result.playerPretty, result.url.chars + 11); + } + else if(ffStrbufStartsWithS(&result.url, "https://")) { + ffStrbufAppendS(&result.playerPretty, result.url.chars + 8); + } + else if(ffStrbufStartsWithS(&result.url, "http://")) { + ffStrbufAppendS(&result.playerPretty, result.url.chars + 7); + } + + //If we found a website name, make it more pretty + if(result.playerPretty.length > 0) + { + ffStrbufSubstrBeforeFirstC(&result.playerPretty, '/'); //Remove the path + ffStrbufSubstrBeforeLastC(&result.playerPretty, '.'); //Remove the TLD } + //We may have removed everything + bool hasCustomPrettyName = result.playerPretty.length > 0; + + if(hasCustomPrettyName) + { + result.playerPretty.chars[0] = (char) toupper(result.playerPretty.chars[0]); + ffStrbufAppendS(&result.playerPretty, " ("); + } + + ffStrbufAppend(&result.playerPretty, &result.player); + + if(hasCustomPrettyName) + ffStrbufAppendC(&result.playerPretty, ')'); + pthread_mutex_unlock(&mutex); return &result; } diff --git a/src/fastfetch.c b/src/fastfetch.c index 36a945020..25886a0bd 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -304,16 +304,19 @@ static inline void printCommandHelp(const char* command) } else if(strcasecmp(command, "player-format") == 0) { - constructAndPrintCommandHelpFormat("player", "{}", 1, - "Player name" + constructAndPrintCommandHelpFormat("player", "{}", 3, + "Pretty player name", + "Player name", + "DBus bus name" ); } else if(strcasecmp(command, "song-format") == 0) { - constructAndPrintCommandHelpFormat("song", "{2} - {3} - {1}", 3, + constructAndPrintCommandHelpFormat("song", "{2} - {3} - {1}", 4, "Song name", "Artist name", - "Album name" + "Album name", + "Song url" ); } else if(strcasecmp(command, "datetime-format") == 0 || strcasecmp(command, "date-format") == 0 || strcasecmp(command, "time-format") == 0) diff --git a/src/fastfetch.h b/src/fastfetch.h index 88fd2c0a4..25bbafa16 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -257,10 +257,13 @@ typedef struct FFTempsResult typedef struct FFMediaResult { - FFstrbuf player; + FFstrbuf busNameShort; //e.g. plasma-browser-integration + FFstrbuf player; // e.g. Google Chrome + FFstrbuf playerPretty; // e.g. YouTube (Google Chrome) FFstrbuf song; FFstrbuf artist; FFstrbuf album; + FFstrbuf url; } FFMediaResult; typedef struct FFDateTimeResult diff --git a/src/modules/player.c b/src/modules/player.c index e17fd47b7..3a2bd45ae 100644 --- a/src/modules/player.c +++ b/src/modules/player.c @@ -1,7 +1,7 @@ #include "fastfetch.h" #define FF_PLAYER_MODULE_NAME "Media Player" -#define FF_PLAYER_NUM_FORMAT_ARGS 1 +#define FF_PLAYER_NUM_FORMAT_ARGS 3 void ffPrintPlayer(FFinstance* instance) { @@ -16,12 +16,14 @@ void ffPrintPlayer(FFinstance* instance) if(instance->config.playerFormat.length == 0) { ffPrintLogoAndKey(instance, FF_PLAYER_MODULE_NAME, 0, &instance->config.playerKey); - ffStrbufPutTo(&media->player, stdout); + ffStrbufPutTo(&media->playerPretty, stdout); } else { ffPrintFormatString(instance, FF_PLAYER_MODULE_NAME, 0, &instance->config.playerKey, &instance->config.playerFormat, NULL, FF_PLAYER_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, &media->player} + {FF_FORMAT_ARG_TYPE_STRBUF, &media->playerPretty}, + {FF_FORMAT_ARG_TYPE_STRBUF, &media->player}, + {FF_FORMAT_ARG_TYPE_STRBUF, &media->busNameShort} }); } } diff --git a/src/modules/song.c b/src/modules/song.c index e2439e338..c81783e15 100644 --- a/src/modules/song.c +++ b/src/modules/song.c @@ -1,7 +1,7 @@ #include "fastfetch.h" #define FF_SONG_MODULE_NAME "Song" -#define FF_SONG_NUM_FORMAT_ARGS 3 +#define FF_SONG_NUM_FORMAT_ARGS 4 void ffPrintSong(FFinstance* instance) { @@ -36,7 +36,8 @@ void ffPrintSong(FFinstance* instance) ffPrintFormatString(instance, FF_SONG_MODULE_NAME, 0, &instance->config.songKey, &instance->config.songFormat, NULL, FF_SONG_NUM_FORMAT_ARGS, (FFformatarg[]){ {FF_FORMAT_ARG_TYPE_STRBUF, &media->song}, {FF_FORMAT_ARG_TYPE_STRBUF, &media->artist}, - {FF_FORMAT_ARG_TYPE_STRBUF, &media->album} + {FF_FORMAT_ARG_TYPE_STRBUF, &media->album}, + {FF_FORMAT_ARG_TYPE_STRBUF, &media->url} }); } }