Last active
May 16, 2020 07:29
-
-
Save Tatsh/bc8d998452476c3900a6 to your computer and use it in GitHub Desktop.
Example AppleScript in JavaScript.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Send a message to one person by name with Messages.app | |
function sendMessageTo(name, message) { | |
var app = Application('Messages'); | |
var chats = app.chats(); // Get all the chats, regardless of service | |
var theChat; | |
for (var i = 0, len < chats.length; i < len; i++) { | |
chat = chats[i]; | |
if (chat.participants().length > 1) { // Ignore 'rooms' | |
continue; | |
} | |
if (chat.participants()[0].name() === name) { // Compare name shown on buddy list/message list | |
theChat = chat; | |
break; | |
} | |
} | |
app.send(message, {to: theChat}); | |
} | |
// Delete all songs in the iTunes library (not the file, just the database record) | |
function emptyiTunesLibrary() { | |
var app = Application('iTunes') | |
var lib, k; | |
for (k in app['sources']()) { | |
source = app['sources'][k]; | |
if (source.name() === 'Library') { | |
lib = source; | |
break; | |
} | |
} | |
for (k in lib.tracks()) { | |
lib.tracks()[k].delete(); | |
} | |
} | |
// Get a device source object by name from iTunes | |
function getDeviceByName(searchTerm) { | |
var app = Application('iTunes'); | |
var source, k; | |
for (k in app['sources']) { | |
source = app['sources'][k]; | |
if (source.kind() === 'iPod' && source.name() === searchTerm) { | |
return source; | |
} | |
} | |
throw new Exception('No device with name ' + searchTerm); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# use $.printf because that doesn't give an extra new line, unlike console.log | |
ObjC.import 'stdio' | |
ObjC.import 'stdlib' | |
ObjC.import 'AppKit' | |
ObjC.import 'Foundation' | |
NSUTF8StringEncoding = 4 | |
running = false | |
# Check if iTunes is running | |
# First way, equivalent to `ps aux | egrep 'iTunes$'` | |
# pipe = $.NSPipe.pipe | |
# file = pipe.fileHandleForReading # NSFileHandle | |
# task = $.NSTask.alloc.init | |
# task.launchPath = '/bin/ps' | |
# task.arguments = ['aux'] | |
# task.standardOutput = pipe | |
# | |
# task.launch | |
# | |
# data = file.readDataToEndOfFile # NSData | |
# file.closeFile | |
# | |
# data = $.NSString.alloc.initWithDataEncoding(data, NSUTF8StringEncoding) | |
# for line in ObjC.unwrap(data).split '\n' | |
# if /iTunes$/.test line | |
# running = true | |
# break | |
# Second way, with NSWorkspace | |
for app in ObjC.unwrap($.NSWorkspace.sharedWorkspace.runningApplications) | |
# alternative is to unwrap, and this first check is unneccesary: | |
# if ObjC.unwrap(app.bundleIdentifier) == 'com.apple.iTunes' | |
if typeof app.bundleIdentifier.isEqualToString == 'undefined' | |
continue | |
if app.bundleIdentifier.isEqualToString 'com.apple.iTunes' | |
running = true | |
break | |
if not running | |
#$.printf '/me is not playing anything at the moment\n' | |
$.exit 1 | |
itunes = Application 'iTunes' | |
try | |
currentTrack = itunes.currentTrack() | |
catch | |
# No track playing | |
$.exit 0 | |
$.printf "/me is listening to #{ currentTrack.artist() } - #{ currentTrack.name() } (via iTunes)" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ObjC.import 'stdio' | |
ObjC.import 'AppKit' | |
ObjC.import 'Foundation' | |
class FileNotFoundError extends Error | |
class iTunesNotRunningError extends Error | |
class iTunes | |
finder: Application 'Finder' | |
_library: null | |
running: -> | |
for app in ObjC.unwrap($.NSWorkspace.sharedWorkspace.runningApplications) | |
if typeof app.bundleIdentifier.isEqualToString == 'undefined' | |
continue | |
if app.bundleIdentifier.isEqualToString 'com.apple.iTunes' | |
return true | |
return false | |
constructor: -> | |
Object.defineProperty this, 'itunes', { | |
get: => | |
if not @running() | |
$.NSWorkspace.sharedWorkspace.launchAppWithBundleIdentifierOptionsAdditionalEventParamDescriptorLaunchIdentifier( | |
'com.apple.iTunes', | |
$.NSWorkspaceLaunchAsync | $.NSWorkspaceLaunchAndHide, | |
$.NSAppleEventDescriptor.nullDescriptor, | |
null, | |
) | |
return Application('iTunes') | |
} | |
Object.defineProperty this, 'library', { | |
get: => | |
if @_library | |
return @_library | |
for source in @itunes['sources']() | |
if source.name() == 'Library' | |
@_library = source | |
break | |
@_library | |
} | |
Object.defineProperty this, 'currentTrack', { | |
get: => | |
@itunes.currentTrack | |
} | |
deleteOrphanedTracks: -> | |
ret = [] | |
for track in @library.tracks() | |
name = track.name() | |
try | |
loc = track.location() | |
catch | |
$.printf "Removing #{ name }" | |
ret.push track | |
track.delete() | |
continue | |
if not loc or not @finder.exists loc | |
$.printf "Removing #{ name }" | |
ret.push track | |
track.delete() | |
ret | |
# root must be a Finder folder item | |
# finder.home().folders.byName('Music').folders.byName('import'); | |
addTracksAtPath: (root) -> | |
paths = (Path(x.url().replace(/^file\:\/\//, '')) for x in root.entireContents()) | |
@itunes.add paths, {to: @library} | |
# Refresh all tracks in case some changes do not get detected | |
for track in @library.tracks() | |
@itunes.refresh(track) | |
it = new iTunes() | |
dir = it.finder.home().folders.byName('Music').folders.byName('import') | |
console.log 'Deleting orphaned tracks' | |
deleted = it.deleteOrphanedTracks() | |
console.log 'Updating iTunes track list' | |
it.addTracksAtPath dir | |
# Update ratings | |
# Have to use .items for 'hidden' files | |
filePath = dir.items.byName('.ratings').url().replace(/^file\:\/\//, '') | |
ratingsFileData = $.NSString.stringWithContentsOfFileUsedEncodingError(filePath, $.NSUTF8StringEncoding, null) | |
ratings = {} | |
console.log 'Building basename:track hash' | |
for track in it.library.tracks() | |
loc = track.location().toString() | |
loc = ObjC.unwrap($.NSString.stringWithString(loc).lastPathComponent) | |
ratings[loc] = track | |
console.log 'Setting ratings' | |
for line in ObjC.unwrap(ratingsFileData).split '\n' | |
line = line.trim() | |
if not line | |
continue | |
spl = line.split ' ' | |
filename = spl[1].trim() | |
rating = parseInt spl[0], 10 | |
rating /= 5 | |
rating *= 100 | |
if filename not of ratings | |
throw new FileNotFoundError filename | |
ratings[filename]().rating = rating |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ObjC.import 'AppKit' | |
class iTunesNotRunningError extends Error | |
class iTunes | |
finder: Application 'Finder' | |
_library: null | |
running: -> | |
for app in ObjC.unwrap($.NSWorkspace.sharedWorkspace.runningApplications) | |
if typeof app.bundleIdentifier.isEqualToString == 'undefined' | |
continue | |
if app.bundleIdentifier.isEqualToString 'com.apple.iTunes' | |
return true | |
return false | |
constructor: -> | |
Object.defineProperty this, 'itunes', { | |
get: => | |
if not @running() | |
throw new iTunesNotRunningError('iTunes not found to be running') | |
return Application('iTunes') | |
} | |
Object.defineProperty this, 'library', { | |
get: => | |
if @_library | |
return @_library | |
for source in @itunes['sources']() | |
if source.name() == 'Library' | |
@_library = source | |
break | |
@_library | |
} | |
Object.defineProperty this, 'currentTrack', { | |
get: => | |
@itunes.currentTrack | |
} | |
clearOrphanedTracks: -> | |
ret = [] | |
for track in @library.tracks() | |
name = track.name() | |
try | |
loc = track.location() | |
catch | |
$.printf "Removing #{ name }" | |
ret.push track | |
track.delete() | |
continue | |
if not loc or not @finder.exists loc | |
$.printf "Removing #{ name }" | |
ret.push track | |
track.delete() | |
ret | |
# root must be a Finder folder item | |
# finder.home().folders.byName('Music').folders.byName('import'); | |
addTracksAtPath: (root) -> | |
paths = (Path(x.url().replace(/^file\:\/\//, '')) for x in root.entireContents()) | |
@itunes.add paths, {to: @library} | |
# Refresh all tracks in case some changes do not get detected | |
for track in @library.tracks() | |
@itunes.refresh(track) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment