1
1
#include " fastfetch.h"
2
2
#include " detection/media/media.h"
3
- #include " common/library.h"
4
3
#include " common/processing.h"
5
- #include " util/apple/cf_helpers.h"
6
- #include " util/apple/osascript.h"
7
- #include " fastfetch_datatext.h"
8
4
9
5
#import < Foundation/Foundation.h>
10
- #import < CoreFoundation/CoreFoundation.h>
11
6
12
- extern void MRMediaRemoteGetNowPlayingInfo (dispatch_queue_t dispatcher, void (^callback)(_Nullable CFDictionaryRef info)) __attribute__((weak_import));
13
- extern void MRMediaRemoteGetNowPlayingClient (dispatch_queue_t dispatcher, void (^callback)(_Nullable id clientObj)) __attribute__((weak_import));
14
- extern CFStringRef MRNowPlayingClientGetBundleIdentifier (id clientObj) __attribute__((weak_import));
15
- extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier (id clientObj) __attribute__((weak_import));
16
- void MRMediaRemoteGetNowPlayingApplicationIsPlaying (dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
7
+ @interface MRContentItem : NSObject <NSCopying >
8
+ @property (nonatomic , readonly , copy ) NSDictionary <NSString*, NSString*>* nowPlayingInfo;
9
+ @end
17
10
18
- static const char * getMediaByMediaRemote (FFMediaResult* result)
19
- {
20
- #define FF_TEST_FN_EXISTANCE (fn ) if (!fn) return " MediaRemote function " #fn " is not available"
21
- FF_TEST_FN_EXISTANCE (MRMediaRemoteGetNowPlayingInfo);
22
- FF_TEST_FN_EXISTANCE (MRMediaRemoteGetNowPlayingClient);
23
- FF_TEST_FN_EXISTANCE (MRNowPlayingClientGetBundleIdentifier);
24
- FF_TEST_FN_EXISTANCE (MRNowPlayingClientGetParentAppBundleIdentifier);
25
- FF_TEST_FN_EXISTANCE (MRMediaRemoteGetNowPlayingApplicationIsPlaying);
26
- #undef FF_TEST_FN_EXISTANCE
11
+ @interface MRClient : NSObject <NSCopying , NSSecureCoding >
12
+ @property (nonatomic , copy ) NSString * bundleIdentifier;
13
+ @property (nonatomic , copy ) NSString * displayName;
14
+ @end
27
15
28
- dispatch_group_t group = dispatch_group_create ();
29
- dispatch_queue_t queue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0 );
30
-
31
- dispatch_group_enter (group);
32
- MRMediaRemoteGetNowPlayingApplicationIsPlaying (queue, ^(BOOL playing) {
33
- ffStrbufSetStatic (&result->status , playing ? " Playing" : " Paused" );
34
- dispatch_group_leave (group);
35
- });
36
-
37
- dispatch_group_enter (group);
38
- __block const char * error = NULL ;
39
- MRMediaRemoteGetNowPlayingInfo (queue, ^(_Nullable CFDictionaryRef info) {
40
- if (info != nil )
41
- {
42
- error = ffCfDictGetString (info, CFSTR (" kMRMediaRemoteNowPlayingInfoTitle" ), &result->song );
43
- if (!error)
44
- {
45
- ffCfDictGetString (info, CFSTR (" kMRMediaRemoteNowPlayingInfoArtist" ), &result->artist );
46
- ffCfDictGetString (info, CFSTR (" kMRMediaRemoteNowPlayingInfoAlbum" ), &result->album );
47
- }
48
- }
49
- else
50
- error = " MRMediaRemoteGetNowPlayingInfo() failed" ;
51
-
52
- dispatch_group_leave (group);
53
- });
16
+ @interface MRPlayerPath : NSObject <NSCopying , NSSecureCoding >
17
+ @property (nonatomic , copy ) MRClient* client;
18
+ @end
54
19
55
- dispatch_group_enter (group);
56
- MRMediaRemoteGetNowPlayingClient (queue, ^(_Nullable id clientObj) {
57
- if (clientObj != nil )
58
- {
59
- CFStringRef identifier = MRNowPlayingClientGetBundleIdentifier (clientObj);
60
- if (identifier == nil )
61
- identifier = MRNowPlayingClientGetParentAppBundleIdentifier (clientObj);
62
- if (identifier != nil )
63
- ffCfStrGetString (identifier, &result->playerId );
64
- }
65
- dispatch_group_leave (group);
66
- });
20
+ @interface MRNowPlayingRequest
21
+ + (bool )localIsPlaying ;
22
+ + (MRContentItem*)localNowPlayingItem ;
23
+ + (MRPlayerPath*)localNowPlayingPlayerPath ;
24
+ @end
67
25
68
- dispatch_group_wait (group, DISPATCH_TIME_FOREVER);
69
- // Don't dispatch_release because we are using ARC
26
+ static const char * getMediaByMediaRemote (FFMediaResult* result)
27
+ {
28
+ if (!NSClassFromString (@" MRNowPlayingRequest" ))
29
+ return " MediaRemote framework is not available" ;
30
+ if (!MRNowPlayingRequest.localNowPlayingItem )
31
+ return " No media found" ;
32
+ ffStrbufSetStatic (&result->status , MRNowPlayingRequest.localIsPlaying ? " Playing" : " Paused" );
70
33
71
- if (result->playerId .length > 0 )
72
- {
73
- char buf[128 ];
74
- snprintf (buf, ARRAY_SIZE (buf), " name of app id \" %s \" " , result->playerId .chars );
75
- ffOsascript (buf, &result->player );
76
- }
34
+ NSDictionary <NSString *, NSString *>* infoDict = MRNowPlayingRequest.localNowPlayingItem .nowPlayingInfo ;
35
+ ffStrbufSetS (&result->song , infoDict[@" kMRMediaRemoteNowPlayingInfoTitle" ].UTF8String );
36
+ ffStrbufSetS (&result->artist , infoDict[@" kMRMediaRemoteNowPlayingInfoArtist" ].UTF8String );
37
+ ffStrbufSetS (&result->album , infoDict[@" kMRMediaRemoteNowPlayingInfoAlbum" ].UTF8String );
77
38
78
- if (result->song .length > 0 )
79
- return NULL ;
39
+ MRClient* bundleObj = MRNowPlayingRequest.localNowPlayingPlayerPath .client ;
40
+ ffStrbufSetS (&result->playerId , bundleObj.bundleIdentifier .UTF8String );
41
+ ffStrbufSetS (&result->player , bundleObj.displayName .UTF8String );
42
+ return NULL ;
43
+ }
80
44
81
- return error;
45
+ __attribute__ ((visibility(" default" ), used))
46
+ int ffPrintMediaByMediaRemote(void )
47
+ {
48
+ FFMediaResult media = {
49
+ .status = ffStrbufCreate (),
50
+ .song = ffStrbufCreate (),
51
+ .artist = ffStrbufCreate (),
52
+ .album = ffStrbufCreate (),
53
+ .playerId = ffStrbufCreate (),
54
+ .player = ffStrbufCreate (),
55
+ };
56
+ if (getMediaByMediaRemote (&media) != NULL )
57
+ return 1 ;
58
+ ffStrbufPutTo (&media.status , stdout);
59
+ ffStrbufPutTo (&media.song , stdout);
60
+ ffStrbufPutTo (&media.artist , stdout);
61
+ ffStrbufPutTo (&media.album , stdout);
62
+ ffStrbufPutTo (&media.playerId , stdout);
63
+ ffStrbufPutTo (&media.player , stdout);
64
+ ffStrbufDestroy (&media.status );
65
+ ffStrbufDestroy (&media.song );
66
+ ffStrbufDestroy (&media.artist );
67
+ ffStrbufDestroy (&media.album );
68
+ ffStrbufDestroy (&media.playerId );
69
+ ffStrbufDestroy (&media.player );
70
+ return 0 ;
82
71
}
83
72
84
- static const char * getMediaByOsascript (FFMediaResult* result)
73
+ static const char * getMediaByAuthorizedProcess (FFMediaResult* result)
85
74
{
75
+ // #1737
76
+ FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF (" import ctypes;ctypes.CDLL('%s ').ffPrintMediaByMediaRemote()" , instance.state .platform .exePath .chars );
86
77
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate ();
87
- // The script must be executed by `/usr/bin/osascript`. `ffOsascript` doesn't work here
78
+
88
79
const char * error = ffProcessAppendStdOut (&buffer, (char * const []) {
89
- " /usr/bin/osascript " ,
90
- " -e " ,
91
- FASTFETCH_DATATEXT_NOWPLAYING ,
80
+ " /usr/bin/python3 " , // Must be signed by Apple. Homebrew python doesn't work
81
+ " -c " ,
82
+ script. chars ,
92
83
nil
93
84
});
94
85
if (error) return error;
@@ -107,7 +98,7 @@ void ffDetectMediaImpl(FFMediaResult* media)
107
98
{
108
99
const char * error;
109
100
if (@available (macOS 15.4 , *))
110
- error = getMediaByOsascript (media);
101
+ error = getMediaByAuthorizedProcess (media);
111
102
else
112
103
error = getMediaByMediaRemote (media);
113
104
if (error) ffStrbufAppendS (&media->error , error);
0 commit comments