mac os backend implementation

This commit is contained in:
EinTim23 2024-11-05 15:22:28 +01:00
parent 8a6ff3db12
commit 84e4250a7f
3 changed files with 99 additions and 33 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
build/* build/*
.DS_Store .DS_Store
.cache/*
src/rsrc.hpp src/rsrc.hpp
PlayerLink.exe PlayerLink.exe

View File

@ -1,25 +1,17 @@
// #ifdef __APPLE__
// MediaRemote.h
// MusicRPC
//
// Created by Alexandra Aurora Göttlicher
//
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoDidChangeNotification;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoTitle; FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoTitle;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoAlbum; FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoAlbum;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoArtist; FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoArtist;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoDuration; FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoDuration;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoElapsedTime; FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoElapsedTime;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoArtworkData;
FOUNDATION_EXPORT CFStringRef _Nullable kMRMediaRemoteNowPlayingInfoPlaybackRate;
typedef void (^ MRMediaRemoteGetNowPlayingInfoCompletion)(CFDictionaryRef _Nullable information); typedef void (^ MRMediaRemoteGetNowPlayingInfoCompletion)(CFDictionaryRef _Nullable information);
typedef void (^ MRMediaRemoteGetNowPlayingApplicationPIDCompletion)(int PID); typedef void (^ MRMediaRemoteGetNowPlayingApplicationPIDCompletion)(int PID);
typedef void (^ MRMediaRemoteGetNowPlayingApplicationIsPlayingCompletion)(Boolean isPlaying);
FOUNDATION_EXPORT void MRMediaRemoteRegisterForNowPlayingNotifications(dispatch_queue_t _Nullable queue);
FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingApplicationPID(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingApplicationPIDCompletion _Nullable completion); FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingApplicationPID(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingApplicationPIDCompletion _Nullable completion);
FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingInfoCompletion _Nullable completion); FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingInfoCompletion _Nullable completion);
FOUNDATION_EXPORT void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t _Nullable queue, MRMediaRemoteGetNowPlayingApplicationIsPlayingCompletion _Nullable completion); #endif

View File

@ -1,32 +1,105 @@
#ifdef __APPLE__ #ifdef __APPLE__
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h> #include <AppKit/AppKit.h>
#include <Foundation/Foundation.h>
#include <dispatch/dispatch.h> #include <dispatch/dispatch.h>
#include <filesystem>
#include <format>
#include <fstream>
#include "../MediaRemote.hpp" #include "../MediaRemote.hpp"
#include "../backend.hpp" #include "../backend.hpp"
#define LAUNCH_AGENT_TEMPLATE \
R"(<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>{}</string>
<key>ProgramArguments</key>
<array>
<string>{}</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>AbandonProcessGroup</key>
<true/>
</dict>
</plist>)"
std::shared_ptr<MediaInfo> backend::getMediaInformation() { std::shared_ptr<MediaInfo> backend::getMediaInformation() {
std::string appName = ""; __block NSString *appName = nil;
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSDictionary *playingInfo = nil;
MRMediaRemoteGetNowPlayingApplicationPID(dispatch_get_main_queue(), ^(pid_t pid) {
if (pid > 0) { dispatch_group_t group = dispatch_group_create();
NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
if (app) dispatch_group_enter(group);
appName = app.bundleIdentifier MRMediaRemoteGetNowPlayingApplicationPID(dispatch_get_main_queue(), ^(pid_t pid) {
} if (pid > 0) {
dispatch_semaphore_signal(semaphore); NSRunningApplication *app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
}); if (app)
MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef result) { appName = [[app.bundleIdentifier copy] retain];
if (result) {
NSDictionary *playingInfo = (__bridge NSDictionary *)(result);
NSLog(@"Now Playing Info: %@", playingInfo);
} }
dispatch_semaphore_signal(semaphore); dispatch_group_leave(group);
}); });
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_group_enter(group);
dispatch_release(semaphore); MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef result) {
return nullptr; 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)
return nullptr;
bool paused = [playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoPlaybackRate] intValue] == 0;
NSString *title = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle];
std::string songTitle = title ? [title UTF8String] : "";
NSString *album = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum];
std::string songAlbum = album ? [album UTF8String] : "";
NSString *artist = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist];
std::string songArtist = artist ? [artist UTF8String] : "";
NSData *artworkData = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData];
std::string thumbnailData;
if (artworkData)
thumbnailData = std::string((const char *)[artworkData bytes], [artworkData length]);
NSNumber *elapsedTimeNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoElapsedTime];
NSNumber *durationNumber = playingInfo[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDuration];
int64_t elapsedTimeMs = elapsedTimeNumber ? static_cast<int64_t>([elapsedTimeNumber doubleValue] * 1000) : 0;
int64_t durationMs = durationNumber ? static_cast<int64_t>([durationNumber doubleValue] * 1000) : 0;
std::string appNameString = appName.UTF8String;
[appName release];
[playingInfo release];
return std::make_shared<MediaInfo>(paused, songTitle, songArtist, songAlbum, appNameString, thumbnailData,
durationMs, elapsedTimeMs);
} }
bool backend::toggleAutostart(bool enabled) { return false; } bool backend::toggleAutostart(bool enabled) {
std::filesystem::path launchAgentPath = std::getenv("HOME");
launchAgentPath = launchAgentPath / "Library" / "LaunchAgents" / "PlayerLink.plist";
if (!enabled && std::filesystem::exists(launchAgentPath)) {
std::filesystem::remove(launchAgentPath);
return true;
}
NSString *binaryPath = [[[NSProcessInfo processInfo] arguments][0] stringByStandardizingPath];
std::string formattedPlist = std::format(LAUNCH_AGENT_TEMPLATE, "PlayerLink", binaryPath.UTF8String);
std::ofstream o(launchAgentPath);
o.write(formattedPlist.c_str(), formattedPlist.size());
o.close();
return true;
}
#undef LAUNCH_AGENT_TEMPLATE
#endif #endif