Skip to content

Commit 9821b6a

Browse files
committed
fix mac os 15.4 support because apple restricted the mediaremote to processes that hold internal entitlements
1 parent 8fb4af3 commit 9821b6a

5 files changed

Lines changed: 73 additions & 75 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
cmake_minimum_required (VERSION 3.8)
1+
cmake_minimum_required (VERSION 3.12)
22
include("cmake/create_resources.cmake")
33

44
file(GLOB_RECURSE SOURCES "src/*.cpp")
55

66
#enable objective c support on mac os, needed for wxwidgets and compile for both intel macs and apple sillicon macs
77
if(APPLE)
8-
list(APPEND SOURCES "src/backends/darwin.mm" ${CMAKE_SOURCE_DIR}/osx/icon.icns)
8+
list(APPEND SOURCES "src/backends/darwin.mm" ${CMAKE_SOURCE_DIR}/osx/icon.icns ${CMAKE_SOURCE_DIR}/osx/MediaRemote.scptd)
99
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE)
1010
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "" FORCE)
1111
project ("PlayerLink" LANGUAGES C CXX OBJCXX)
@@ -30,16 +30,9 @@ if(WIN32)
3030
list(APPEND LIBRARIES WindowsApp)
3131
target_link_options(PlayerLink PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
3232
elseif(APPLE)
33-
set(MEDIAREMOTE_FRAMEWORK_PATH "/System/Library/PrivateFrameworks")
34-
find_library(MEDIAREMOTE_LIBRARY MediaRemote PATHS ${MEDIAREMOTE_FRAMEWORK_PATH})
35-
if (MEDIAREMOTE_LIBRARY)
36-
message(STATUS "Found MediaRemote: ${MEDIAREMOTE_LIBRARY}")
37-
list(APPEND LIBRARIES ${MEDIAREMOTE_LIBRARY})
38-
else()
39-
message(FATAL_ERROR "MediaRemote framework not found.")
40-
endif()
4133
set_target_properties(PlayerLink PROPERTIES MACOSX_BUNDLE TRUE)
4234
set_source_files_properties(${CMAKE_SOURCE_DIR}/osx/icon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
35+
set_source_files_properties(${CMAKE_SOURCE_DIR}/osx/MediaRemote.scptd PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
4336
set_target_properties(PlayerLink PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/osx/Info.plist)
4437
elseif(UNIX AND NOT APPLE)
4538
list(APPEND LIBRARIES dbus)

osx/MediaRemote.scptd

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use framework "Foundation"
2+
try
3+
set MediaRemote to current application's NSBundle's bundleWithPath:"/System/Library/PrivateFrameworks/MediaRemote.framework/"
4+
MediaRemote's load()
5+
6+
set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest")
7+
set bundleID to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()'s bundleIdentifier()
8+
set info to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo()
9+
set title to info's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle"
10+
set album to info's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum"
11+
set artist to info's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist"
12+
set duration to info's valueForKey:"kMRMediaRemoteNowPlayingInfoDuration"
13+
set playbackStatus to info's valueForKey:"kMRMediaRemoteNowPlayingInfoPlaybackRate"
14+
set elapsed to info's valueForKey:"kMRMediaRemoteNowPlayingInfoElapsedTime"
15+
16+
set jsonString to "{"
17+
set jsonString to jsonString & "\"title\": \"" & title & "\", "
18+
set jsonString to jsonString & "\"album\": \"" & album & "\", "
19+
set jsonString to jsonString & "\"artist\": \"" & artist & "\", "
20+
set jsonString to jsonString & "\"duration\": \"" & duration & "\", "
21+
set jsonString to jsonString & "\"playbackStatus\": \"" & playbackStatus & "\", "
22+
set jsonString to jsonString & "\"elapsed\": \"" & elapsed & "\","
23+
set jsonString to jsonString & "\"player\": \"" & bundleID & "\""
24+
set jsonString to jsonString & "}"
25+
return jsonString
26+
on error
27+
set jsonString to "{\"player\": \"none\"}"
28+
return jsonString
29+
end try
30+

src/MediaRemote.hpp

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/backends/darwin.mm

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
#include <Foundation/NSObjCRuntime.h>
12
#ifdef __APPLE__
23
#include <AppKit/AppKit.h>
34
#include <Cocoa/Cocoa.h>
45
#include <Foundation/Foundation.h>
56
#include <dispatch/dispatch.h>
67
#include <filesystem>
8+
#include <nlohmann-json/single_include/nlohmann/json.hpp>
79
#include <fstream>
810

9-
#include "../MediaRemote.hpp"
1011
#include "../backend.hpp"
1112

1213
void hideDockIcon(bool shouldHide) {
@@ -16,64 +17,55 @@ void hideDockIcon(bool shouldHide) {
1617
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
1718
}
1819

19-
std::shared_ptr<MediaInfo> backend::getMediaInformation() {
20-
__block NSString *appName = nil;
21-
__block NSDictionary *playingInfo = nil;
22-
23-
dispatch_group_t group = dispatch_group_create();
24-
25-
dispatch_group_enter(group);
26-
MRMediaRemoteGetNowPlayingApplicationPID(dispatch_get_main_queue(), ^(pid_t pid) {
27-
if (pid > 0) {
28-
NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
29-
if (app)
30-
appName = [[app.bundleIdentifier copy] retain];
31-
}
32-
dispatch_group_leave(group);
33-
});
34-
35-
dispatch_group_enter(group);
36-
MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef result) {
37-
if (result)
38-
playingInfo = [[(__bridge NSDictionary *)result copy] retain];
39-
dispatch_group_leave(group);
40-
});
41-
42-
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
43-
dispatch_release(group);
44-
if (appName == nil || playingInfo == nil)
45-
return nullptr;
20+
NSString* getFilePathFromBundle(NSString* fileName, NSString* fileType) {
21+
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType];
22+
return filePath;
23+
}
4624

47-
bool paused = [playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoPlaybackRate] intValue] == 0;
25+
NSString* executeCommand(NSString* command, NSArray* arguments) {
26+
NSTask *task = [[NSTask alloc] init];
27+
task.launchPath = command;
28+
task.arguments = arguments;
4829

49-
NSString *title = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle];
50-
std::string songTitle = title ? [title UTF8String] : "";
30+
NSPipe *pipe = [NSPipe pipe];
31+
task.standardOutput = pipe;
32+
[task launch];
5133

52-
NSString *album = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum];
53-
std::string songAlbum = album ? [album UTF8String] : "";
34+
NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile];
35+
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
36+
[task waitUntilExit];
37+
38+
return output;
39+
}
5440

55-
NSString *artist = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist];
56-
std::string songArtist = artist ? [artist UTF8String] : "";
41+
std::shared_ptr<MediaInfo> backend::getMediaInformation() {
42+
static NSString* script = getFilePathFromBundle(@"MediaRemote", @"scptd");
43+
NSString* output = executeCommand(@"/usr/bin/osascript", @[script]);
44+
nlohmann::json j = nlohmann::json::parse([output UTF8String]);
5745

58-
NSData *artworkData = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData];
46+
std::string appName = j["player"].get<std::string>();
47+
if (appName == "none")
48+
return nullptr;
5949

60-
std::string thumbnailData;
61-
if (artworkData)
62-
thumbnailData = std::string((const char *)[artworkData bytes], [artworkData length]);
50+
bool paused = j["playbackStatus"].get<std::string>() == "0";
6351

64-
NSNumber *elapsedTimeNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoElapsedTime];
52+
std::string songTitle = j["title"].get<std::string>();
6553

66-
NSNumber *durationNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDuration];
54+
std::string songAlbum = j["album"].get<std::string>();
6755

68-
int64_t elapsedTimeMs = elapsedTimeNumber ? static_cast<int64_t>([elapsedTimeNumber doubleValue] * 1000) : 0;
56+
std::string songArtist = j["artist"].get<std::string>();
6957

70-
int64_t durationMs = durationNumber ? static_cast<int64_t>([durationNumber doubleValue] * 1000) : 0;
58+
int64_t elapsedTimeMs = 0;
59+
int64_t durationMs = 0;
60+
try {
61+
double durationNumber = std::stod(j["duration"].get<std::string>());
62+
durationMs = static_cast<int64_t>(durationNumber * 1000);
7163

72-
std::string appNameString = appName.UTF8String;
64+
double elapsedTimeNumber = std::stod(j["elapsed"].get<std::string>());
65+
elapsedTimeMs = static_cast<int64_t>(elapsedTimeNumber * 1000);
66+
} catch (...) {}
7367

74-
[appName release];
75-
[playingInfo release];
76-
return std::make_shared<MediaInfo>(paused, songTitle, songArtist, songAlbum, appNameString, thumbnailData,
68+
return std::make_shared<MediaInfo>(paused, songTitle, songArtist, songAlbum, appName, "",
7769
durationMs, elapsedTimeMs);
7870
}
7971

vendor/discord-rpc

0 commit comments

Comments
 (0)