From bbdeb668d6afa1041e228d296c84a95a037995f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 19 Sep 2022 20:05:23 +0800 Subject: [PATCH] Media: support song detection on macOS --- CMakeLists.txt | 4 +- src/detection/{ => media}/media.h | 1 + src/detection/media/media_apple.m | 63 +++++++++++++++++++ .../{media.c => media/media_linux.c} | 2 +- src/modules/player.c | 2 +- src/modules/song.c | 2 +- src/util/apple/cfdict_helpers.c | 13 ++-- src/util/apple/cfdict_helpers.h | 6 +- 8 files changed, 80 insertions(+), 13 deletions(-) rename src/detection/{ => media}/media.h (94%) create mode 100644 src/detection/media/media_apple.m rename src/detection/{media.c => media/media_linux.c} (99%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d5e37328..88517d6db 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 fa3d22b7c..69d648690 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 000000000..1093c26e0 --- /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 4ef505284..bf166e39e 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 fc3902bd4..097b848ad 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 4d093d894..5f8290039 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 f03c1dcc4..9dd50ba9b 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 cfb1e3c81..c552f6382 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