Automatisera OS X med Javascript

Kommer du ofta på dig själv med att göra saker du helst skulle automatisera? Har du tittat på Applescript men inte orkat lära dig språket? Använd Javascript istället.

Framför dig har du en hel hög filer som du vill byta namn på och kanske strukturera om. Hur gör du? Den genomsnittliga datoranvändaren gör det förmodligen till ett manuellt söndagsprojekt. Den med något mindre fritid försöker troligtvis hitta något verktyg som löser det. Sedan finns det de som genast i huvudet bryter ner problemet i flera operationer och inser att det går att lösa genom programmering, och dessutom lära sig något på vägen.

De flesta datoranvändare går att kategorisera i tre grupper. De som flyttar filer med dra-och-slapp och klickar i menyer, för att det mappar direkt mot vår mentala modell av problemet. Nästa steg är de som använder alla kortkommandon de hittar för att effektivisera sin vardag eller sitt arbete. Och så den sista gruppen, som ser datorn som en mängd filer med olika tjänster och gränssnitt ovanpå som går att skripta och automatisera.

För den som vill göra som den sista gruppen finns ett antal olika verktyg. För Windows finns Batch och det mer moderna Powershell. Linux har sitt Bash och OS X Applescript. Men sedan OS X Yosemite finns även Javascript direkt integrerat i OS X. Så varför inte lära dig både automatisering och ett av de hetaste programmeringsspråken samtidigt?

Världens mest missförstådda programmeringsspråk

Javascript har av många kallats för "världens mest missförstådda programmeringsspråk". Det beror förmodligen på att Javascript i grunden är helt olikt alla andra större språk, i kombination med att utvecklare från många olika bakgrunder försöker använda språket på lika många sätt. Lägg sedan till de mindre lyckade designvalen och rena buggarna i Javascript som kom med av farten när språket togs fram på 10 dagar, och därefter blivit kvar på grund av webbläsarkompatibilitet.

Anledningen till brådskan var att Netscape, där skaparen Brendan Eich jobbade, annars hade valt Java som inbyggt programmeringsspråk. Att Java var det hetaste språket under andra hälften av 90-talet är också anledningen till namnet Javascript, ren marknadsföring. För språken i sig har ingen relation utan är i grunden helt olika.

Vad är det då som gör Javascript så speciellt om man jämför med andra språk? Det är egentligen inget man behöver känna till för enklare automatiseringsskript, och ett ämne stort nog för en dedikerad text. Men om du känner till klasser och arv från andra språk, glöm dem. I Javascript behöver du inga klasser för att skapa så kallade objekt. Varje objekt har sedan en så kallad "prototyp" som är ett annat objekt, och med denna kedja kan du åstadkomma återanvändning av kod på samma sätt som arv och andra hierarkier.

Med bakgrunden på plats, låt oss hugga tag i det mer praktiska.

Det lättaste sättet att börja experimentera med Javascript och OS X är via en REPL, en akronym för read-eval-print-loop och uttalas "räppell". Detta kommandoradsverktyg fungerar på samma sätt som motsvarande i Python, Ruby och Node. Du matar helt enkelt in instruktioner en och en, varpå resultatet skrivs ut direkt. Öppna terminalen och skriv:

osascript -il JavaScript

Där argumentet "i" står för interaktivt och "l" (litet L) låter dig välja Javascript istället för Applescript. Prova sedan med att skriva:

Application("Safari").running()

Som svarar med true eller false beroende på om Safari körs eller inte. Detta svar är av typen boolean och det kan vi använda för ett villkorstest:

Application("Safari").running() ? console.log("Safari är öppet") : console.log("Safari är inte öppet”)

Bekanta dig med skriptredigeraren

Även om REPL-funktionen är praktisk för att experimentera blir den svårjobbad när du ska skriva längre skript. Då är det dags att öppna Skriptredigeraren som är det inbyggda verktyget i OS X för att skriva och köra skript inom Open Scripting Architecture (OSA).

När du kör igång Skriptredigeraren och skapar ett nytt skript så möts du av ett ganska avskalat gränssnitt. Det ackompanjeras av ett fönster som ger dig snabbåtkomst till dokumentationen för hur olika Apple-program kan skriptas.

Vi bygger på det vi experimenterade med i REPL-funktionen men jobbar denna gång mot Mails skriptgränssnitt. Först skapar vi ett objekt för själva skriptet som vi sedan kan använda för att visa dialogrutor:

var app = Application.currentApplication()
app.includeStandardAdditions = true

Den andra raden anger att vi vill inkludera extra funktionalitet, vilket krävs för att visa dialogrutor. Därefter hämtar vi en referens till Mail:

var Mail = Application("Mail")

Därefter bygger vi samma villkorssats som i REPL-funktionen, men denna gång visar vi meddelandet i en dialogruta och anropar Mails skriptgränssnitt för att starta eller stänga applikationen:

if (Mail.running()) {
	app.displayAlert("Status", {"message": String("Mail körs, avslutar…")})
    Mail.quit()
}
else {
	app.displayAlert("Status", {"message": String("Mail är inte igång, startar…")})
	Mail.checkForNewMail()
}

Notera att displayAlert-metoden tar ett objekt som andra parameter, här bestående av nyckeln "message" som innehåller en textsträng. Det här var lärorikt men inte speciellt användbart. Låt oss bygga något du faktiskt har användning för och dessutom bekanta oss med Automator.

Nu när vi kommit igång med Javascript och Skriptredigeraren så kan vi bygga något vettigt. Häromåret var det väldigt populärt att ta ett självporträtt varje dag och sedan sätta samman till en enda bildserie. Vad sägs om att istället ta en skärmdump på ditt skrivbord en gång om dagen, och sedan mejla denna bild till dig själv.

Det som behöver göras kan sammanfattas i tre punkter:

  1. Anropa kommandoradsprogrammet screencapture som sparar en skärmdump till specificerad sökväg.

  2. Skapa ett mejl med bilden bifogad och skicka detta till valfri e-postadress.

  3. Schemalägg uppgiften så att den körs automatiskt.

Vi vill alltså att ett mejl likt detta ska dimpa ner i inkorgen:

Skapa ett nytt skript i Skriptredigeraren där vi först placerar inställningsvariabler för den e-postadress som ska få mejlet och var skärmdumpen ska sparas:

var sendToEmail = "[email protected]"
var savePicPath = "/Users/andreas/screenshot.jpg"

Därefter skapar vi som tidigare ett objekt för applikationen:

var app = Application.currentApplication()
app.includeStandardAdditions = true

Detta objekt kan vi nu använda för att anropa ett kommandoradsprogram, i detta fall screencapture:

app.doShellScript('screencapture ' + savePicPath)

Nu har bilden fångats och sparats. Nästa steg är att skapa ett nytt e-postmeddelande adresserat till den e-postadress vi sparade i variabeln sendToMail:

Mail = Application('com.apple.Mail')
message = Mail.OutgoingMessage().make()
message.toRecipients.push(Mail.Recipient({ address: sendToEmail }))

Vi kan använda Javascripts Date-objekt för att fånga den aktuella tiden och använda denna i meddelandets ämnesrad och innehåll:

message.subject = "Skärmdump " + Date()
message.content = "Denna skärmdump togs cirka " + Date()

Därefter ska bilden bifogas. Hittills har vi kunnat hålla alltsammans i bakgrunden, men för att bilden ska kunna bifogas måste vi göra meddelandet synligt under ett ögonblick:

message.visible = true
attachment = Mail.Attachment({ fileName: savePicPath })
message.attachments.push(attachment)
message.visible = false

Slutligen kan mejlet skickas:

message.send()

Provkör skriptet direkt i Skriptredigeraren. Om det fungerar är nästa steg att schemalägga skriptet i verktyget Automator. Öppna detta och du möts av en dialogruta där du kan välja olika typer av mallar (tryck Cmd + N om du inte ser dialogen). Välj här Kalender-alarm.

Automator låter dig bygga flöden bestående av olika komponenter. Du ser komponenterna listade till vänster och flödet visualiserat till höger. I den vänstra listan, markera Verktyg och leta sedan upp "Kör Javascript" i underlistan till höger. Dra sedan ut denna komponent i flödet till höger.

När komponenten dyker upp i flödet som en ruta har den en del förifylld Javascriptkod. Rensa bort detta och kopiera över hela din kod vi just skrev från Skriptredigeraren. Tryck därefter Cmd + S och välj ett namn på kalenderhändelsen.

När du sparat kalenderhändelsen sätts den till att köra den aktuella tiden och en gång. Öppna därför Kalender och konfigurera den att köras upprepande gånger på vald tidpunkt.

Du har nu skapat ditt egna lilla spionprogram eller loggboksförare, beroende på hur man ser på det. Att arbeta i Javascript känns nog för de flesta betydligt mer hemvant än Applescript. Men tyvärr har Apple fortfarande mycket bristfällig dokumentation på hur Javascript används i OS X.

Avslutningsvis, låt oss återgå till den allra första meningen i den här texten. Om du fortfarande sitter med en hög filer som du hade hoppats kunna döpa om genom Javascript, ta en titt på denna Github Gist.

Då Apples egna dokumentation för Javascript är i stort sett obefintlig får du istället förlita dig på tredjepartskällor. En sådan är Github-repot JXA Cookbook som ger många exempel på hur du använder Javascript i kombination med OS X skriptmöjligheter.