diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d5e37328e..88517d6dba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -189,7 +189,6 @@ set(LIBFASTFETCH_SRC src/detection/gtk.c src/detection/terminalShell.c src/detection/vulkan.c - src/detection/media.c src/detection/datetime.c src/detection/temps.c src/detection/title.c @@ -253,6 +252,7 @@ if(APPLE) src/detection/terminalfont/terminalfont_apple.c src/util/apple/cfdict_helpers.c src/util/apple/osascript.m + src/detection/media/media_apple.m ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC @@ -264,6 +264,7 @@ elseif(ANDROID) src/detection/memory/memory_linux.c src/detection/displayserver/displayserver_android.c src/detection/terminalfont/terminalfont_android.c + src/detection/media/media_linux.c ) else() list(APPEND LIBFASTFETCH_SRC @@ -279,6 +280,7 @@ else() src/detection/displayserver/linux/xlib.c src/detection/displayserver/linux/wmde.c src/detection/terminalfont/terminalfont_linux.c + src/detection/media/media_linux.c ) endif() diff --git a/src/detection/media.h b/src/detection/media/media.h similarity index 94% rename from src/detection/media.h rename to src/detection/media/media.h index fa3d22b7cb..69d648690d 100644 --- a/src/detection/media.h +++ b/src/detection/media/media.h @@ -13,6 +13,7 @@ typedef struct FFMediaResult FFstrbuf artist; FFstrbuf album; FFstrbuf url; + const char* error; } FFMediaResult; const FFMediaResult* ffDetectMedia(FFinstance* instance); diff --git a/src/detection/media/media_apple.m b/src/detection/media/media_apple.m new file mode 100644 index 0000000000..1093c26e06 --- /dev/null +++ b/src/detection/media/media_apple.m @@ -0,0 +1,63 @@ +#include "fastfetch.h" +#include "detection/media/media.h" +#include "common/library.h" +#include "util/apple/cfdict_helpers.h" + +#import +#import +#import + +void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)); + +const char* getMedia(FFMediaResult* result) +{ + ffStrbufInit(&result->busNameShort); + ffStrbufInit(&result->player); + ffStrbufInit(&result->song); + ffStrbufInit(&result->artist); + ffStrbufInit(&result->album); + ffStrbufInit(&result->url); + + FFstrbuf fake; + ffStrbufInitA(&fake, 0);//MediaRemote is a macOS builtin framework thus its path should not change + + FF_LIBRARY_LOAD( + MediaRemote, + fake, + "dlopen MediaRemote failed", + "/System/Library/PrivateFrameworks/MediaRemote.framework/MediaRemote", + 1); + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(MediaRemote, MRMediaRemoteGetNowPlayingInfo); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + ffMRMediaRemoteGetNowPlayingInfo(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(_Nullable CFDictionaryRef info) { + if(info != nil) { + ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song); + ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist); + ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album); + } + dispatch_semaphore_signal(semaphore); + }); + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + return NULL; +} + +const FFMediaResult* ffDetectMedia(FFinstance* instance) +{ + FF_UNUSED(instance) + static FFMediaResult result; + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + static bool init = false; + + if(!init) + { + pthread_mutex_lock(&mutex); + if(!init) + { + result.error = getMedia(&result); + init = true; + } + pthread_mutex_unlock(&mutex); + } + + return &result; +} diff --git a/src/detection/media.c b/src/detection/media/media_linux.c similarity index 99% rename from src/detection/media.c rename to src/detection/media/media_linux.c index 4ef505284c..bf166e39ec 100644 --- a/src/detection/media.c +++ b/src/detection/media/media_linux.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "detection/media.h" +#include "detection/media/media.h" #include #include diff --git a/src/modules/player.c b/src/modules/player.c index fc3902bd4f..097b848adc 100644 --- a/src/modules/player.c +++ b/src/modules/player.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/media.h" +#include "detection/media/media.h" #include diff --git a/src/modules/song.c b/src/modules/song.c index 4d093d894a..5f82900398 100644 --- a/src/modules/song.c +++ b/src/modules/song.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/media.h" +#include "detection/media/media.h" #include diff --git a/src/util/apple/cfdict_helpers.c b/src/util/apple/cfdict_helpers.c index f03c1dcc45..9dd50ba9b8 100644 --- a/src/util/apple/cfdict_helpers.c +++ b/src/util/apple/cfdict_helpers.c @@ -1,6 +1,6 @@ #include "cfdict_helpers.h" -bool ffCfDictGetString(CFMutableDictionaryRef dict, CFStringRef key, FFstrbuf* result) +bool ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) { CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key); if(cf == NULL) @@ -10,12 +10,13 @@ bool ffCfDictGetString(CFMutableDictionaryRef dict, CFStringRef key, FFstrbuf* r { CFStringRef cfStr = (CFStringRef)cf; uint32_t length = (uint32_t)CFStringGetLength(cfStr); - ffStrbufEnsureFree(result, length + 1); - if(CFStringGetCString(cfStr, result->chars, length + 1, kCFStringEncodingASCII)) + //CFString stores UTF16 characters, therefore may require larger buffer to convert to UTF8 string + ffStrbufEnsureFree(result, length * 2); + if(CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) { - result->length = length; // CFStringGetCString ensures the buffer is NUL terminated // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring + result->length = strnlen(result->chars, (uint32_t)result->allocated); } } else if(CFGetTypeID(cf) == CFDataGetTypeID()) @@ -34,7 +35,7 @@ bool ffCfDictGetString(CFMutableDictionaryRef dict, CFStringRef key, FFstrbuf* r return true; } -bool ffCfDictGetBool(CFMutableDictionaryRef dict, CFStringRef key, bool* result) +bool ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) { CFBooleanRef cf = (CFBooleanRef)CFDictionaryGetValue(dict, key); if(cf == NULL || CFGetTypeID(cf) != CFBooleanGetTypeID()) @@ -44,7 +45,7 @@ bool ffCfDictGetBool(CFMutableDictionaryRef dict, CFStringRef key, bool* result) return true; } -bool ffCfDictGetInt(CFMutableDictionaryRef dict, CFStringRef key, int* result) +bool ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) { CFNumberRef cf = (CFNumberRef)CFDictionaryGetValue(dict, key); if (cf == NULL || CFGetTypeID(cf) != CFNumberGetTypeID()) diff --git a/src/util/apple/cfdict_helpers.h b/src/util/apple/cfdict_helpers.h index cfb1e3c81d..c552f6382e 100644 --- a/src/util/apple/cfdict_helpers.h +++ b/src/util/apple/cfdict_helpers.h @@ -6,8 +6,8 @@ #include "fastfetch.h" #include -bool ffCfDictGetString(CFMutableDictionaryRef dict, CFStringRef key, FFstrbuf* result); -bool ffCfDictGetBool(CFMutableDictionaryRef dict, CFStringRef key, bool* result); -bool ffCfDictGetInt(CFMutableDictionaryRef dict, CFStringRef key, int* result); +bool ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result); +bool ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result); +bool ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result); #endif