From 9821b6a294873f975852f06419a0baf2fe404800 Mon Sep 17 00:00:00 2001 From: EinTim23 Date: Sat, 3 May 2025 21:07:39 +0200 Subject: [PATCH] fix mac os 15.4 support because apple restricted the mediaremote to processes that hold internal entitlements --- CMakeLists.txt | 13 ++---- osx/MediaRemote.scptd | 30 ++++++++++++++ src/MediaRemote.hpp | 17 -------- src/backends/darwin.mm | 90 +++++++++++++++++++----------------------- vendor/discord-rpc | 2 +- 5 files changed, 75 insertions(+), 77 deletions(-) create mode 100644 osx/MediaRemote.scptd delete mode 100644 src/MediaRemote.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 20b5237..b1b9be5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ -cmake_minimum_required (VERSION 3.8) +cmake_minimum_required (VERSION 3.12) include("cmake/create_resources.cmake") file(GLOB_RECURSE SOURCES "src/*.cpp") #enable objective c support on mac os, needed for wxwidgets and compile for both intel macs and apple sillicon macs if(APPLE) - list(APPEND SOURCES "src/backends/darwin.mm" ${CMAKE_SOURCE_DIR}/osx/icon.icns) + list(APPEND SOURCES "src/backends/darwin.mm" ${CMAKE_SOURCE_DIR}/osx/icon.icns ${CMAKE_SOURCE_DIR}/osx/MediaRemote.scptd) set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64" CACHE STRING "" FORCE) set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "" FORCE) project ("PlayerLink" LANGUAGES C CXX OBJCXX) @@ -30,16 +30,9 @@ if(WIN32) list(APPEND LIBRARIES WindowsApp) target_link_options(PlayerLink PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup") elseif(APPLE) - set(MEDIAREMOTE_FRAMEWORK_PATH "/System/Library/PrivateFrameworks") - find_library(MEDIAREMOTE_LIBRARY MediaRemote PATHS ${MEDIAREMOTE_FRAMEWORK_PATH}) - if (MEDIAREMOTE_LIBRARY) - message(STATUS "Found MediaRemote: ${MEDIAREMOTE_LIBRARY}") - list(APPEND LIBRARIES ${MEDIAREMOTE_LIBRARY}) - else() - message(FATAL_ERROR "MediaRemote framework not found.") - endif() set_target_properties(PlayerLink PROPERTIES MACOSX_BUNDLE TRUE) set_source_files_properties(${CMAKE_SOURCE_DIR}/osx/icon.icns PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + set_source_files_properties(${CMAKE_SOURCE_DIR}/osx/MediaRemote.scptd PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") set_target_properties(PlayerLink PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/osx/Info.plist) elseif(UNIX AND NOT APPLE) list(APPEND LIBRARIES dbus) diff --git a/osx/MediaRemote.scptd b/osx/MediaRemote.scptd new file mode 100644 index 0000000..02d8ad3 --- /dev/null +++ b/osx/MediaRemote.scptd @@ -0,0 +1,30 @@ +use framework "Foundation" +try + set MediaRemote to current application's NSBundle's bundleWithPath:"/System/Library/PrivateFrameworks/MediaRemote.framework/" + MediaRemote's load() + + set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest") + set bundleID to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()'s bundleIdentifier() + set info to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo() + set title to info's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle" + set album to info's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum" + set artist to info's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist" + set duration to info's valueForKey:"kMRMediaRemoteNowPlayingInfoDuration" + set playbackStatus to info's valueForKey:"kMRMediaRemoteNowPlayingInfoPlaybackRate" + set elapsed to info's valueForKey:"kMRMediaRemoteNowPlayingInfoElapsedTime" + + set jsonString to "{" + set jsonString to jsonString & "\"title\": \"" & title & "\", " + set jsonString to jsonString & "\"album\": \"" & album & "\", " + set jsonString to jsonString & "\"artist\": \"" & artist & "\", " + set jsonString to jsonString & "\"duration\": \"" & duration & "\", " + set jsonString to jsonString & "\"playbackStatus\": \"" & playbackStatus & "\", " + set jsonString to jsonString & "\"elapsed\": \"" & elapsed & "\"," + set jsonString to jsonString & "\"player\": \"" & bundleID & "\"" + set jsonString to jsonString & "}" + return jsonString +on error + set jsonString to "{\"player\": \"none\"}" + return jsonString +end try + diff --git a/src/MediaRemote.hpp b/src/MediaRemote.hpp deleted file mode 100644 index cfda3bb..0000000 --- a/src/MediaRemote.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifdef __APPLE__ -#import - -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoTitle; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoAlbum; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoArtist; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoDuration; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoElapsedTime; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoArtworkData; -FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoPlaybackRate; - -typedef void (^ MRMediaRemoteGetNowPlayingInfoCompletion)(CFDictionaryRef _Nullable information); -typedef void (^ MRMediaRemoteGetNowPlayingApplicationPIDCompletion)(int PID); - -FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingApplicationPID(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingApplicationPIDCompletion _Nullable completion); -FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingInfoCompletion _Nullable completion); -#endif \ No newline at end of file diff --git a/src/backends/darwin.mm b/src/backends/darwin.mm index ee947b0..2ee2231 100644 --- a/src/backends/darwin.mm +++ b/src/backends/darwin.mm @@ -1,12 +1,13 @@ +#include #ifdef __APPLE__ #include #include #include #include #include +#include #include -#include "../MediaRemote.hpp" #include "../backend.hpp" void hideDockIcon(bool shouldHide) { @@ -16,64 +17,55 @@ void hideDockIcon(bool shouldHide) { [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; } +NSString* getFilePathFromBundle(NSString* fileName, NSString* fileType) { + NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:fileType]; + return filePath; +} + +NSString* executeCommand(NSString* command, NSArray* arguments) { + NSTask *task = [[NSTask alloc] init]; + task.launchPath = command; + task.arguments = arguments; + + NSPipe *pipe = [NSPipe pipe]; + task.standardOutput = pipe; + [task launch]; + + NSData *data = [[pipe fileHandleForReading] readDataToEndOfFile]; + NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + [task waitUntilExit]; + + return output; +} + std::shared_ptr backend::getMediaInformation() { - __block NSString *appName = nil; - __block NSDictionary *playingInfo = nil; + static NSString* script = getFilePathFromBundle(@"MediaRemote", @"scptd"); + NSString* output = executeCommand(@"/usr/bin/osascript", @[script]); + nlohmann::json j = nlohmann::json::parse([output UTF8String]); - dispatch_group_t group = dispatch_group_create(); - - dispatch_group_enter(group); - MRMediaRemoteGetNowPlayingApplicationPID(dispatch_get_main_queue(), ^(pid_t pid) { - if (pid > 0) { - NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; - if (app) - appName = [[app.bundleIdentifier copy] retain]; - } - dispatch_group_leave(group); - }); - - dispatch_group_enter(group); - MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef result) { - if (result) - playingInfo = [[(__bridge NSDictionary *)result copy] retain]; - dispatch_group_leave(group); - }); - - dispatch_group_wait(group, DISPATCH_TIME_FOREVER); - dispatch_release(group); - if (appName == nil || playingInfo == nil) + std::string appName = j["player"].get(); + if (appName == "none") return nullptr; - bool paused = [playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoPlaybackRate] intValue] == 0; + bool paused = j["playbackStatus"].get() == "0"; - NSString *title = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle]; - std::string songTitle = title ? [title UTF8String] : ""; + std::string songTitle = j["title"].get(); - NSString *album = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum]; - std::string songAlbum = album ? [album UTF8String] : ""; + std::string songAlbum = j["album"].get(); - NSString *artist = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist]; - std::string songArtist = artist ? [artist UTF8String] : ""; + std::string songArtist = j["artist"].get(); - NSData *artworkData = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData]; + int64_t elapsedTimeMs = 0; + int64_t durationMs = 0; + try { + double durationNumber = std::stod(j["duration"].get()); + durationMs = static_cast(durationNumber * 1000); - std::string thumbnailData; - if (artworkData) - thumbnailData = std::string((const char *)[artworkData bytes], [artworkData length]); + double elapsedTimeNumber = std::stod(j["elapsed"].get()); + elapsedTimeMs = static_cast(elapsedTimeNumber * 1000); + } catch (...) {} - NSNumber *elapsedTimeNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoElapsedTime]; - - NSNumber *durationNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDuration]; - - int64_t elapsedTimeMs = elapsedTimeNumber ? static_cast([elapsedTimeNumber doubleValue] * 1000) : 0; - - int64_t durationMs = durationNumber ? static_cast([durationNumber doubleValue] * 1000) : 0; - - std::string appNameString = appName.UTF8String; - - [appName release]; - [playingInfo release]; - return std::make_shared(paused, songTitle, songArtist, songAlbum, appNameString, thumbnailData, + return std::make_shared(paused, songTitle, songArtist, songAlbum, appName, "", durationMs, elapsedTimeMs); } diff --git a/vendor/discord-rpc b/vendor/discord-rpc index e86d7a8..ca0091c 160000 --- a/vendor/discord-rpc +++ b/vendor/discord-rpc @@ -1 +1 @@ -Subproject commit e86d7a81de7a33323e2038182ab53a26c69f7880 +Subproject commit ca0091c80054e640cbc772160ec594d2ca361db3