I have a script that’s gotten pretty long, and I want to know if there’s a way to shorten it. It has quite a few repeated sections, and I’ve been reading up on handlers, and if i’m right, handlers can take the repeated sections into 1 or a few lines apiece. Except the entire thing (almost) is contained within a tell command. Does that mean I can’t use handlers? Is there another option? Would it help if I took the entire tell command and broke it up into a bunch of tell/end tells? If you need specifics, my script (or an older version of it) is here: http://macscripter.net/viewtopic.php?id=36366. Thanks.
Handlers are definitely the way to go. If you use them within a “tell” block, you should precede their calls with the word “my” so the call will be passed back to your script rather than to the application which won’t recognize it.
set A to {}
tell application "Finder"
repeat with k from 1 to 2
set end of A to my getText(k)
end repeat
end tell
tell application "System Events"
set end of A to my getText(3)
end tell
to getText(n)
return item n of {"Text_1", "Text_2", "Text_3"}
end getText
A --> {"Text_1", "Text_2", "Text_3"}
A couple of comments on what you’re doing first:
¢ Scripting Safari is much easier than other browsers thanks to its ability to “do javascript”. If you know a bit of javascript and DOM manipulation then you never have to do any “tell System Events to keystroke …” etc.
¢ Youtube videos almost always use AAC audio and personally I prefer to just download the whole video then extract the audio track with ffmpeg to a .m4a file. This means the audio does not get re-encoded so there’s zero loss of quality and no inflation in size. Of course it does mean a somewhat bigger download.
But as for simplifying your code, here are a few tips…
¢ Rather than using repeats like “repeat with numtimes from 1 to 15” where the loop counter variable doesn’t get used, you can just do “repeat 15 times”.
¢ Code like
if condition then
statements
else
if condition2 then
statements
end if
end if
Can be shortened to
if condition then
statements
else if condition2 then
statements
end if
¢ Code like
if condition then
if condition2 then
statements
end if
end if
Can be shortened to
if condition and condition2 then
statements
end if
¢ Code like
if condition then
statement -- (one line)
end if
Can be shortened to
if condition then statement
¢ Text item delimiters! Saving and restoring these is a myth (I think from the days of OS 9). I do not understand why people insist on continuing to do so today. You’re writing your own script, you know when you’re relying on text item delimiters and when you’re not. One script’s text item delimiters does NOT affect another script’s text item delimiters.
Code like
set prevTIDs to text item delimiters of AppleScript
set text item delimiters of AppleScript to "+"
set songs to text items of songs
set text item delimiters of AppleScript to " "
set songs to "" & songs
set text item delimiters of AppleScript to prevTIDs
Can be shortened to
set text item delimiters of AppleScript to "+"
set songs to text items of songs
set text item delimiters of AppleScript to " "
set songs to songs as text
Note also that “of AppleScript” is only necessary when you’re within a tell block.
¢ You have a couple of big sections that tab and return in a search results page. These could be shortened to something like
tell application "System Events"
if doc contains "Translate results into my language" then keystroke tab
if doc contains "did you mean" then keystroke tab
repeat 13 times
keystroke tab
end repeat
keystroke return
end tell
Hope this helps
Wow guys you were sooooo helpful!!! I just learned a ton!! Thank you so much!!
Adam:
I think I understand what you’re saying. I’m a bit confused, but I might be able to figure it out with a bit of experimenting. If you care to help further, it would be nice to have an example from my script. Thanks so much though for your help! You may have given me the 1 clue needed to proceed, and I truly appreciate that! Thanks!!1
gannet:
I’m not sure that switching to Safari with this script would help because I know 0 javascript and nothing about DOM. This is the only language I know anything about besides the very basics of html. For my purpose, the quality isn’t that big of a deal, it’s mostly just getting masses of songs quickly, but thank you. I was trying to figure out how to repeat with a variable so thank you so much for that. For the “elses” and combining “ifs”, I just did that yesterday, actually, so that’s covered, but thanks again. I had seen the combining of “if” “then” to one line but hadn’t thought about it. As for the rest of it…You’re blowing my mind!!! I will put these in tomorrow on my day off! Thank you so much! You have been so helpful and I appreciate it so much! I can’t believe how kind you were to spell it all out for me so I could understand and so clearly too! THANK YOU!!
Because it’s always good practice to to restore any defaults that you change, especially in an environment where your code may incorporate code written by others or where others might incorporate your code into theirs. The principle ” as has already been quoted somewhere else ” is to “Script defensively but courteously.”
What you do in your own scripts is up to you. Beginners should always be taught the right way to do things. It sets them off on the right foot and saves the rest of us having to answer the same old “Why is this happening?” questions year after year.
I have to agree with Nigel because of this situation:
set aValue to "aKey:withvalue
anotherKey:withanotherValue"
return functionA(aValue)
on functionA(aValue)
set text item delimiters of AppleScript to string id 10
set theRow to functionB(text item 1 of aValue) -->will mess things up
set theRow to functionB(text item 2 of aValue) --<for this call
set text item delimiters of AppleScript to ""
return theRow --it shoud be {"anotherKey", "withanotherValue"}
end functionA
on functionB(aValue) --will go wrong
set text item delimiters of AppleScript to ":"
set __textItems to text items of aValue
set text item delimiters of AppleScript to ""
return __textItems
end functionB
I have to admin that I always set delimiters to “” but that’s because it fits the way my programming works so text item delimiters aren’t set in a nested way but alway procedural.
Hm, I’m not sure I agree. If you are in an environment like Nigel says where you’re sharing code around, then yes it may be a good idea. But coding every script you write “courteously, just in case someone might want to copy code from it” seems a bit ridiculous and certainly gets tedious with TIDs. If someone does want to copy code from an arbitrary script, it’s their responsibility to make sure it works within their own script.
My own practice is to always (and only) set TIDs exactly when I need them, without restoring them to anything afterward. I only mentioned it in the interest of helping shorten the script, but I should let him choose his own style
[edit] Just to clarify my comment about OS 9: Prior to 10.5, text item delimiters persisted across all scripts within Script Editor, so it was of some importance to preserve them. I had an idea the situation was worse back on OS 9 but I don’t know for sure.
Speaking of TIDs though, drummerof13 if you’re running on 10.6 or later you can actually do both your text substitutions at once:
set text item delimiters of AppleScript to {"+", tab}
Also, you appear to have a complex way of determining if a page has finished loading. Could you not just do something like this?
repeat while loading of active tab
delay 1
end repeat
(I wish Safari could do this :()
haha thanks gannet for your loading idea. This is my first project using applescript, so I know very little. I had tried something like “if active tab is loading” (in the early stages of this script, but it never seemed to work, so I quickly went for something else. However, sometimes it says it’s done loading, but it’s really not, and it’s also important for me to know what’s on the page in order for the script to know what to do next, so I think i’ll morph both ideas together. Once again, thank you so much for your input. You have been SOOO helpful!!!
A page status 200 for example doesn’t say anything how it is represented on your page. You have to understand that a page status 200 is just the html content like you see in view source. The webkit (html renderer) hasn’t anything done yet, external files linked to this file hasn’t been loaded yet like javascript, images and css files and still the page status is 200. This is normal behaviour because the ‘main’ file is succesfully loaded and completed. Then there is another item named AJAX. AJAX get called when a page load is completed and then they load certain html code into your page.
To determine if a page is loaded you can do the following things with javascript
- check the http status of an image if it’s not loaded then the page load is not completed
- check if an element exists (I use it to check if an ajax request has took place or not)
Thanks DJ, but most of that was over my head, and I found out I can use cURL, so i don’t even need to wait for the pages to load. Thanks though!