Creative way to run any Applescript in Python

Posted on
Mon Apr 20, 2015 1:29 pm
SpencerJRoberts offline
User avatar
Posts: 256
Joined: Dec 09, 2012
Location: Mountain View, CA

Creative way to run any Applescript in Python

This may not be news to programming experts here but I found it super helpful!

I have many legacy applescripts controlling certain things in Indigo that either at the time didn't have Python counterparts or at the time I didn't have the Python skills for. Now that I'm decent with Python I've been slowly going through and eliminating any applescripts I can for future-proofing (since I can't use device id's in applescript) and for more powerful scripting. In my quest to do this I stumbled on this article showing how to easily call an applescript in Python and even pass Python variables mid-applescript.

Essentially you create a Python script that you will store in your Python "site-packages" folder and import it to any script just like any other Python module. Here is the script:

Code: Select all
#!/usr/bin/python

import subprocess

def asrun(ascript):
  "Run the given AppleScript and return the standard output and error."

  osa = subprocess.Popen(['osascript', '-'],
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE)
  return osa.communicate(ascript)[0]

def asquote(astr):
  "Return the AppleScript equivalent of the given string."
 
  astr = astr.replace('"', '" & quote & "')
  return '"{0}"'.format(astr)

Note: The above script is modified from the article for compatibility with Python 2.6

In addition to this, I've now created two other scripts which import this one for control of iTunes and Airfoil through Python. Here's an example where you can pass parameters into your Applescript:

Code: Select all
def playPlaylist(my_playlist):
    ascript = '''
    tell application "iTunes"
        play playlist {0}
    end tell
    '''.format(asquote(my_playlist))
    print ascript
    asrun(ascript)

This wasn't possible before Indigo 6.1 because the str.format() function only works with Python 2.6 and above. If you have more parameters to pass you just add more {}'s with incrementing numbers in them and pass what you want in the format function using asquote (from our applescript.py). ''' {0} {1}'''.format(asquote(someVar1), asquote(someVar2))

With the ability to import these basic scripts as modules I can now easily make Python scripts like this:

Code: Select all
import itunes, airfoil

thisPlaylist = indigo.variables[somevarid].value

airfoil.setSource('iTunes')
airfoil.setVol('string with speaker name', 0)
airfoil.connect('string with speaker name')
itunes.setVol('80')
itunes.stop()
itunes.shuffleOld(thisPlaylist)
itunes.playPlaylist(thisPlaylist)
airfoil.fadeUp('string with speaker name', .33)


Here are the scripts if anyone wants to use them. Note that iTunes changed how it lets you shuffle after version 10, so if you have 10 or older use the shuffleOld() function and if you have 11 or newer use the shuffleOn() and shuffleOff() functions.

Available functions:

itunes.py
playpause()
play()
pause()
stop()
next()
prev()
back() # (will return to beginning of track before going to prev track)
shuffleOn() # (iTunes 11+)
shuffleOff() # (iTunes 11+)
shuffleOld(playlistNameString) # (iTunes 10 and below)
playPlaylist(playlistNameString)
setVol(volumeAsString)

airfoil.py
setSource(sourceString)
disconnectAll()
connect(speakerNameString)
disconnect(speakerNameString)
setVol(speakerNameString, volume_INT)
getVol(speakerNameString)
fadeUp(speakerNameString, volumeToFadeUpTo_INT)
fadeDown(speakerNameString, volumeToFadeDownTo_INT)

Happy to help anyone get started with this if you have questions!

Posted on
Mon Apr 20, 2015 8:05 pm
matt (support) offline
Site Admin
User avatar
Posts: 21416
Joined: Jan 27, 2003
Location: Texas

Re: Creative way to run any Applescript in Python

Excellent tip – thanks! I flagged your original post as sticky so more folks will find it.

Image

Posted on
Mon Apr 20, 2015 9:03 pm
SpencerJRoberts offline
User avatar
Posts: 256
Joined: Dec 09, 2012
Location: Mountain View, CA

Re: Creative way to run any Applescript in Python

Thanks Matt!

Posted on
Tue Jul 11, 2017 7:33 pm
wideglidejrp offline
User avatar
Posts: 555
Joined: Jan 15, 2012
Location: Danbury, CT

Re: Creative way to run any Applescript in Python

I have a working Applescript I run everyday, but I am trying to switch everything to Python. Some things have been easy, others not so easy. The following code was cobbled together through various discussion groups. It works, but I would really like to make it work in Python. So far, I have not been successful. Any assistance would be greatly appreciated.

Code: Select all
set value of variable "pennwood_date" to (items 1 thru -7 of (date string of (current date)) as text) as string
set value of variable "pennwood_day" to (weekday of (current date)) as text
set value of variable "pennwood_month" to (month of (current date)) as text
set theDate to (current date)
set isoDate to theDate as «class isot» as string -- get current iso date/time
log isoDate
set value of variable "pennwood_time" to isoTimeTo12Hour(isoDate)
isoTimeTo12Hour(isoDate)
on isoTimeTo12Hour(isoDateString) -- convert 24-hour time to AM/PM
   set meridiem to " AM"
   set theHour to text 12 thru 13 of isoDateString as number
   if theHour = 12 then set meridiem to " PM"
   if theHour = 0 then set theHour to 12
   if theHour > 12 then set {theHour, meridiem} to {theHour - 12, " PM"}
   return "" & theHour & text 14 thru 16 of isoDateString & meridiem
end isoTimeTo12Hour
set spring to {April, May}
set summer to {June, July, August}
set fall to {September, October, November}
set winter to {December, January, February, March}
if month of (current date) is in spring then
   set value of variable "pennwood_season" to "Spring"
else if month of (current date) is in summer then
   set value of variable "pennwood_season" to "Summer"
else if month of (current date) is in fall then
   set value of variable "pennwood_season" to "Fall"
else if month of (current date) is in winter then         
   set value of variable "pennwood_season" to "Winter"
end if

John R Patrick
Author of
Home Attitude

Posted on
Tue Jul 11, 2017 7:45 pm
FlyingDiver offline
User avatar
Posts: 7213
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Creative way to run any Applescript in Python

wideglidejrp wrote:
I have a working Applescript I run everyday, but I am trying to switch everything to Python. Some things have been easy, others not so easy. The following code was cobbled together through various discussion groups. It works, but I would really like to make it work in Python. So far, I have not been successful. Any assistance would be greatly appreciated.


Forget the AppleScript. Just tell us what you want when it's all done and we'll tell you how to do it in Python. I can't figure out what that script is actually trying to do.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Tue Jul 11, 2017 7:58 pm
wideglidejrp offline
User avatar
Posts: 555
Joined: Jan 15, 2012
Location: Danbury, CT

Re: Creative way to run any Applescript in Python

The AppleScript creates five variables which I use in a number of action groups. The variables are derived from pennwoodDate (2017-07-11 05:37:25.638720) and the recent values are:

pennwood_date = Tuesday, July 11
pennwood_day = Tuesday
pennwood_month = July
pennwood_time = 7:41 AM
pennwood_season = Summer

I use these with Amazon Web Services Polly AI text to speech, so the AM or PM part is important. I agree the AppleScript is weird, but it does work reliably. I am sure Python can do it more simply and elegantly. Thank you for your interest.

John R Patrick
Author of
Home Attitude

Posted on
Tue Jul 11, 2017 8:21 pm
FlyingDiver offline
User avatar
Posts: 7213
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Creative way to run any Applescript in Python

All from https://docs.python.org/2/library/datetime.html

Put in the right variable numbers.
Code: Select all

def season(month):
    seasons = {
        1: "Winter",
        2: "Winter",
        3: "Winter",
        4: "Spring",
        5: "Spring",
        6: "Summer",
        7: "Summer",
        8: "Summer",
        9: "Fall",
        10: "Fall",
        11: "Fall",
        12: "Winter",
    }
    return seasons(month, "Unknown")

import datetime

pennwood_date  = indigo.variables[12345678]
pennwood_day  = indigo.variables[12345678]
pennwood_month  = indigo.variables[12345678]
pennwood_time  = indigo.variables[12345678]
pennwood_season  = indigo.variables[12345678]

now = datetime.datetime.now()

indigo.variable.updateValue(pennwood_date, str(now.strftime("%A, %B %d"))
indigo.variable.updateValue(pennwood_day, str(now.strftime("%A"))
indigo.variable.updateValue(pennwood_month, str(now.strftime("%B"))
indigo.variable.updateValue(pennwood_time, str(now.strftime("%I:%M %p"))
indigo.variable.updateValue(pennwood_season, season(now.month))



I haven't actually tested this code, btw....

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Jul 12, 2017 6:22 am
wideglidejrp offline
User avatar
Posts: 555
Joined: Jan 15, 2012
Location: Danbury, CT

Re: Creative way to run any Applescript in Python

This script does not create the variables. What you have done is used what the AppleScript created. I want to get rid of the Apple Script.

John R Patrick
Author of
Home Attitude

Posted on
Wed Jul 12, 2017 6:31 am
FlyingDiver offline
User avatar
Posts: 7213
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Creative way to run any Applescript in Python

wideglidejrp wrote:
This script does not create the variables. What you have done is used what the AppleScript created. I want to get rid of the Apple Script.


This script does not require the AppleScript in any way. It sets the values of existing Indigo variables. Do you actually need it to create the variables each time? That seems odd.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Jul 12, 2017 6:34 am
wideglidejrp offline
User avatar
Posts: 555
Joined: Jan 15, 2012
Location: Danbury, CT

Re: Creative way to run any Applescript in Python

Yes, they need to be created everyday. That was the purpose of the Apple Script. Also, they need to be in a particular format as I outlined. The Python script needs to do exactly what the Apple Script does. It may do it differently, but it has to do the same functions.

John R Patrick
Author of
Home Attitude

Posted on
Wed Jul 12, 2017 6:47 am
FlyingDiver offline
User avatar
Posts: 7213
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Creative way to run any Applescript in Python

wideglidejrp wrote:
Yes, they need to be created everyday. That was the purpose of the Apple Script. Also, they need to be in a particular format as I outlined. The Python script needs to do exactly what the Apple Script does. It may do it differently, but it has to do the same functions.


Created each time or updated each time? Creating each time would mean deleting them first, which doesn't make any sense. I updated the code a little. Here's the results.

Code: Select all
def season(month):
    seasons = {
        1: "Winter",
        2: "Winter",
        3: "Winter",
        4: "Spring",
        5: "Spring",
        6: "Summer",
        7: "Summer",
        8: "Summer",
        9: "Fall",
        10: "Fall",
        11: "Fall",
        12: "Winter",
    }
    return seasons.get(month, "Unknown")

import datetime

pennwood_date  = indigo.variables[269690833]
pennwood_day  = indigo.variables[7849349]
pennwood_month  = indigo.variables[1170738921]
pennwood_time  = indigo.variables[519400370]
pennwood_season  = indigo.variables[431536702]

now = datetime.datetime.now()

indigo.variable.updateValue(pennwood_date, str(now.strftime("%A, %B %d")))
indigo.server.log("pennwood_date = " + str(pennwood_date.value))
indigo.variable.updateValue(pennwood_day, str(now.strftime("%A")))
indigo.server.log("pennwood_day = " + str(pennwood_day.value))
indigo.variable.updateValue(pennwood_month, str(now.strftime("%B")))
indigo.server.log("pennwood_month = " + str(pennwood_month.value))
indigo.variable.updateValue(pennwood_time, str(now.strftime("%I:%M %p")))
indigo.server.log("pennwood_time = " + str(pennwood_time.value))
indigo.variable.updateValue(pennwood_season, season(now.month))
indigo.server.log("pennwood_season = " + str(pennwood_season.value))


Code: Select all
   Script                          pennwood_date = Wednesday, July 12
   Script                          pennwood_day = Wednesday
   Script                          pennwood_month = July
   Script                          pennwood_time = 08:44 AM
   Script                          pennwood_season = Summer

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Posted on
Wed Jul 12, 2017 7:29 am
DaveL17 offline
User avatar
Posts: 6753
Joined: Aug 20, 2013
Location: Chicago, IL, USA

Re: Creative way to run any Applescript in Python

Hi John - I agree with Joe. It doesn't seem efficient to delete and recreate the same variables every day. Why not just update their values?

If you must recreate them every day, here is code that check to see if a variable already exists, and if not, create it.

Code: Select all
if "pennwood_date" not in indigo.variables:
    indigo.variable.create("pennwood_date", "", folder='Optional')

indigo.variable.updateValue(pennwood_date, str(now.strftime("%A, %B %d")))

if you don't use variable folders, you can delete the comma and everything that follows (except for the closing parentheses).

I came here to drink milk and kick ass....and I've just finished my milk.

[My Plugins] - [My Forums]

Posted on
Wed Jul 12, 2017 9:06 am
RogueProeliator offline
User avatar
Posts: 2501
Joined: Nov 13, 2012
Location: Baton Rouge, LA

Re: Creative way to run any Applescript in Python

Yes, they need to be created everyday. That was the purpose of the Apple Script. Also, they need to be in a particular format as I outlined. The Python script needs to do exactly what the Apple Script does. It may do it differently, but it has to do the same functions.

I think that you are misunderstanding the Python that Jon wrote -- what he wrote does put the variables in the particular format that your AppleScript was doing; he is directly assigning the values to Indigo variables. Your AppleScript was not creating new Indigo variables each run, at least not what you posted.

Adam

Posted on
Wed Jul 12, 2017 9:09 am
jay (support) offline
Site Admin
User avatar
Posts: 18219
Joined: Mar 19, 2008
Location: Austin, Texas

Re: Creative way to run any Applescript in Python

That AppleScript doesn't create the variables - it just updates variables that are already there. Looks to me like FlyingDiver's script produces the same results.

John, I highly recommend that you go through one of the many Python 2 beginner tutorials out on the net - it will give you the foundation to read the python scripts that others help you with. We all were Python newbies at one point and the tutorials helped accelerate our learning experience significantly.

Jay (Indigo Support)
Twitter | Facebook | LinkedIn

Posted on
Wed Jul 12, 2017 9:18 am
FlyingDiver offline
User avatar
Posts: 7213
Joined: Jun 07, 2014
Location: Southwest Florida, USA

Re: Creative way to run any Applescript in Python

The only thing my script might need is some code to remove leading zeros from hours or dates. But I really doubt having the zeros there would change the TTS results.

joe (aka FlyingDiver)
my plugins: http://forums.indigodomo.com/viewforum.php?f=177

Who is online

Users browsing this forum: No registered users and 3 guests