diff --git a/CMakeLists.txt b/CMakeLists.txt index 661fbce4c..374974ffc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,11 @@ endif() fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP) fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE) +if(APPLE) + # See src/detection/media/media_apple.m + fastfetch_load_text(src/data/nowPlaying.scptd DATATEXT_NOWPLAYING) +endif() + configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY) configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY) if(APPLE) diff --git a/src/data/nowPlaying.scptd b/src/data/nowPlaying.scptd new file mode 100644 index 000000000..21ce40501 --- /dev/null +++ b/src/data/nowPlaying.scptd @@ -0,0 +1,24 @@ +use scripting additions +use framework "/System/Library/PrivateFrameworks/MediaRemote.framework" + +set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest") + +if MRNowPlayingRequest's localNowPlayingItem() is missing value then + return +end if + +if MRNowPlayingRequest's localIsPlaying() then + set status to "Playing" +else + set status to "Paused" +end if + +set infoDict to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo() +set bundleObj to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client() + +return status & " +" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle" as text) & " +" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist" as text) & " +" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum" as text) & " +" & (bundleObj's bundleIdentifier() as text) & " +" & (bundleObj's displayName() as text) diff --git a/src/detection/media/media_apple.m b/src/detection/media/media_apple.m index 818bf2cbf..1d2356ad2 100644 --- a/src/detection/media/media_apple.m +++ b/src/detection/media/media_apple.m @@ -1,8 +1,10 @@ #include "fastfetch.h" #include "detection/media/media.h" #include "common/library.h" +#include "common/processing.h" #include "util/apple/cf_helpers.h" #include "util/apple/osascript.h" +#include "fastfetch_datatext.h" #import #import @@ -13,7 +15,7 @@ extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribu extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import)); void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import)); -static const char* getMedia(FFMediaResult* result) +static const char* getMediaByMediaRemote(FFMediaResult* result) { #define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available" FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo); @@ -79,8 +81,34 @@ static const char* getMedia(FFMediaResult* result) return error; } +static const char* getMediaByOsascript(FFMediaResult* result) +{ + FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); + // The script must be executed by `/usr/bin/osascript`. `ffOsascript` doesn't work here + const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) { + "/usr/bin/osascript", + "-e", + FASTFETCH_DATATEXT_NOWPLAYING, + nil + }); + if (error) return error; + if (buffer.length == 0) return "No media found"; + + // status\ntitle\nartist\nalbum\nbundleName\nappName + FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player }; + char* line = NULL; + size_t len = 0; + for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i) + ffStrbufSetS(varList[i], line); + return NULL; +} + void ffDetectMediaImpl(FFMediaResult* media) { - const char* error = getMedia(media); - ffStrbufAppendS(&media->error, error); + const char* error; + if (@available(macOS 15.4, *)) + error = getMediaByOsascript(media); + else + error = getMediaByMediaRemote(media); + if (error) ffStrbufAppendS(&media->error, error); } diff --git a/src/fastfetch_datatext.h.in b/src/fastfetch_datatext.h.in index 5c73b9d49..f40367a92 100644 --- a/src/fastfetch_datatext.h.in +++ b/src/fastfetch_datatext.h.in @@ -2,3 +2,7 @@ #define FASTFETCH_DATATEXT_JSON_HELP @DATATEXT_JSON_HELP@ #define FASTFETCH_DATATEXT_STRUCTURE @DATATEXT_STRUCTURE@ + +#ifdef __APPLE__ + #define FASTFETCH_DATATEXT_NOWPLAYING @DATATEXT_NOWPLAYING@ +#endif