I'm trying to write an AppleScript to query iCal and find all the events I've got for a given date, in any calendar.
I started by writing a simple script that does something simple with every event in a given calendar:
tell application "iCal"
tell calendar "Reuniones"
set the_events to every event
repeat with an_event in the_events
-- do something with every event
set value to summary of an_event
end repeat
end tell
end tell
However, this simple script is taken a lot of time to execute (a few seconds), even if I'm not doing anything complex inside the loop. I'm afraid that the real script will really take a lot of time to execute.
I'm not very familiar with Applescript, and thus I imagine I'm doing something silly that has severe performance implications.
Can anybody explain me why this takes that much to execute? Can anybody suggest something to improve my code? I'm now going to start checking the date of the event, with a condition in the loop. I suspect there must be a way to search for events with a date (like the Automator action does), but I haven't been able to find a "native" way to do so ....
EDIT: I'm using Mac OS X Tiger (10.4). It is possible that newer versions of iCal have improved the library of operations available.
I've been grappling with this today and found that you can filter by date (at least on Snow Leopard). So
tell application "iCal"
set out to ""
set todaysDate to current date
set time of todaysDate to 0
repeat with c in (every calendar)
set theEvents to (every event of c whose start date ≥ todaysDate)
repeat with current_event in theEvents
set out to out & summary of current_event & "\n"
end repeat
end repeat
return out
end tell
will return the summary of all future events, and very quickly, compared to iterating through all events.
It isn't AppleScript, but the best of the bunch of other ways to do this seems to be iCalBuddy, which uses the public Cocoa APIs rather than parsing the calendar file directly and handles repeating events sensibly.
icalBuddy -nc -eed -iep title,datetime eventsToday+1
My initial intent was to select only the events for a given date, but apparently there aren't methods in iCal to access only the events for a specific day.
Thus, it is always necessary to go over all the events registered in every calendar. Even when interested in the events of a single calendar, say 'Today's Meetings", it is necessary to go through the entire set of events.
The best alternatives I've found around in the web don't use Apple Script, but instead they process the 'ics' files where the info is actually stored.
For reference, those files are located in '~/Library/ApplicationSupport/iCal'.
Related
I want to be able to have a script which can detects if I have new messages in my messaging apps.. Slack, lync,.
Is it possible to use applescript to read if there is any active notification on the apps in the Dock..
If you do:
`getconf DARWIN_USER_DIR`/com.apple.notificationcenter/db
(which line I found at Ask Different), you'll get returned:
/var/folders/_d/pg2g_[some_funny_numbers]/0//com.apple.notificationcenter/db: is a directory
Inside this/my folder I found:
db db-shm db-wal db2upgraded
When some action happens (I sent a notification) only db-wal gets updated (nearly) at once.
So, in principle it should be possible to write an AS (saved as Stay Open app) that periodically looks if "db-wal" has changed (comparing saved sizes or change dates) and, ONLY if so, searches it for some keywords (Slack, lync,…) again comparing # of occurrences, thus learning if s.th. new has arrived. Admittedly sounds awkward but could work.
It would be much more elegant to use a folder script, but as no file is moved nor a folder opened/closed such a script can not be invoked.
I have an excel file on a shared drive used by 6/7 people, however only one person can edit at a time. The frustration comes when one person opens the file for editing then disappears for lunch for an hour, leaving the excel file open and un-editable for other users.
Is it possible for VBA to listen for when a station is locked, and activate a macro accordingly?
Sorry I am not posting any of my own attempts as I'm a bit of a fish out of water with this level of VBA.
Any points that may help get me started would be really useful.
You have a few options:
Kill the co-workers who do this
Have other users create a copy and save-as to then merge latter (quite hacky)
Or you try a timeout - so if the user selects nothing i 10 minutes the workbook closes. Selecting lock would be a issue with security I think and windows wouldnt let you have that kind of power.
So to timeout call a function every ten minutes to check if user has selected any other cells in the worbook.
If difference("n", lastaction , Now) > 10 Then
ThisWorkbook.Close SaveChanges:=True
End If
You can use NOW function in vba to find current date and time and the work out difference with when an action was made to find the value of 'lastaction'. To do this use:
Sub AnAction(ByVal Sh As Object, ByVal Target As Range)
lastaction = now
End Sub
Hopefully that answers your question.
We have a PDF document processing system, implemented in AppleScript (where we call the scripts from the shell using osascript). In some of the scripts, we call Acrobat Preflight Droplets from the Applescript.
This does usually work without problems. However, in some cases, where the processed document is big or/and complex. the droplet returns control to the script before the report is written and the document is moved to the "success" or "failure" folder. The consequence is that the process continues, but without the moved file, it eventually fails.
The workaround so far has been to add a delay after those droplet calls. This does help, but it is a waste of time for small documents, and there will always be a document big and complex enough to take longer than the delay.
We also found out that the time needed for finishing writing the report and moving the document depends on the speed of the system (had to be expected…).
The workaround would be to calculate the delay from the document size, its number of pages, and a machine-dependent parameter. Document size, and number of pages are no big deal; they can be retrieved in the Applescript.
The problem is the machine-dependent parameter, which can be determined experimentally. But how do I make that parameter available to all the scripts needing it?
Incorporating it into the scripts is not an option, because we have a number of systems installed, and if we would do that, we'd end up in a maintenance nightmare. Passing it as an argument in the initial system call is also not possible, because the calls are many, and again would lead to a maintenance nightmare.
So, is there a way to set up a place where that machine parameter can be stored and easily called from any Applescript, no matter how it itself is called.
Thanks a lot for your advice.
You might find the Property List Suite in System Events useful. It’s a standard means of storing and then retrieving such information. Property List files themselves are simply XML files, so you can even create them outside of AppleScript and then read them within your scripts.
There’s a description with examples at https://apple.stackexchange.com/questions/58007/how-do-i-pass-variables-values-between-subsequent-applescript-runs-persistent
A simple suggestion if you only have one paramater to keep track of would be to just have a text file in a known location on each machine. The only content of the text file would be the machine paramater. I like to use the Application Support folder this kind of thing.
Assuming your machine parameter is CPU speed. You can save a text file in /Library/Application Support/Preflight Scripts/machinecpu.txt with the contents:
2.4
Then in Applescript, you would just read the text file.:
set machineParam to read file "Macintosh HD:Library:Application Support:Preflight Scripts:machinecpu.txt"
I have an applescript xcode project in xcode 3.2 and am trying to change the system volume...however it doesn't work...it either stops the nstimer or doesnt do anything at all...
Is there a way to log the errors so that I can pinpoint the issue?
Here is my code
set newVolume to 50
set volume output volume newVolume
textName's setStringValue_(currentVolume)
set currentVolume to newVolume
obv this is a much more condense version but this literally does not work...it is inside of an NSTimer but, even when not within an NSTimer it still does not work...newVolume, currentVolume, and textName are all declared...do I need to declare something for the set volume line?
So, your actual question was simply how to log errors from AppleScriptObjC:
AppleScriptObjC will log any errors thrown in your script to the console -- just look in the bottom pane in Xcode. For instance, in your case you should see something like “«script» doesn’t understand the «aevtstvl» message.” (This isn’t terribly clear, but it’s telling you that your script sent a set volume command to a script object, which didn’t have a handler for it.) If you want to capture and log errors yourself, you can put troublesome sections inside a try/on error block, and deal with it yourself in the error handler.
If you’re feeling extra inquisitive, you can also turn on the NSScriptingDebugLogLevel preference, like this:
defaults write com.me.myapp NSScriptingDebugLogLevel 1
...and AppleScriptObjC will log information about every message sent either way across the bridge. (Set it to 0 or use defaults delete to turn it off.)
That’s error logging. Now, what you didn’t actually ask, but I’m going to answer anyway, was “How do I fix my set volume command?”
Short version: add tell current application to:
tell current application to set volume output volume 50
And yes, the range for the “new” volume parameters is 0 to 100. The old compatibility one goes from 0 to 7. (Why? The old Control Panel volume slider had 8 stops.)
Long version:
There’s a bad interaction between the default direct parameter and set volume’s handling of it. When using AppleScriptObjC, “it”, and therefore the default direct parameter, unless you say otherwise, is the current script, and set volume chokes on that. You can force “it” to be nothing by saying tell current application to. (Alternatively, you could give it an explicit direct parameter by using the old-fashioned form set volume x where x is a real number from 0 to 7. However, this doesn’t match the numbers you get from get volume settings, only lets you set the output volume, and doesn’t let you set things like “muted” correctly.)
And by the way, if your AppleScriptObjC project is sufficiently simple (in particular, if you don’t need any interface), you can write it directly in AppleScript Editor: choose File > New from Template > Cocoa-AppleScript Applet, and use the normal AppleScript on run and on open handlers, except that you can now also invoke anything from Cocoa.
When attempting to load the iTunes XML/plist file, I get "internal table overflow." After Googling, it looks like Applescript has run out of memory. The file is 18 meg on disk, so while on the larger side of things, it should still work on a Mac with 2 gigs.
How can I resolve this?
Obviously, since it's created by iTunes, I can't control the generate of it much.
Update: The relevant snippet:
tell application "System Events"
tell property list file (itunes_xml_file as string)
tell contents
set my_tracks to value of property list item "Tracks"
repeat with t in items of my_tracks
I guess that AppleScript is simply not made to handle this amount of data. I tried to use AppleScript a while back as well and tried to do something similar (reading an iTunes library). AppleScript's original intention was to automate applications by sending AppleEvents to them - which in combination with the weird syntax of AppleScript, confuses a lot and makes it difficult to do a lot of simple things.
After some frustrating time I decided to use Python instead, as it provides a simple module for reading the plist files: http://docs.python.org/dev/library/plistlib.html
Possibly not what you wanted to hear, but the problem with AppleScript is that it is easily overloaded with data, as the abstraction of data it works with is rather bulky and takes up lot of memory.
I'm sure if you give Python a try, you'll have something up and running in less than a hour. Python is installed on all Macs by default and is really easy to learn.
OS version 10.6.8
Update: Confirmation of validity
After initially writing the below I tried to revert the code at hand but could not reproduce the error and hid the post by "deleting" it.
Just now the error happened when loading one non-existant and one existent file-path in an options-parsing script loaded with a load script call, initially handled by run handler, called by the CLI osascript(1) program. This time it is revertible and I feel confident to un-"delete" it.
In short, my solution is to change anyone_else's POSIX file path_posix to AppleScript's POSIX file path_posix
Some relation
After writing the below I now realize that i first only saw "iTunes" and missed the relevant first line with tell app "system events" and the use of it's property list file which perhaps/actually/somehow could be related to my issue with info for a POSIX file.
A note related to OP/question: file or alias as string gives a colon-separated "HFS"-path. System Events handles both.
My issue
In a script-loading script i got error "Internal table overflow." number -2707 from the block below.
It was issued when i called the block's handler using ~IPC~ (app app_name's handler_name()) (when i investigated it more thoroughly but, i had come across it before - without IPC).
try
set file_modified_date to (info for my POSIX file file_path_posix)'s modification date
true
on error error_message number error_number from error_source partial result error_result to error_class
if {error_number} is not in {-43, -37} then error error_message number error_number from error_source partial result error_result to error_class
false
end try
A (the(?)) parent (used for my) of this script, worth mentioning, is current application (with some levels in between) (compiled and bundled in "AppleScript Editor" to be run as a stand-alone .app)
My solution
Changing
set file_modified_date to (info for my POSIX file file_path_posix)'s modification date
to
set file_modified_date to (info for AppleScript's POSIX file file_path_posix)'s modification date
solved the issue - for now.
Thoughts
I'm guessing different ~modules~ has different "tables" (don't now much C) for handling a thing like POSIX file and info for (open "Scripting Addition" / extension (OSAX) "Standard Additions", as it (both) still is, is it not?).
Hope this helps, and that my level of detail (and parentheses) didn't loose or confuse you :) Good night.
Diggin' 'round the cradles
Around the AS memory grave: (Spam prevention made me downgrade all but 2 hyperlinks - give me some rep. and i'll fix it :p)
• The eminent ~has [on this error code] (http://lists.apple.com/archives/applescript-users/2005/Jul/msg00166.html) with a related but perhaps other source (and mentioning his library loader) via list.apple.com.
• Some [good questioning] (http://lists.apple.com/archives/applescript-implementors/2005/Jun/msg00104.html), some to which the below might be a slightly yawning answer:
• cs.cmu.edu provides (120625) a pascal source from 1992 that defines the same limits as my local /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/OpenScripting.framework/Versions/A/Headers/AppleScript.h
• And finally a more distantly related [issue with large scripts] (http://macscripter.net/viewtopic.php?id=11760) from macscripter.net - a good forum of knowledge and collection of resources around applescript.