Safariで表示中のダウンロード残り時間の文字列を数値に変換するために作成したAppleScriptです。
Safariで実行中のダウンロード残り時間の一覧情報を表インタフェースで表示する、ごくごく私的な用途のAppleScriptを書いていたときに必要になったものです。
Safariのダウンロード情報表示は、最近のバージョンではポップオーバーで行われるようになっています。そのポップオーバーの上に表インタフェースが配置されていて、その中の各行の中にあるUI Elementを追いかけるとダウンロード残り時間情報などが取得できます。
▲GUI Scriptingに欠かせない。PFiddlesoftのUI Browser。使わないのと使うのとでは、生産性が1億倍ぐらい違うツール
ただし、得られた「残り時間」の文字列をいったんdateオブジェクトに変換して、経過秒数を計算するのに少々骨が折れました。Safariのダウンロード一覧に表示される文字列はあくまでも「結果表示」で、0分とか0時間とか0秒といった桁は表示が省略されます。
当初、「HH時間mm分ss秒」という固定フォーマットだと勝手に思い込んで処理していました。ところが、各桁が省略されるパターンに遭遇。固定文字列でフォーマット指定をして評価しようとしても、いろいろと無理がありました。自然言語っぽい表記で経過時間の情報を与えられたときに、それを評価してdateオブジェクトに変換するのはけっこうな手間がかかります。
「時」「分」「秒」の各情報が存在するかどうかチェックし、各パターンに合わせた日付フォーマッター文字列を場合分けで書いてみたものの、前述のとおり途中の桁が省略されるパターンに遭遇。3つの桁情報の有無に対応するだけでも、3x2x1=6パターンに対応するif文が必要。さらに、「年」「月」「日」まで表示される可能性を考慮すると、桁要素が6個になるため、6x5x4x3x2x1=720パターンに対処するif文が必要に。この、if文で固定フォーマット文字列を場合分けで選択するというアプローチでは処理が破綻することがあきらかです(if文をそんなに書いたら見通しが悪くなって、矛盾した表記が混入してもわからないでしょう。そこはかとなく、頭が悪い感じもします)。
そこで、与えられた経過時間文字列を直接チェックして、「経過時間文字列に合うように」NSDateFormatter用の文字列を「動的に」組み立てるように方針を転換。これで、大幅に簡潔な記述で済むようになりました。
一番の誤算は、AppleScript上でNSDateのtimeIntervalSinceReferenceDate()の結果が正しく取得できなかったこと。このメソッドで2000年1月1日からの相対秒を取得するつもりだったのですが、期待したような結果は得られませんでした。そのため、2000年1月1日のdateオブジェクトを用意して引き算で経過秒数を求めました。このあたり、AFS(Apple File System)導入時にタイムスタンプの分解能が増やされたことに影響を受けているのだろうかと疑っています。
用途が果てしなく下らない割にてこずらされました。
AppleScript名:時分秒の文字列を数値に変換 v5 |
— Created 2021-06-06 by Takaaki Naganoya — 2021 Piyomaru Software use AppleScript version "2.4" use scripting additions use framework "Foundation" set relSecNum to relativeSecondsFromStringWithDateFormat("22時間 21分 15秒") of me –> 80475 set relSecNum to relativeSecondsFromStringWithDateFormat("22時間 15秒") of me –> 79215 set relSecNum to relativeSecondsFromStringWithDateFormat("22時間") of me –> 79200 on relativeSecondsFromStringWithDateFormat(postDateStr as string) set sepList to {"年", "月", "日", "時間", "分", "秒"} set formList to {"yyyy", "MM", "dd", "HH", "mm", "ss"} set formatStr to "" repeat with i from 1 to 6 set aSepStr to contents of item i of sepList set aFormStr to contents of item i of formList if postDateStr contains aSepStr then set formatStr to formatStr & (aFormStr) & (aSepStr) end if end repeat set postDate to dateFromStringWithDateFormat(postDateStr, formatStr) of me set origDate to dateFromStringWithDateFormat("0時間 0分 0秒", "HH時間mm分ss秒") of me set aSeconds to postDate – origDate return aSeconds end relativeSecondsFromStringWithDateFormat on dateFromStringWithDateFormat(dateString as string, dateFormat as string) set dStr to current application’s NSString’s stringWithString:dateString set dateFormatStr to current application’s NSString’s stringWithString:dateFormat set aDateFormatter to current application’s NSDateFormatter’s alloc()’s init() aDateFormatter’s setDateFormat:dateFormatStr aDateFormatter’s setLocale:(current application’s NSLocale’s alloc()’s initWithLocaleIdentifier:"en_US_POSIX") set aDestDate to (aDateFormatter’s dateFromString:dStr) return aDestDate as date end dateFromStringWithDateFormat |