Monday, March 25, 2013

Giving an icon to an applescript application

I showed how to save an applescript code as an application in my previous post. In this post I will show how to give a different image to an applescript application to replace the customary apple applet icon. I've already saved one of my codes that opens my gmail web account in safari (check my previous posts) as an app "GMail" on my Desktop.

First thing I did was to choose an icon from google images. Just search for whatever image you'd like to give it to your app. I chose some GMail image that came up in the images search. Then, open the image with preview.

Select the image and copy it to clipboard.




Then, right click on the app you saved and select "Get Info".


Click on the applet icon in the left most corner of the info window that has opened up. You can blue shade around the icon highlighting the fact it has been selected.



After that, just paste the image we've copied onto clipboard from preview by doing command + v. Now, you can see that icon has been changed.


This is what I've got on my Desktop. As you can see the icon of the app has been changed. This looks much better. Right?


Now, you can simply drag this app onto your dock and with one click you have your application running.



Making an app from applescript

This post shows how to make an app from applescript code on your mac.

First, open applescript editor and write/put some applescript code. Press Command + Space bar and type apple and you should applescript editor like shown below.


Save the code in scpt (script) format just in case you'd like to make changes at some point in the future.


Once you're done saving it scpt format, try to save it again by selecting duplicate and then rename it from the arrow mark next to title of the document it self.


Now you should see the app "display" where ever you saved it. I saved it on the Desktop and this is how it looks.


Double clicking on it would make it run like any other application on your Desktop. Since I put the code 'display dialog "Hello! How are you?", running it would show a display dialog with this content like shown below.



App on Mac through applescript to open GMail web account in Safari

Recently, out of curiosity I started writing an applescript code to make an app to login onto my gmail web account. Once I started it I realized there are many things I needed to consider. Here are the different scenarios:

1) One just booted the system. Hence, the app should start Safari, open Gmail login page and then login with credentials stored in a keychain.

2) One has already logged into his gmail account. But, the page has been closed but account hasn't been logged out. In this scenario, app should not enter the username and password as when it tries to open the Gmail login page your Gmail opens up with your inbox with emails since you already logged in before closing the page.

3) You logged out but didn't close the page. Then, after a while you want to log back in. In this case it should not reopen the login page but find the already logged out page that's open and put the credentials.

4) The account is already opened and active in a tab that is not in focus right now. In this situation, app should simply bring this tab to the front.

5) The other case is where Safari is minimized with account is already open but page is closed, is logged out but page is open, etc.

6) Most important thing is to make sure Gmail login page loads before it starts entering username and password.

7) At the same time accessing username and password has to be secure.

8) Multiple windows and tabs are open and the app should cycle through them to find some of the above mentioned cases.

This code covers all these cases. I'm sure there are many more one might come across. For now this is working great for me on my 3 different macs (office iMac, home iMac and Macbook Pro). All these 3 have mountain lion operating system with Safari 6.0.3.

This code uses apple security tool to access the username and password I have stored in a keychain. This makes it very secure unlike storing the password in the script it self (check for one of my previous scripts).

The one important thing one needs to remember is to change the keychain location in the script based on their username. For example, on all my macs my username is manchu and I store the keychain in the default location of /Users/manchu/Library/Keychain. So, if you save it in the default location then you should just change manchu in the above path with your home directory name (the one that has home/house symbol in the finder window on the left pane).

This code ensures that page has successfully loaded by checking whether File --> Save as becomes active in the Safari menu. I'm not sure whether this is the right way but some how it appears to be working ok. I have given 10 seconds for the page to load. If it doesn't happen before that it will let you know that page has failed to load through announcement as well as display dialog. If you don't want your Mac to announce it then hash the lines with "say".

If you'd like to use this script, then make sure you create a keychain with your Gmail login credentials in it and change the path to it in the script below. You can see my post before this one to know how to create a keychain.

Here is the code:


# Applescript to open Gmail account in Safari.
# Written by Sreedhar Manchu.
# Password retrieval from keychain access has been accomplished with the code
# found on www.vickash.com. The page is titled "More Secure Passwords In Applescript"

set IsDefined to true
set theCredentials to getCredentials of ¬
 "GMailPersonal" from "/Users/manchu/Library/Keychains/WebLogins.keychain"
set userName to account of theCredentials
set thePW to password of theCredentials
set theTitle to "" & userName & "@gmail.com - Gmail" as string
if appIsRunning("Safari") then
 tell application "Safari"
  activate
  if windows is not {} then
   activate
   repeat with j from (count of windows) to 1 by -1
    repeat with i from (count of tabs of window j) to 1 by -1
     set thisTab to tab i of window j
     set thePageName to name of thisTab
     #display dialog thePageName
     if thePageName contains theTitle then
      set current tab of window j to thisTab
      set windowNum to j
      set alreadyLogged to true
     end if
    end repeat
   end repeat
  end if
 end tell
end if
try
 get alreadyLogged
on error
 set IsDefined to false
end try
if IsDefined then
 tell application "Safari"
  activate
  set index of window windowNum to 1
 end tell
else
 set IsDefined to true
 set theTitle to "Gmail: Email from Google" as string
 tell application "Safari"
  activate
  if windows is not {} then
   activate
   repeat with j from (count of windows) to 1 by -1
    repeat with i from (count of tabs of window j) to 1 by -1
     set thisTab to tab i of window j
     set thePageName to name of thisTab
     if thePageName is equal to theTitle then
      #set tabNum to i
      set theWindows to windows
      set winOne to item j of theWindows
      if (miniaturized of winOne) then
       #set miniaturized of winOne to false
       activate
       #delay 0.5
      end if
      #set currentTab to item i of tabs of window j
      set currentTab to item i of tabs of winOne
      #set winOne to item j of windows
      set alreadyOpen to true
     end if
    end repeat
   end repeat
  end if
 end tell
 try
  get alreadyOpen
 on error
  set IsDefined to false
 end try
 if IsDefined then
  tell application "Safari"
   activate
   tell winOne
    set index to 1
    set visible to false
    set visible to true
   end tell
   #set thisTab to tab tabNum of window 1
   #set current tab of window 1 to thisTab
   set current tab of window 1 to currentTab
   tell application "System Events"
    keystroke userName
    keystroke tab
    keystroke thePW
    keystroke return
   end tell
  end tell
 else
  tell application "Safari"
   activate
   if windows is not {} then
    tell window 1
     if (miniaturized) then
      set miniaturized to false
     end if
     set current tab to (make new tab with properties {URL:"https://mail.google.com"})
     #set current tab to (make new tab with properties {URL:"http://www.bsnl.co.in"})
    end tell
   else
    tell application "Safari"
     activate
     make new document with properties {URL:"https://mail.google.com"}
    end tell
   end if
  end tell
  if page_loaded(10) then
   set IsDefined to false
   tell application "Safari"
    activate
    #set theURL to URL of current tab of front window as text
    #set thePageName to name of current tab of front window as string
    set thePageName to name of current tab of window 1 as string
    if thePageName as string is equal to "" or thePageName as string is equal to null or thePageName is equal to missing value then
     set pageIsNotLoading to true
    end if
   end tell
   try
    get pageIsNotLoading
   on error
    set IsDefined to true
   end try
   if IsDefined then
    #display dialog thePageName
    set theTitle to "" & userName & "@gmail.com - Gmail" as string
    if thePageName does not contain theTitle then
     tell application "Safari"
      activate
      tell application "System Events"
       keystroke userName
       keystroke tab
       keystroke thePW
       keystroke return
       say "Gmail login has been successful"
      end tell
     end tell
    end if
   else
    say "Either page has failed to load or Gmail is taking time"
    display dialog "Either page has failed to load or Gmail is taking time!"
   end if
  end if
 end if
end if

on page_loaded(timeout_value) -- in seconds
 tell application "System Events"
  tell process "Safari"
   tell menu 1 of menu bar item "File" of menu bar 1
    repeat with i from 1 to timeout_value
     if enabled of menu item "Save as..." is false then
      delay 0.5
     else
      return true
     end if
     if i is timeout_value then
      #set timeoutValue to timeout_value * 0.5
      beep
      display dialog "" & timeout_value * 0.5 & " seconds have elapsed; Either page has failed to load or Gmail is taking time!"
      return false
     end if
    end repeat
   end tell
  end tell
 end tell
end page_loaded

on extractData(theText, theFieldName, theEndDelimiter, spaces)
 set theDataStart to the offset of theFieldName in theText
 if theDataStart = 0 then
  return ""
 else
  set theDataStart to theDataStart + (length of theFieldName) + spaces
  set theData to text theDataStart through end of theText
  set theDataEnd to ((offset of theEndDelimiter in theData) - 1)
  set theData to text 1 through theDataEnd of theData
 end if
end extractData

on getCredentials of theKeychainItem from theKeychain
 set theKeychainPath to (POSIX path of theKeychain) as text
 try
  set theKeychainAlias to (POSIX file theKeychainPath) as alias
  set theKeychainPath to (POSIX path of theKeychainAlias)
 on error
  return "Keychain file not found at specified location: " & ¬
   theKeychain as text
 end try
 try
  set theResult to do shell script ¬
   "security 2>&1 find-generic-password -gs " & ¬
   theKeychainItem & " " & ¬
   quoted form of theKeychainPath
  set theAccount to extractData(theResult, "\"acct\"<blob>=\"", "\"", 0)
  set thePassword to extractData(theResult, "password: \"", "\"", 0)
  return {account:theAccount, password:thePassword}
 on error
  return "Generic password item specifeid does not exist in keychain: " & ¬
   theKeychainItem
 end try
end getCredentials

on appIsRunning(appName)
 tell application "System Events" to (name of processes) contains appName
end appIsRunning

Creating a new keychain on Mac

Recently, I wanted to make an app on my mac for logging onto my gmail account in Safari browser. Once I started looking into applescript I realized best way to use an login credentials is through mac native keychain access. For my GMail applescript I had to make a keychain and this is how I did it. First, open keychain access from applications. Goto File --> New Keychain or selecting New Keychain from the popup that comes up when you right click on the left pane as shown below:

 

I gave a name 'WebLogins' and created in a default location "/Users/manchu/Library/Keychains/"

 

Enter a password for the newly created keychain. This keeps all your username and password combinations we're going to keep in this keychain secure just in case some one got hold of your system.



Now click on WebLogins in the left pane and then click on "+" all the way below immediately next to the left pane. This would ask you to give a name to the item you're going to create. I gave it GMailPersonal as I'm going to use this item for logging onto my GMail web account. For account name I use my GMail username and for Password I use my GMail account password. Save it by clicking "Add".

 

Next step is to change the settings for this Keychain. Right click on "WebLogins" and select 'Change Settings for Keychain "WebLogins"...' as shown below:

 

Since I need my app to access these credentials randomly I uncheck the first item as I don't want to enter the keychain password every time it accesses the keychain. Since I use this to see my gmail it doesn't make sense to uncheck "Lock when sleeping" as I don't need to activate my app either remotely or make it run at certain time in a day (let's say cron job) in my absence.

 

In my applescript I use the tool security to access the username and password from the WebLogins keychain. You'd be asked to either always allow or deny or just one-time allow the security to access the username and password. I go for always allow as I don't want to enter keychain password through out the day.

 

Whenever you logout of or restart the system you will be asked to enter the keychain password as a security feature. As you see security tool is trying to use the password.

 

Saturday, March 23, 2013

Thunderbolt display problem

I have thunderbolt display that goes along with my iMac. Most of the time I don't use this display unless I'm working from home and I need to keep many terminal windows open. But when I don't need this display it looks like I can not turn it off. This means this display is turned on when ever I'm using iMac. I searched online and haven't found a native solution. There is an app SwitchResX that would do this, it seems. But it just doesn't make sense to not to be able to do it. So far, what I have been doing to solve this problem is to plug the thunderbolt cable off the iMac and this would turn the display off. But it's frustrating to do this when you need to do this many times as you need to reach for the cable at the back of the iMac. So, I looked at the SwitchResX and it looks like a great tool if you really need all the functionality it provides. This is not the case for me and so what I'm doing these days is to simply make the display brightness to zero. Just to let you know, when you press brightness key on your keyboard it acts only on your iMac display. In order to reduce or increase the thunderbolt display brightness just press brightness key while holding control key. This would do the trick. In any case, I'd be great if someone could post any other solution that's working out well.

Reduce display brightness and volume by quarter notches on Mac

Sometimes you'd be listening to something on your mac with a volume that corresponds to last bar. Then pressing the volume down for one more time would mute it. But one'd wish that there was something else one could have done to bring it to little less than how it was before but not mute it. Here is the solution:

option + shift + brightness buttons

option + shift + volume buttons

Pressing brightness or volume up/down buttons while holding option and shift down would increase/lower the brightness or volume by quarter notches and there by gives you greater control.

Wednesday, March 20, 2013

Fell in love with this Korean song

My daughter loves to watch "Mator tall tales" on Netflix. I watch it too sitting next to her and I love it. Anyway, one thing that caught my attention is the song that comes at the end of it. First I thought it was a Japanese song and later realized it was Korean and the woman's voice pretty much haunted me until I went and found it on youtube. Looks like whoever posted this video had the same love for it. Here is the song in case you'd like to listen to:

Friday, January 18, 2013

AppleScript to open any web interface/account like GMail, etc

Few years back I switched to Mac and since then I'd say it's been great. Yes, Macs are expensive but they do offer great things in comparison. Anyway, since I'm not doing a sales pitch here I'll go ahead and say how you can automate logging onto any of your web accounts, for example your gmail account. The reason I do this is that I open Google web interface for both email and calendar everyday early in the morning at my work. Eventually, you'd think of doing it with just one click and so I came up with this.

First, open AppleScript editor on your mac and type what I show here below:
tell application "Safari" to open location "https://mail.google.com"
delay 5
tell application "Safari" to activate
tell application "System Events"
 keystroke "username"
 keystroke tab
 keystroke "password"
 keystroke return
end tell
Most of the times usernames and passwords are contain numerals. Entering keystroke "Sreedhar123" for username would just enter "Sreedhar" in the username field without 123 at the end of it. Which I'd say is a problemo. To avoid this from happening we need to enter applescript key codes for the numbers. So, for "Sreedhar123" you need to put this code:
tell application "Safari" to open location "https://mail.google.com"
delay 5
tell application "Safari" to activate
tell application "System Events"
 keystroke "Sreedhar"
        key code 18
        key code 19
        key code 20
 keystroke tab
 keystroke "password"
 keystroke return
end tell
Remember that same goes for password as well. Google "applescript keycodes" if you are looking a keycode for a specific character.


Of course, you can test this script immediately without having to save it by clicking on "Run" in the AppleScript menu. Once your'e satisfied save it as an application by choosing "Application" from the dropdown menu for File Format. You can drag the saved application onto your dock. Clicking it would take you to gmail web interface with just one and only one click. Nice! Right?

Now, remember that once you save it as an app you wouldn't be able to change the code anymore. If you'd like to see or change the code you'll have to save it in Script format by choosing "Script" for File Format which is default. Again, it's a no brainer doing something like this because you've your password exposed. Whereas saving it as an app doesn't expose anything.

Doing this way you can automate logging onto any web interface with just one click there by avoiding typing the web page address, entering the username, password and then entering return.

Finally, as you see I put "delay 5" in the code so that it waits for 5 seconds before trying to enter the username. The reason is that sometimes a page takes 2 to 3 seconds to load. If it takes more than 5 seconds then change this number. Otherwise, nothing happens as applescript goes through the code executing each line. Which means it'll have entered the username and password into something as the page hasn't loaded yet. In the worst case this might end up typing full or partial username and password into the address bar. So, be careful.

Wednesday, January 16, 2013

Making an app with an applescript on your mac that gets you public transit directions


At the end of the day in my office, just before leaving the office I generally check google maps for getting public transit directions and time tables. Google Maps lets you save driving directions with a link "Save to My Maps" under the directions to your "My places". But this is not the case with public transit directions. Which in my opinion sucks. This might sound trivial to some one who uses their car to goto office. Trust me it's a heck of nuisance to someone like me as I use public transit all the time.

Generally, what I do is I open a new tab in my browser and then open the page "maps.google.com" and then click on public transit, then type the addresses, let's say for example home or office if you've saved them or type the entire addresses and then select the train or bus from options based on your public transit mode. Again, it doesn't sound that big of a deal if you have to do this once in a month. But I do this million times in a month. So, I've started looking for some sort of a way to save it to my places.

Whatever I found googling didn't help me at all. In the end I've decided to make an app for my self with an applescript on my mac. Then I thought of putting it here if someone is interested in knowing how I did it. Here we go:

First goto maps.google.com and get the public transit directions for your destination. Let's say we need public transit directions from Hoboken HBLR Terminal to Penn Station, New York, NY. I know that there is a PATH train service that runs from Hoboken to 34th street which is where Penn station. Of course, you don't need to know anything of this at all. As I know I always select the option "train" from show options. Then I get the link to directions from share symbol next to My places. This is what I've got here:

https://maps.google.com/maps?saddr=Hoboken+HBLR+Terminal&daddr=Penn+Station,+New+York,+NY&hl=en&ll=40.740982,-74.011202&spn=0.027411,0.05579&sll=40.740982,-74.012575&sspn=0.027411,0.05579&geocode=Fc-MbQId92SW-yk7lmyP4lnCiTHoGLLYwLjysQ%3BFfTNbQIdlPKW-yELxignjABkPin5tzQUrlnCiTELxignjABkPg&oq=Penn&dirflg=rT&ttype=now&noexp=0&noal=0&sort=def&mra=ls&t=m&z=15&start=0



Once you have this link, go and open applescript editor (Press command + space bar and type applescript) and add this code below and then save it to where ever you want to have it in your system. I put it on my desktop.

Applescript Code:

do shell script "open -a Safari \"https://maps.google.com/maps?saddr=Hoboken+HBLR+Terminal&daddr=Penn+Station,+New+York,+NY&hl=en&ll=40.740982,-74.011202&spn=0.027411,0.05579&sll=40.740982,-74.012575&sspn=0.027411,0.05579&geocode=Fc-MbQId92SW-yk7lmyP4lnCiTHoGLLYwLjysQ%3BFfTNbQIdlPKW-yELxignjABkPin5tzQUrlnCiTELxignjABkPg&oq=Penn&dirflg=rT&ttype=now&noexp=0&noal=0&sort=def&mra=ls&t=m&z=15&start=0\""


The above code opens the tab with public transit directions in Safari.

To open the page in a default browser, just remove -a Safari:

do shell script "open \"https://maps.google.com/maps?saddr=Hoboken+HBLR+Terminal&daddr=Penn+Station,+New+York,+NY&hl=en&ll=40.740982,-74.011202&spn=0.027411,0.05579&sll=40.740982,-74.012575&sspn=0.027411,0.05579&geocode=Fc-MbQId92SW-yk7lmyP4lnCiTHoGLLYwLjysQ%3BFfTNbQIdlPKW-yELxignjABkPin5tzQUrlnCiTELxignjABkPg&oq=Penn&dirflg=rT&ttype=now&noexp=0&noal=0&sort=def&mra=ls&t=m&z=15&start=0\""


Before making it an app you can simply try running it with "Run" on the editor which shows you whether it is working or not. Once you know that it is working the way you wanted it to be go for save options and there select "Application" in the "File Format" drop down menu. Once you save it as application, let's say on your Desktop you can simply drag it onto your Dock.

Once you have it there on the dock you can simply click it just like you open any other application. This opens public transit directions with your selected public transportation mode with the latest time table.

By the way, if you'd like to save your script so that you can modify or refer to in the future then I say save another copy some where in SCPT format by choosing SCPT from File Format drop down menu options.

PBS Script Generator: Interdependent dropdown/select menus in Javascript

PBS SCRIPT GENERATOR
SH/BASH TCSH/CSH
Begin End Abort

About Me

LA, CA, United States
Here I write about the battles that have been going on in my mind. It's pretty much a scribble.

Sreedhar Manchu

Sreedhar Manchu
Higher Education: Not a simple life anymore