Skip to content

Instantly share code, notes, and snippets.

@SKaplanOfficial
Last active March 24, 2026 14:43
Show Gist options
  • Select an option

  • Save SKaplanOfficial/f9f5bdd6455436203d0d318c078358de to your computer and use it in GitHub Desktop.

Select an option

Save SKaplanOfficial/f9f5bdd6455436203d0d318c078358de to your computer and use it in GitHub Desktop.
AppleScript and JXA scripts to get Now Playing info. Works on macOS 15.4+, including macOS 26 beta 1.
function run() {
const MediaRemote = $.NSBundle.bundleWithPath('/System/Library/PrivateFrameworks/MediaRemote.framework/');
MediaRemote.load
const MRNowPlayingRequest = $.NSClassFromString('MRNowPlayingRequest');
const appName = MRNowPlayingRequest.localNowPlayingPlayerPath.client.displayName;
const infoDict = MRNowPlayingRequest.localNowPlayingItem.nowPlayingInfo;
const title = infoDict.valueForKey('kMRMediaRemoteNowPlayingInfoTitle');
const album = infoDict.valueForKey('kMRMediaRemoteNowPlayingInfoAlbum');
const artist = infoDict.valueForKey('kMRMediaRemoteNowPlayingInfoArtist');
return `${title.js}${album.js}${artist.js} | ${appName.js}`;
}
use framework "AppKit"
on run
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 appName to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()'s displayName()
set infoDict to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo()
set title to (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle") as text
set album to (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum") as text
set artist to (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist") as text
return title & " - " & album & " - " & artist & " | " & appName
end run
@SKaplanOfficial
Copy link
Copy Markdown
Author

@kreatoo In case it's still relevant: seems MediaRemote can't do it, but MediaPlayer can (but only for Music.app, I think).

use framework "Foundation"
use framework "MediaPlayer"
use scripting additions

-- Get the system-wide music player
set player to current application's MPMusicPlayerController's systemMusicPlayer()

-- Get item for the current track
set nowPlayingItem to player's nowPlayingItem()

if nowPlayingItem is not missing value then
	-- Get artwork as 500x500px PNG image
	set artworkImage to nowPlayingItem's artwork()'s imageWithSize:{500, 500}
	set imageRep to (artworkImage's representations()'s objectAtIndex:0)
	set artworkData to imageRep's representationUsingType:(current application's NSPNGFileType) |properties|:(missing value)
	
	-- Output to downloads directory
	set filePath to POSIX path of (path to downloads folder) & "artwork.png"
	artworkData's writeToFile:filePath atomically:false
else
	return false
end if

JXA equivalent:

(() => {
	ObjC.import('MediaPlayer');
	
	// Get the system-wide music player
	const player = $.MPMusicPlayerController.systemMusicPlayer;
	
	// Get item for the current track
	const currentTrack = player.nowPlayingItem.item;
	
	if (currentTrack) {
		// Get artwork as 500x500px PNG image
		const artworkImage = currentTrack.artwork.imageWithSize((500,500));
		const artworkData = artworkImage.representations.objectAtIndex(0).representationUsingTypeProperties($.NSPNGFileType, $({}));
		
		// Output to downloads directory
		return artworkData.writeToFileAtomically(`${Application('System Events').downloadsFolder.posixPath()}/artwork.png`, false);
	} else {
		return false;
	}
})()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment