Save and restore applications and layout - windows

I'm looking for ways to reduce the wasted time spent to open all the applications needed, position windows, open urls/files/change directories/etc. before actual coding starts.
In the perfect world there would be 2 buttons marked 'SAVE STATE' and 'RESTORE STATE' per 'project'. The kind of feature you find in some games.
I'm on a mac and just spent afew hours banging my head with 'Automator' (which for some reason has problems to even open firefox from the dock) and then applescript (which gives me the feeling i'm in for a long ride).
Searching on the net led me to this script:
http://snipt.net/Fotinakis/applescript-to-save-and-restore-window-positions/
#!/usr/bin/osascript
-- Usage:
-- $ osacompile -o windowPositions.compiled.scpt windowPositions.scpt
-- $ osascript windowPositions.compiled.scpt --save
-- $ osascript windowPositions.compiled.scpt --restore
-- Change this to be the list of windows you want to save/restore
property affectedProcesses : {"Chrome", "Adium", "Eclipse", "Terminal"}
property windowRecord : {}
on run argv
if (count of argv) is equal to 0 then
log "Please specify one of --save or --restore."
return
end if
tell application "System Events"
if (item 1 of argv is equal to "--save") then
set windowRecord to {}
repeat with i from 1 to count affectedProcesses
set end of windowRecord to {0, {}, {}}
end repeat
repeat with p from 1 to count affectedProcesses
set processName to (item p of affectedProcesses)
if exists process processName then
log "Process '" & processName & "' exists"
tell process processName
set numWindows to count windows
set item 1 of item p of windowRecord to numWindows
repeat with i from 1 to numWindows
set end of item 2 of item p of windowRecord to position of window i
set end of item 3 of item p of windowRecord to size of window i
end repeat
end tell
end if
end repeat
else
repeat with p from 1 to count affectedProcesses
set processName to (item p of affectedProcesses)
if exists process processName then
log "Process '" & processName & "' exists"
tell process processName
set numWindows to item 1 of item p of windowRecord
repeat with i from 1 to numWindows
set position of window i to (item i of item 2 of item p of windowRecord)
set size of window i to (item i of item 3 of item p of windowRecord)
end repeat
end tell
end if
end repeat
end if
end tell
end run
It does half the job (resize and position current windows) but falls apart on a multi-monitor multi-desktops setup. There is no contact info for the original author to ask for help or feedback.
Can anyone shed some light on saving and restoring applications and layout? It feels like such a common task that ought to have some helper utilities. The best I have is the 'sleep mode' but it seems I have to to do a full restart every other day and I have different applications and layout for different projects.

This is a feature of Lion (Mac OS X 10.7) ... I wouldn't kill yourself over a feature Apple has seen the need for and has implemented rather seamlessly...

Related

Get data from webpage via Apple script

I'm trying to get the data of Crypto name, Price, and % from the webpage https://www.worldcoinindex.com/
How can i get the % column value via the following scripts?
set theHtml to do shell script "curl -s " & quoted form of "https://www.worldcoinindex.com"
set text item delimiters to {"<tbody>", "</tbody>"}
set tableContents to theHtml's text item 2 # item 2 is the body of the price table
set text item delimiters to {"<h2>"} # site uses new h2 for each currency
set tableChunks to tableContents's text items 2 thru -1
set pasteStr to ""
repeat with aChunk in tableChunks
set text item delimiters to "><span>$ </span><span class=\"span\">"
tell aChunk's text item 1 to set {theSymbol, thePrice} to {first word, last word}
set pasteStr to pasteStr & theSymbol & tab & thePrice & return
end repeat
set the clipboard to pasteStr
Here is an alternate way for your consideration:
Note that this requires Allow JavaScript from Apple Events to be checked on the hidden Develop menu in Safari.
To unhide the hidden Develop menu:
Safari > Preferences… > Advanced > [√] Show Develop menu in menu bar
Example AppleScript code:
tell application "Safari"
make new document ¬
with properties {URL:"https://www.worldcoinindex.com"}
my waitForSafariPageToFinishLoading()
tell front document
set tickerList to {}
set lastPriceList to {}
set percentageList to {}
repeat with i from 0 to 99
set ticker to ¬
do JavaScript ¬
"document.getElementsByClassName('ticker')[" & i & "].innerText;"
copy words of ticker as text to end of tickerList
set lastPrice to ¬
do JavaScript ¬
"document.getElementsByClassName('number pricekoers lastprice')[" & i & "].innerText;"
copy lastPrice to end of lastPriceList
set percentage to ¬
do JavaScript ¬
"document.getElementsByClassName('percentage')[" & i & "].innerText;"
copy percentage to end of percentageList
end repeat
end tell
end tell
set tempListItem to {}
set groupedItemsList to {}
repeat with i from 1 to 100
copy item i of tickerList to end of tempListItem
copy item i of lastPriceList to end of tempListItem
copy item i of percentageList to end of tempListItem
copy tempListItem to end of groupedItemsList
set tempListItem to {}
end repeat
set tabDelimitatedListAsText to ""
repeat with anItem in groupedItemsList
set {TID, AppleScript's text item delimiters} to ¬
{AppleScript's text item delimiters, tab}
set thisItem to text of anItem as text
set AppleScript's text item delimiters to TID
set tabDelimitatedListAsText to ¬
tabDelimitatedListAsText & thisItem & linefeed
end repeat
set the clipboard to tabDelimitatedListAsText
on waitForSafariPageToFinishLoading()
-- # Wait for page to finish loading in Safari.
-- # This works in macOS Catalina and
-- # macOS Big Sur and may need adjusting
-- # for other versions of macOS.
tell application "System Events" to repeat until ¬
exists (buttons of groups of toolbar 1 of window 1 of ¬
process "Safari" whose name = "Reload this page")
delay 0.5
end repeat
end waitForSafariPageToFinishLoading
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.

Applescript - Check if Page Content of URLs List contain THIS_TEXT | Output all these URLs

Trying the following:
My script returns approx. 20 URLs as variable Single_URLs
Check if these URLs contain THIS_TEXT
Keep URL's containing THIS_TEXT
Delete the other URLs from the result
Pure Applescript or Shell.
My example script just checks IF the provided URL contains THIS_TEXT as i could not get any further by now.
--Open Pages
set site_url to "https://teespring.com/shop/CLASSIC-DODGE-CHARGER-MOP?aid=marketplace&tsmac=marketplace&tsmic=search#pid=212&cid=5819&sid=front"
tell application "Safari"
activate
open location site_url
end tell
-- wait until page loaded
property testingString : "CLASSIC DODGE CHARGER" --Text on website to look for
set pageLoaded to false
tell application "Safari"
repeat while pageLoaded is false
set readyState to (do JavaScript "document.readyState" in document 1)
set pageText to text of document 1
if (readyState is "complete") and (pageText contains testingString) then set pageLoaded to true
delay 0.2
end repeat
end tell
-- get number of links
set theLinks to {}
tell application "Safari" to set num_links to (do JavaScript "document.links.length" in document 1)
set linkCounter to num_links - 1
-- retrieve the links
repeat with i from 0 to linkCounter
tell application "Safari" to set end of theLinks to do JavaScript "document.links[" & i & "].href" in document 1
end repeat
theLinks
set nonExcludedURLs to {}
pageLoaded
This is a a charitable project to help Artists not being cheated. Every help is very welcome, Thanks.
Here's a script that would do that with AppleScript:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
on run
set URLFoundItems to {}
set SearchItemsList to {"CLASSIC DODGE CHARGER"}
set URLList to {"https://teespring.com/shop/CLASSIC-DODGE-CHARGER-MOP?aid=marketplace&tsmac=marketplace&tsmic=search#pid=212&cid=5819&sid=front"}
repeat with i from 1 to count of URLList
set URLv to item i of URLList
tell application "Safari"
try
tell window 1
set current tab to (make new tab with properties {URL:URLv})
end tell
on error
make new document with properties {URL:URLv}
end try
set readyState to (do JavaScript "document.readyState" in document 1)
set pageLoaded to false
repeat while pageLoaded is false
set readyState to (do JavaScript "document.readyState" in document 1)
set SearchIn to source of document 1
if (readyState is "complete") and SearchIn ≠ "" then
set pageLoaded to true
else
delay 0.2
end if
end repeat
repeat with z from 1 to count of SearchItemsList
set SearchString to item z of SearchItemsList
set x to offset of SearchString in SearchIn
if x > 0 then
set URLFoundItems to URLFoundItems & URLv & " (" & SearchString & ")" as string
end if
end repeat
tell window 1
close current tab
end tell
end tell
end repeat
return URLFoundItems
end run
I hope this helps.

Why is this AppleScript idle timer not triggering correctly?

I am trying to create a timer that increments at a certain time (in this case, whenever the time is xx:03:24) and sends a notification when it reaches a user-inputted value. Once it does so, it resets the increment and repeats until manually quit.
However, this code is not reliably triggering when it is supposed to. Does anyone have a guess as to why?
on quit
continue quit
end quit
tell application "Notifications Scripting"
set event handlers script path to (path to me)
end tell
global actions, newActions
using terms from application "Notifications Scripting"
on notification activated
tell application "Safari"
activate
set winlist to every window
repeat with win in winlist
set numtabs to 0
try
set tablist to every tab of win
set numtabs to length of tablist
end try
if numtabs is greater than 0 then
repeat with t in tablist
if "fallenlondon.storynexus.com" is in (URL of t as string) then
tell application "System Events"
tell window id (id of win as integer) of application "Safari" to set current tab to tab (index of t as integer)
end tell
end if
end repeat
end if
end repeat
end tell
end notification activated
end using terms from
display dialog "How many actions do you want to build up before being notified?" default answer "1"
set actions to (text returned of result) as number
set newActions to 0
on idle
if ((seconds of (current date)) = 24) and ((minutes of (current date)) mod 10 = 3) then
set newActions to (newActions + 1)
set delayTime to 540
else
set delayTime to 0.5
end if
if newActions ≥ actions then
if newActions = 1 then
tell application "Notifications Scripting" to display notification "Fallen London" message "You have " & newActions & " new action!" sound name "Glass"
else
tell application "Notifications Scripting" to display notification "Fallen London" message "You have " & newActions & " new actions!" sound name "Glass"
end if
set newActions to 0
end if
return delayTime
end idle
I would not expect your idle implementation to work reliably. It is not a precision timing mechanism; therefore the following assumption is unsound:
if ((seconds of (current date)) = 24) and ((minutes of (current date)) mod 10 = 3) then
You're attempting to hit a 1-second window in a 10-minute loop here, and if you miss that window it'll be another 10 minutes till you get to try again.
A reliable way to do it is to store a date representing the time upon which to next trigger, then periodically check if the current date is now after that date and trigger if it does:
to nextTriggerDate() -- returns next xx:x3:23 date
set d to current date
set {d's minutes, d's seconds} to {((d's minutes) div 10 * 10) + 3, 23}
if d < (current date) then set d to d + 10 * minutes
d
end nextTriggerDate
property _triggerDate : nextTriggerDate()
on idle
if (current date) > _triggerDate then
set _triggerDate to nextTriggerDate()
-- DO STUFF HERE...
end if
return 1
end idle
Alternatively, you could use NSTimer via the AppleScript-ObjC bridge, which is designed specifically for this type of task, or set up a launchd script to run an AppleScript on the specified times if you don't want to be tied to a stay-open applet.
I think you have a few things working against you with your code.
First thing to note is that only the code within the idle handler will be called on each idle event. In other words, if you're expecting the main body of your script to run with each idle process, it will not.
try this as an example...
on run
display dialog "hello!" giving up after 3
end run
on idle
display dialog "Idle test!" giving up after 3
return 5
on idle
When you save the code above as a stay open script, you'll get one dialog that says "hello" then you'll get the "Idle test!" message several times, until you quit the script. Remember to save it as "Stay Open"
To fix this, if you expect all the code outside of the idle handler to run, create a custom function from it that you call from your idle handler.
on yourCustomFunction()
-- All the code you want to run prior when the idle function is called
end yourCustomFunction
on idle
yourCustomFunction()
-- any other additional code you want to run here
return 5
end idle
Another thing I'd like to point out. You don't need to tell application "Notifications Scripting", you can just display notification as shown below.
on idle
if ((seconds of (current date)) = 24) and ((minutes of (current date)) mod 10 = 3) then
set newActions to (newActions + 1)
set delayTime to 540
else
set delayTime to 0.5
end if
if newActions ≥ actions then
if newActions = 1 then
display notification "You have " & newActions & " new action!" with title "Fallen London" sound name "Glass"
else
display notification "You have " & newActions & " new actions!" with title "Fallen London" sound name "Glass"
end if
set newActions to 0
end if
return delayTime
end idle
Lastly, I would recommend adding an on run handler rather than just writing your code in the script without it.

Mavericks AppleScript count every desktop always returns 1

I've got a script taken from GitHub that is supposed to set the wallpaper of every desktop to a certain image depending on the time of day. (I have modified it from the original code to include more time ranges, issue shows in both versions)
The script attempts to count the number of desktops in order to change more than just the current desktop. It does this by first telling System Events the following
set theDesktops to a reference to every desktop
And then, in order to loop through every desktop, it does the following:
if ((count theDesktops) > 1) then
repeat with x from 2 to (count theDesktops)
--some code removed, see full code below
end repeat
end if
The issues is that count theDesktops always returns a 1, no matter how many desktops there are, as seen in the following screenshot.
http://ss.kobitate.com/2013-12-28_0922_2.png
What can be done to fix this? Here is the full code
(*
Script by Philip Hutchison, April 2013
http://pipwerks.com
MIT license http://pipwerks.mit-license.org/
This script assumes:
1. You have a folder named "Wallpapers" in your Pictures folder
2. You have a subfolder named "Time of Day" in Wallpapers
3. You have six subfolders inside "Time of Day", with names that match the variables below.
* If you decide to use different folder names, you must change the variables to match the new folder names
4. You have images inside each folder
For example:
/Users/YOUR_USER_NAME/Pictures/Wallpapers/Time of Day/Afternoon Early/image.jpg
GeekTool can execute this script for you at specified intervals. Use this line in the command field:
osascript ~/Pictures/Wallpapers/Time\ of\ Day/wallpaper.scpt
*)
-- BEGIN USER CONFIGURATION
-- supply folder names
set morningEarly to "Morning Early"
set morningLate to "Morning Late"
set afternoonEarly to "Afternoon Early"
set afternoonLate to "Afternoon Late"
set eveningEarly to "Evening Early"
set eveningLate to "Evening Late"
set nightEarly to "Night Early"
set nightLate to "Night Late"
-- for multiple monitor support.
-- set to true to display the same image on all desktops, false to show unique images on each desktop
set useSamePictureAcrossDisplays to true
-- END USER CONFIGURATION
-- get current hour
set h to hours of (current date)
-- set default periodOfDay
set periodOfDay to nightLate
-- change value of periodOfDay based on current time
if (h > 6 and h < 8) then
set periodOfDay to morningEarly
else if (h ≥ 8 and h < 10) then
set periodOfDay to morningLate
else if (h ≥ 10 and h < 12) then
set periodOfDay to afternoonEarly
else if (h ≥ 12 and h < 16) then
set periodOfDay to afternoonLate
else if (h ≥ 16 and h < 18) then
set periodOfDay to eveningEarly
else if (h ≥ 18 and h < 20) then
set periodOfDay to eveningLate
else if (h ≥ 20 and h < 22) then
set periodOfDay to nightEarly
else if (h ≥ 22) then
set periodOfDay to nightLate
end if
-- helper function ("handler") for getting random image
on getImage(folderName)
tell application "Finder"
return some file of folder ("Pictures:Wallpapers:Time of Day:" & folderName) of home as text
end tell
end getImage
tell application "Finder"
-- wrapped in a try block for error suppression
try
-- determine which picture to use for main display
set mainDisplayPicture to my getImage(periodOfDay)
-- set the picture for additional monitors, if applicable
tell application "System Events"
-- get a reference to all desktops
set theDesktops to a reference to every desktop
-- handle additional desktops
if ((count theDesktops) > 1) then
-- loop through all desktops (beginning with the second desktop)
repeat with x from 2 to (count theDesktops)
-- determine which image to use
if (useSamePictureAcrossDisplays is false) then
set secondaryDisplayPicture to my getImage(periodOfDay)
else
set secondaryDisplayPicture to my mainDisplayPicture
end if
-- apply image to desktop
set picture of item x of the theDesktops to secondaryDisplayPicture
end repeat
end if
end tell
-- set the primary monitor's picture
-- due to a Finder quirk, this has to be done AFTER setting the other displays
set desktop picture to mainDisplayPicture
end try
end tell
Edit: Fixed an unrelated mistake I found in the code
This seems to be fixed now. I remember testing this when #KobiTate posted it.
I am now on 10.9.1 but not sure when it was fixed
tell application "System Events"
set theDesktops to count of (a reference to every desktop)
set theDesktops2 to count every desktop
end tell
log "count of (a reference to every desktop) = " & theDesktops
log "count every desktop = " & theDesktops2
Returns:
(count of (a reference to every desktop) = 2)
(count every desktop = 2)

Applescript to change rating of song currently playing in iTunes

I set up an applescript to change the rating of the current song in iTunes and it worked the first few times but now does nothing. Here is the code:
tell application "System Events"
if (name of processes) contains "iTunes" then
set iTunesRunning to true
else
set iTunesRunning to false
end if
end tell
if iTunesRunning then
tell application "iTunes"
repeat with theTrack in (get selection)
set the rating of theTrack to 100
end repeat
end tell
end if
Anyone see any glaring issues in there? FYI, this is attached to a global hotkey, but even opening it in Applescript Editor and hitting "Run" does nothing.
Ack. All I had to was ask to find the answer myself.
tell application "System Events"
if (name of processes) contains "iTunes" then
set iTunesRunning to true
else
set iTunesRunning to false
end if
end tell
if iTunesRunning then
tell application "iTunes"
set rating of current track to 100
end tell
end if
I don't remember where I found this, but it's a more robust version that might help you. I execute it with a key command using FastScripts. It brings up a dialog box prompting you to rate the current song on a scale of 0 to 5 with a default rating of 4.
tell application "Finder"
set frontApp to name of first process whose frontmost is true
end tell
set currTrack to ""
set thisNum to false
tell application "iTunes"
if player state = playing then
set currTrack to current track
set thisName to name of current track
set thisArt to artist of current track
set numList to {"0", "1", "2", "3", "4", "5", "", "Rate All"}
set thisRating to rating of currTrack
set songArt to ("'" & thisName & "' by " & thisArt)
end if
end tell
tell application frontApp
if currTrack = "" then
beep
tell application frontApp
display dialog "There is no song playing in iTunes at this time." buttons "OOPS" default button "OOPS" with icon note
end tell
else
if thisRating ≠ 0 then
set thisRating to 4
set thisList to (choose from list numList with prompt "Select a rating for this song:" & return & songArt & return & "Select \"Rate All\" to apply rating to all matching songs." default items thisRating OK button name "Select" with empty selection allowed and multiple selections allowed)
else
set thisList to (choose from list numList with prompt "Select a rating for this song:" & return & songArt & return & "Select \"Rate All\" to apply rating to all matching songs." OK button name "Select" with empty selection allowed and multiple selections allowed)
end if
end if
end tell
if thisList ≠ false then
--tell application "iTunes"
set thisRating to ""
repeat with i from 1 to count of items of thisList
set thisItem to item i of thisList
if thisItem = "Rate All" then
if thisRating = "" then
display dialog "You must select a rating to apply to this song." buttons "OK" default button "OK" with icon caution
else
tell application "iTunes"
set dataList to {name, artist, album, time} of currTrack
set addSourceData to {time, size, year, bit rate} of currTrack
set matchList to {"Time", "Size", "Year", "Bit Rate"}
set matchDef to (choose from list matchList with prompt "You may choose criteria to match in addition to track name, artist, and album." with multiple selections allowed and empty selection allowed)
if matchDef = {} then set matchDef to false
set trackList to (every track of library playlist 1 whose ((name = item 1 of dataList) and (artist = item 2 of dataList) and (album = item 3 of dataList)))
set trackCount to count of items of trackList
repeat with j from 1 to trackCount
set thisTrack to item j of trackList
set notMatch to false
if matchDef ≠ false then
set addSynchData to {time, size, year, bit rate} of thisTrack
repeat with m from 1 to 4
if ((m = 1) and (matchDef contains "Time")) or ((m = 2) and (matchDef contains "Size")) or ((m = 3) and (matchDef contains "Year")) or ((m = 4) and (matchDef contains "Bitrate")) then
if item m of addSourceData ≠ item m of addSynchData then
set notMatch to true
exit repeat
end if
end if
end repeat
end if
if notMatch = false then
set rating of thisTrack to thisRating
end if
end repeat
if thisRating > 0 then
set thisRating to thisRating / 20 as integer
end if
end tell
display dialog "Rating of " & thisRating & " applied to " & trackCount & " song(s)." buttons "OK" default button "OK" giving up after 3
end if
else
set thisRating to thisItem * 20
tell application "iTunes"
set rating of currTrack to thisRating
end tell
end if
end repeat
--end tell
end if

Resources