#ifdef __APPLE__ #include #include #include #include #include #include #include "../MediaRemote.hpp" #include "../backend.hpp" #define LAUNCH_AGENT_TEMPLATE \ R"( Label {} ProgramArguments {} RunAtLoad AbandonProcessGroup )" std::shared_ptr backend::getMediaInformation() { __block NSString *appName = nil; __block NSDictionary *playingInfo = nil; 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) 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([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, durationMs, elapsedTimeMs); } 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