Convert PDF to JPEG using (old version of) Acrobat

This script will use Acrobat’s built in conversion settings (set in Acrobat’s preferences) to convert an open PDF to a new JPEG file and place that file in the folder of said PDF. If a file with the same name (including extension) exists it will prompt for a new name, at which point you may enter a new name or keep it the same and replace the old file.

Not allowing Acrobat to name the new file because, on Macintosh, Acrobat has a ridiculously low character limit when auto-generating a file.

Has not been tested with multi-page PDF’s, but I do not think it will handle them correctly [it does not]. Acrobat will do it, but the extra file shuffling will not. Also unknown if having a window (document) minimized will cause any shenanigans.

Also note this is written for Acrobat 7. Why? Because old hardware needs old software.

[UPDATE] Changed to allow multiple selections.

tell application "Adobe Acrobat 7.0 Professional"
try
set _docs to name of every document
if (count of _docs) is greater than 1 then
set _docs to (choose from list _docs with prompt "Select file(s) to convert:" with multiple selections allowed) as list
end if
repeat with i in _docs
set _doc to (every document whose name is i)
set _path to file alias of item 1 of _doc
set _temp to (path to temporary items folder as text) & "acrobat_tmp_jpg"
save item 1 of _doc to file _temp using conversion "com.adobe.acrobat.jpeg"
tell application "Finder"
set _name to (text items 1 thru -5 of i) & ".jpg"
set _proof to ((container of file _path) as text) & _name
if (exists _proof) then
set _name to text returned of (display dialog "File '" & _name & "' already exists. Please enter a new name (or leave the same to replace):" default answer _name as text)
set _proof to ((container of file _path) as text) & _name
end if
do shell script "mv " & quoted form of POSIX path of _temp & " " & quoted form of POSIX path of _proof
reveal file _proof
end tell
end repeat
end try
end tell

Speaking against the media narrative of motor vehicle collisions

As a once/sometime/hopefully again vehicular cyclist, a father, and a driver who tries to change my own attitude toward driving and motor vehicles, I consider myself part of the Crash Not Accident crowd. And this is my comment/rant on a recent article about a “truck getting into an accident with a pedestrian” (to paraphrase it).

Genericized and placed here for possible future use. This may be expanded on at some point.

Drivers don’t get cited because society gives us a pass. That’s starting to change but we need publications like this one to get on board. When describing a collision involving a motor vehicle do not attribute it to the vehicle. The truck didn’t hit the pedestrian, the driver did.

Also, drop the term “accident.” When an outside force is not involved these crashes and wrecks are *never* an accident. Faulty manufacturing, poor maintenance, and especially lack of due care while driving are all 100% preventable by a person making a better choice. The smoldering wreckage and broken bodies of a motor vehicle collision are consequences, not accidents.

Driving is by far the most dangerous thing most people will ever do. It’s past time to (once again) see it for what it is. Maybe then tens of thousands of people wouldn’t be killed year after year after year.

Video re-encode script

The purpose of this long, arduous venture was to find a way to simply reduce the size of video files recorded with a Canon ELPH 330 HS digicam. This camera, and surely others, records 720p, 30fps video at a bitrate of 24Mbps, which is at least twice as much as should be necessary. Remember this is a consumer level point-&-shoot whose main draws were: 10x optical zoom; pocketable. This high bitrate results in a 6 minute video being over 1GB. Too much.
Continue reading

Copy video create date from original file

This is the companion script for: Video re-encode script

It uses exiftool to copy the video date atom(s) and setfile (is or was included with Apple’s Developer Tools) to change the file system dates. It will more than likely throw exiftool “File not found” errors and I’m not quite sure why. It has never failed to actually work despite this in my experience, however be very careful to not use this on your original source videos.

Hopefully the settings and prompts make sense.

(* http://strawhousepig.net/

This uses Apple's command line developer tools command 'setfile' to set the filesytem dates.

https://developer.apple.com/download/more/

I believe an Apple Developer account is required for that, but I am not sure.

Uses 'exiftool' to set track date atoms.

https://www.sno.phy.queensu.ca/~phil/exiftool/

*)

-- Set to 'false' to omit initial dialog prompts. Does not affect final confirmation prompt.
property prompt_me : true

-- UTC timezone. Leave blank ("") to not use the timezone setting.
property tzone : "-8:00"

on run
do_it(false)
end run

on do_it(redo)
repeat
if tzone is not "" then set tzone to "-timezone=\"" & tzone & "\" " -- There is a trailing space here.
if prompt_me is true then
if button returned of (display dialog "Choose a TARGET file to set creation and modification dates of.") is "OK" then
set newfile to choose file with prompt "Select TARGET file to set creation and modified dates of:"
end if
else
set newfile to choose file with prompt "Select TARGET file to set creation and modified dates of:"
end if

set filepath to newfile as string
if prompt_me is true then
if button returned of (display dialog "Choose a SOURCE file to *get* creation and modification dates from.") is "OK" then
set oldfile to choose file with prompt "Select SOURCE file to get dates from: " & filepath
end if
else
set oldfile to choose file with prompt "Select SOURCE file to get dates from: " & filepath
end if
set newfilename to name of (info for of newfile)
if newfilename is not (name of (info for of oldfile)) then
set warn_button to button returned of (display alert "File names do not match. Proceed?" as warning buttons {"Cancel", "Start Over", "Proceed"})
if warn_button is "Cancel" then
return
else
if warn_button is "Start Over" then
set redo to true
exit repeat
end if
end if
end if
tell application "System Events" to set [c_date, m_date] to [creation date of oldfile, modification date of oldfile]
set [p_date_c, p_date_m] to [c_date, m_date] -- Saving "pretty" date for dialog prompt.
set c_date to ((month of c_date as integer) & "/" & day of c_date & "/" & year of c_date & " " & hours of c_date & ":" & minutes of c_date & ":" & seconds of c_date) as string
log c_date
set m_date to ((month of m_date as integer) & "/" & day of m_date & "/" & year of m_date & " " & hours of m_date & ":" & minutes of m_date & ":" & seconds of m_date) as string
log m_date
if button returned of (display dialog "This will set the creation and modification dates of file " & filepath & " to:" & return & return & p_date_c & return & p_date_m & return & return & "Proceed?") is "OK" then
try
-- Have to include full path to exiftool binary because AppleScript uses the Bourne shell which doesn't have /usr/local/bin in its path? *rolls eyes*
do shell script "/usr/local/bin/exiftool " & tzone & "-*date=\"`/usr/local/bin/exiftool -time:CreateDate " & quoted form of POSIX path of oldfile & "`\" -wm w " & quoted form of POSIX path of newfile
on error theErr
-- Will throw a "File not found" error if this takes over a certain amount of time. rm must be running faster than exiftool can finish?
display dialog "The 'exiftool' command said: " & theErr
end try
delay 1
try
-- Ready for this, exiftool adds "_original" to the end of the file it's going to modify tags/atoms of. This is still 'newfile' but with a new name.
-- If we manually add "_original" to 'newfile' rm will throw an error looking for newfile_original_original... Wha?
do shell script "rm " & quoted form of POSIX path of newfile
on error theErr
display dialog "The 'rm' command said: " & theErr
end try
delay 1
try
-- Ready again? The original path to 'newfile' is valid again for this... Wha??
do shell script "setfile -d '" & c_date & "' -m '" & m_date & "' " & quoted form of POSIX path of newfile
on error theErr
display dialog "The 'setfile' command said: " & theErr
end try
end if
exit repeat
end repeat
if redo then do_it(false)
end do_it

Cyclists behaving badly? Riding group won’t share the road [Because there isn’t room to]- YouTube

This “news” piece is a disgusting example of stoking motorist elitism and violent attitudes. I feel a few things need to be made straight:

  • There is not room for a car and a bicycle to safely share those lanes side-by-side. Repeat that.
  • Taking the lane is done to cause a motorist to not try to squeeze past with their multiple ton metal box in a lane that does not accommodate that safely. Slowing down and waiting for a safe opportunity to pass will take, what? 10 seconds? 20? 30 or 60? How many minutes would it take for you to be comfortable with someone risking the rest of your life and your family’s lives without you? I’m guessing there isn’t any number at which anyone would be, so don’t risk that of anyone else for the same. Just slow down, be patient and hope others treat you with at least that basic amount of human decency.
  • By riding abreast a large group significantly reduces its length and likewise the time and distance it takes to overtake them. Imagine trying to pass a single file line of 20 bicycles that must ride in the center of the lane due to lack of safe space. That part of British Columbia’s Motor Vehicle Act should be changed for everyone’s benefit.
  • No one stops at stop signs. Whether people walk, ride, or drive people go right on through whenever they feel they have the chance. This is not a cyclist thing, it’s a people thing. The only difference is when a motorist does it it is dangerous for everyone around them. Every time. This article does a good job of introducing a study from the University of South Florida which reflects this point.
  • On that point, imagine how happy the average angry motorists would be to have to sit and wait for 20 bicycles in front of them to each come to the complete stop motorists only demand of cyclists? Yet it will only take a few seconds for the whole group to follow the leader. There’s no need to imagine that, though. In San Francisco, people on bikes do just that occasionally.

I hope the shortsighted producer(s) at CTV who made this video trash is ashamed of the hateful, violent comments it’s drawn. Because I guarantee someone they love and who means the world to them, or someone that person loves, will face the violent hatred of a motorist someday for the simple act of riding a bicycle. Same goes for those commenters.

All it takes is a little empathy and considerate thought about the way things work to see you owe the world around you the utmost care while operating a machine as dangerous as a motor vehicle and that, no, a motor vehicle does imbue you with privilege above others.

Walk down a directory to label (and reveal) zero byte files

_count is not working and I’m not sure why. :/

The walkFolder() function is recursive, so be careful where you choose to run this. Made to help identify corrupt old archives that have been copied (and copied) from Mac to WINDOWS to CDs and back.

on walkFolder(f, _count)
list folder f
repeat with i in the result
set _item to (alias (f & i))
if folder of (info for _item) then
walkFolder(f & i & ":", _count)
else
if first character of i is not "." then
if size of (info for _item) is 0 then
tell application "Finder"
set label index of _item to 7 -- Gray. Perhaps adding a spotlight comment would be better...
reveal _item -- Comment this out if you expect a lot of results.
end tell
set _count to _count + 1
end if
end if
end if
end repeat
return _count
end walkFolder

on run {}
set _count to 0
try
tell application "Finder" to set cwd to folder of window 1 as alias
on error
set cwd to path to desktop folder
end try
set theFolder to (choose folder "Select a folder to list:" default location cwd) as string
my walkFolder(theFolder, _count)
display dialog (_count as text) & " files found to be 0 bytes" giving up after 600
end run

Apologies for formatting errors as I’m editing this post on Safari from OS X 10.5 which doesn’t work well with WordPress’ auto-drafting.

AppleScript Folder Action to auto-trim folder

[UPDATE] This does not work as expected. Doesn’t seem to run as a plain AppleScript and when re-worked into an Automator folder action workflow (word salad anyone?) it might work… It has and it also hasn’t. But, even when it has I have the sneaking suspicion iCloud does not propagate deletes from macOS. Wouldn’t be the only inexplicable behavior from that service.

[UPDATE]This has been moved to a Google Drive folder. I’ve had enough of ghost folders taking up all the space. The principle is however the same, except now it just works. Boom. Roasted.

I have a security camera that FTPs a new folder everyday into a local iCloud folder on my home server. FYI, the real location of your iCloud Drive is within ~/Library/Mobile Documents, which is a package folder.

This storage process has not proved ideal since iCloud doesn’t handle automation very well. It works with Finder windows and Save dialogs, but background processes not so much. The result for me has been constant reminders that my iCloud drive is “full” despite deleting the bulk of folders. Most of the space never comes back and many times folders just “deleted” reappear.

Maybe adding another automated process to this soup is not going to help and may make things worse (will bird even notice when items are removed this way?), but what the hell. This script will delete files oldest first until the number of items it counted when it was called reaches the “keep” count (set to “5” here).

This may be attached to any folder, and items may be sent to the Trash or deleted immediately with rm. but be aware that it does not send files to the Trash. They are removed with rm.

-- http://strawhousepig.net/

-- Number of items to keep.
property keep : 5

-- Number of seconds until the script may run again (incase of runaway process adding to folder).
property cycle : 10

-- plist to store time last run.
property the_dom : "applescript.folderaction.trimfolder"

-- Should items be deleted immediately (set to false) or sent to the Trash (set to true)?
property trashit : true

on adding folder items to this_folder after receiving added_items
do_it(this_folder)
end adding folder items to

on run
set this_folder to choose folder
do_it(this_folder)
end run

on do_it(this_folder)
set the_key to "epoch"
set the_val to (do shell script "date '+%s'")
if my read_array(the_dom, the_key, the_val, cycle) is true then return
do shell script "defaults write " & the_dom & " " & the_key & " " & quoted form of the_val
tell application "Finder"
set _items to items of this_folder
set _items to (sort _items by creation date)
end tell
if (count of _items) is greater than keep then
try
repeat until (count of _items) is equal to keep
if trashit is true then
delete item 1 of _items
else
do shell script "rm -R " & quoted form of POSIX path of (item 1 of _items as alias)
end if
set _items to rest of _items
end repeat
on error theErr number theNum
if theNum is not -128 then display dialog theErr giving up after 60
end try
end if
end do_it

on read_array(the_dom, the_key, the_val, cycle)
try
set last_run to (do shell script "defaults read " & the_dom & " " & the_key)
on error -- Will error if there is nothing to read.
return false
end try
if the_val - last_run is less than cycle then
return true
else
return false
end if
end read_array

Auto-eject drive Folder Action

This script is meant to auto-eject a drive after the amount of time set in the script. It will prompt you first, so you may cancel at that time.

Why would this be useful? I have a Garmin Edge 130 bicycle computer. I had been using my phone, but every app/service has binding arbitration garbage in their 50 page click contract (aka baloney), even so far as with Strava flat out stating they may delete your account if you opt-out of it. Via real mail, of course. Outrageous. So I went with Garmin, who actually have a much smaller click contract. Like a breath of fresh air.

At any rate, my wife also has a Garmin Forerunner 35 watch and, like my Edge 130, includes a drive which mounts on your desktop when plugged into a computer. I believe this drive is used for manually installing watch faces or “widgets” and data screens. Although Garmin makes software to load those sort of things.

We typically plug these devices into a computer to charge them and when they are unplugged the Finder complains about the drive having not been ejected properly and file damage or something. Who even reads those things? That’s where this script comes in and why the trigger is “GARMIN”.

This script is meant to be attached as a Folder Action on the Volumes folder.
-- http://strawhousepig.net/

-- Name of disks to watch out for.
property triggers : {"GARMIN"}

-- Number of seconds until the script executes its mission unless user cancels.
property TKO : 30

on adding folder items to this_folder after receiving added_items
do_it()
end adding folder items to

on run
do_it()
end run

on do_it()
tell application "Finder"
try
set these_hds to every disk whose name is in triggers
if these_hds is not {} then
set now to current date
display dialog "The following volumes will be ejected in " & (TKO as text) & " seconds." & return & return & these_hds as text with icon 2 giving up after TKO
set the_res to the result
if gave up of the_res is true then
my inspected_detected_and_ejected(these_hds)
else
set now_now to current date
delay TKO - (now_now - now)
my inspected_detected_and_ejected(these_hds)
end if
end if
on error theErr number theNum
if theNum is not -128 then display dialog theErr giving up after TKO -- Error -128 is the cancelled by user error.
end try
end tell
end do_it

on inspected_detected_and_ejected(these_hds)
repeat with this_hd in these_hds
try
tell application "Finder" to eject this_hd
end try
end repeat
end inspected_detected_and_ejected

Notable is that this script delays the full set time whether the user clicks “OK” or not.

Sync folders when drive is plugged in.

[UPDATE] Didn’t realize how dangerous this is if you actually need to get a backup file(s) off the drive rather than restore from catastrophic failure. Now prompts to confirm sync before proceeding. Should also prompt to eject when complete.

The previous AppleScript post is an earlier version of nearly the same thing. I posted it here to be able to write a new script for where I work. Its intention is to keep an on-site duplicate of an off-site backup. This can of course be used for simple backups and/or folder syncing operations if given the appropriate trigger(s).

To have this script run automagically attach it as a Folder Action to the Volumes folder (/Volumes).

Also, as the previous post, this script calls an rsync binary in a custom install location. Please be aware of that.

Because I can: rsync manual

-- The name of the volume to watch for.
property trigger : "Backup"

-- The paths of the folders to sync. Drag-n-drop supported (choose "Alias").
property theFolders : {"/Do not/forget to/add quotes around", "/And/commas between/items"}

-- rsync options. I use '-rtE' (recursive, preserve times, copy Extended attributes/resource forks)
property rsync_options : "-rtE --delete" -- For mirroring the contents of source dir.
-- property rsync_options : "-rtE --ignore-existing" -- For keeping deleted files on backup. WARNING: also dupes files moved within the source dir.
-- See the rsync manual (man rsync) for more info.

property skip : {} -- Leave empty. Meant to hold items from theFolders which gave rsync an error so we can start over but ignore items in this list.

on adding folder items to this_folder after receiving added_items
try
repeat with i in added_items
if name of (info for i) is trigger then
if the result of (display dialog trigger & " drive connected. Would you like to sync available source folders now?" giving up after 600) is not false then
do_it(skip)
do shell script "logger 'Sync backup folders: Complete'"
ejectit(trigger)
end if
exit repeat
end if
end repeat
on error theErr
do shell script "logger 'Sync backup folders: " & theErr & "'"
end try
end adding folder items to

on run
do_it(skip)
do shell script "logger 'Sync backup folders: Complete'"
ejectit(trigger)
end run

on ejectit(trigger)
if the result of (display dialog "Backup sync complete. Eject drive '" & trigger & "'?") is not false then
tell application "Finder" to eject trigger
end if
end ejectit

on do_it(skip)
tell application "System Events" to set trigger_path to POSIX path of every disk whose name is trigger -- When a drive is mounted and its previous mount point was not removed the new mount point will be given a unique number to follow the name (which isn't shown in the Finder), e.g. "/Volumes/Backup 1". This asks the System for the path rather than us blindly using text.
if trigger_path is {} then
display dialog "The drive '" & trigger & "' does not appear to be mounted. :("
return
end if
set rsync_options to rsync_options & " "
repeat with i in theFolders
tell application "Finder"
if not (exists (i as POSIX file)) then
set end of skip to i as text
end if
end tell
log skip
if i is not in skip then
try
do shell script "/usr/local/bin/rsync " & rsync_options & quoted form of i & " '" & trigger_path & "/'"
set end of skip to i as text
on error the_err
if i is last item in theFolders then
display dialog "rsync encountered a problem: " & the_err
else
if button returned of (display dialog "rsync encountered a problem: " & the_err & return buttons {"Cancel", "Continue"}) is "Continue" then
set end of skip to i as text
do_it(skip)
end if
end if
end try
end if
end repeat
set skip to {}
end do_it

This script includes error handling that isn’t well tested. Getting it to work with it at all was a bit of a trick (particularly if not (exists (i as POSIX file)) since if not (exists POSIX file i) does not work as expected). So that whole “skip” idea may not work as intended if you are asked to continue. The last do_it(skip) call may need to be my do_it(skip) instead.