Menu

Skip to content
AppleScriptの穴
  • Home
  • Products
  • Books
  • Docs
  • Events
  • Forum
  • About This Blog
  • License
  • 仕事依頼

AppleScriptの穴

Useful & Practical AppleScript archive. Click '★Click Here to Open This Script' Link to download each AppleScript

カテゴリー: Internet

Common Elements Libをv1.3aにアップデート

Posted on 7月 12, 2022 by Takaaki Naganoya

対象のキーワードの構成情報を分解して、2つのキーワードの共通要素をリストアップする「マッキー演算」を行うライブラリ「Common Elements Lib」をアップデートしました。

–> Common Elements Libをダウンロード(v1.3a)

マッキー演算とは、「槇原敬之」と「SMAP」の共通項を求め、結果に「世界に一つだけの花」をリストアップする処理です(ほかにも出てきますが)。

–> {“第58回NHK紅白歌合戦”, “木村拓哉”, “東京都”, “ニッポン放送”, “テレビ朝日”, “ミリオンセラー”, “大阪城ホール”, “インターネットアーカイブ”, “社長”, “ミュージックステーション”, “ケンタッキーフライドチキン”, “スポーツニッポン”, “日刊スポーツ”, “第42回NHK紅白歌合戦”, “リクルートホールディングス”, “エフエム東京”, “日本ゴールドディスク大賞”, “フジテレビジョン”, “J-POP”, “小倉博和”, “世界に一つだけの花”, “We are SMAP!”, “日本”, “日本武道館”, “ISBN”}

WikipediaのMedia APIを用いて問い合わせを行って計算を行います。そのため、(Wikipedia上における当該項目の記事内容の変化によって)実行時期によって演算結果に差が出ます。

アップデート理由は、前バージョンではインターネット接続確認を「http://www.google.com」に対して行っていたところに、このドメインに対してhttp経由でのアクセスが行えないようになったので、エラーを起こすようになりました。

このドメインにhttps経由でアクセスするよう変更しました。

Posted in Internet Library list PRODUCTS REST API | Tagged 10.14savvy 10.15savvy 11.0savvy 12.0savvy | Leave a comment

LAN上の別のMacでYouTubeムービー再生をハンズオーバー v2

Posted on 10月 8, 2020 by Takaaki Naganoya

Safariの最前面のウィンドウで再生中のYouTubeムービーの情報を取得し、LAN上の別のMacで再生を引き継ぐ(ハンズオーバーする)AppleScriptです。

macOS 10.13以降、リモートAppleEvents経由でGUIアプリケーションを直接操作する機能が復活しました(Mac OS X 10.7〜10.12ぐらいまでAppleScriptアプレット間のみリモート通信が許可されていた状態)。

メインマシンで再生中のYouTubeムービーを、LAN上の他のマシンに引き継がせてみました。再生を引き継がれる方のマシンでは、システム環境設定の「共有」で「リモートApple Events」の項目をオンにしています(自分のマシンではすべてこの項目をオンにしています)。

(1)リモートマシン上のユーザーのパスワード

AppleScript書類のコメント(Finderコメント)にパスワードを書いておくと、それを読み取って使用するようにしてみました。

(2)リモートマシン上のSafariの起動

リモートマシン上のアプリケーションの操作は、ただリモートマシン上のアプリケーションを指定すればOKなのですが、操作対象のアプリケーションが起動していない場合にはエラーになります。これは、とても困る仕様です。

そこで、リモートマシンのFinder経由でアプリケーションファイルをオープンすることで、リモートマシン上でSafariを起動します。オープン対象をapplication file “Safari”と指定するとエラーになりますが、application file id “com.apple.Safari”と指定するとエラーになりません。

(3)YouTubeで再生中の情報取得

以前調査しておいた内容をそのまま使っています。再生中ならPauseし、再生中の位置(時間)情報を取得し、文字列で指定するために加工してYouTubeのURLに追加しています。URLの加工部分は少々手抜きをしています。

とくに問題なく、メインマシンから他のマシン(macOS 10.15.7/macOS 11.0beta9)にLAN経由で再生をハンズオーバーできました。

実際に、コントロール先のマシン名(Bonjour名)をremoteMachineNameに、ユーザー名をremoteUserNameに、パスワードを実行するAppleScript書類のFinderコメントに書き込んで実行してください。スクリプトエディタ上でもスクリプトメニューからでも問題なく実行できています。

あとは、Safari上のYouTube再生をフルスクリーンで行えるとよいのですが、少し試した範囲ではできなかったので、また地道に調べておく感じでしょうか。

AppleScript名:LAN上の別のMacでYouTubeムービー再生をハンズオーバー v2.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/10/08
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSMetadataItem : a reference to current application’s NSMetadataItem

set remoteMachineName to "MacMini2014.local"
set remoteUserName to "maro"

–ScriptのCommentに書いておいたパスワードを拾って使う
set mePath to (path to me)

–FinderからCommentは拾えるが、メタデータ経由で取得する処理も試してみた
set remoteUserPass to getFinderComment(POSIX path of mePath) of me

tell application "Safari"
  if running then
    tell front document
      set aURL to URL
      
–最前面のウィンドウがYouTubeの場合のみ処理
      
if aURL does not start with "https://www.youtube.com/" then
        display notification "エラー: YouTubeを再生していないため、ハンズオーバーしませんでした"
        
return
      end if
      
      
–再生中のポジションを取得
      
set tRes to (do JavaScript "document.querySelector(’#movie_player video’).currentTime;")
      
      
–再生状況を取得
      
set pRes to (do JavaScript "document.querySelector(’#movie_player video’).paused;")
      
      
if pRes = false then
        –再生中であればPauseする
        
set aRes to (do JavaScript "document.querySelector(’#movie_player .ytp-play-button’).click();")
      end if
      
      
openYouTubeOnRemoteMachine(remoteUserName, remoteUserPass, remoteMachineName, tRes, aURL) of me
    end tell
  end if
end tell

–指定のリモートマシン上のSafariでYouTubeの指定ムービーの指定箇所からの再生を行う
on openYouTubeOnRemoteMachine(remoteUser, remotePass, remoteMachineLocal, newDuration, newURL)
  set remoteMachineName to "eppc://" & remoteUser & ":" & remotePass & "@" & remoteMachineLocal
  
  
–URLの加工。ちょっと手抜きをした
  
if newDuration is not 0 then
    set tText to retTimeText(newDuration) of me
    
if newURL contains "&" then
      set sepChar to "?"
    else
      set sepChar to "&"
    end if
    
    
set newURL to newURL & sepChar & "t=" & tText
  end if
  
  
using terms from application "Safari"
    tell application "Safari" of machine remoteMachineName
      if not running then
        –起動していなかったらあらためてSafariを起動
        
launchRemoteSafari(remoteMachineName) of me
      end if
      
      
try
        close every document
      end try
      
      
set aWin to make new document
      
      
tell aWin
        set URL to newURL
        
–フルスクリーン再生をためしてみたが、こういう書き方ではなかった模様(URLオープンを待つ必要もある)
        
–set aRes to (do JavaScript "document.querySelector(’#movie_player playFullscreen’).click();")
      end tell
      
    end tell
  end using terms from
end openYouTubeOnRemoteMachine

–リモートマシン上でSafariを起動する
on launchRemoteSafari(aMachine)
  using terms from application "Finder"
    tell application "Finder" of machine aMachine
      open application file id "com.apple.Safari"
    end tell
  end using terms from
end launchRemoteSafari

–数値を「h」「m」「s」でフォーマットして返す
on retTimeText(aTime)
  set aHour to aTime div 3600
  
set aMinute to (aTime – (aHour * 3600)) div 60
  
set aSeconds to (aTime mod 60)
  
  
set aString to ""
  
  
if aHour > 0 then
    set aString to aHour & "h"
  end if
  
  
if aMinute > 0 then
    set aString to aString & (aMinute as integer) & "m"
  end if
  
  
if aSeconds > 0 then
    set aString to aString & (aSeconds as integer as string) & "s"
  end if
  
  
return (aString as string)
end retTimeText

–Finderコメントをメタデータ経由で取得
on getFinderComment(aPOSIX)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIX
  
set aMetaInfo to NSMetadataItem’s alloc()’s initWithURL:aURL
  
set metaDict to (aMetaInfo’s valuesForAttributes:{"kMDItemFinderComment"}) as record
  
if metaDict = {} then return ""
  
set aComment to kMDItemFinderComment of (metaDict)
  
return aComment
end getFinderComment

★Click Here to Open This Script 

Posted in Internet JavaScript Remote Control | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Finder NSMetadataItem NSURL Safari | 14 Comments

SafariでURLローディング完了検出

Posted on 8月 10, 2020 by Takaaki Naganoya

Safariで指定URLのページローディングを検出するAppleScriptです。

Safari 13で従来どおり、do javascriptコマンド経由で、

if (do JavaScript "document.readyState" in document 1) is "complete" then

などと処理させてみたら、URLが変更される前に”complete”が返ってきました。どうも、この処理が非同期実行されるのか、表示が反映される前に内部的にはページ遷移が完了しているようです。

現行のSafariにおいては、上記の処理ではページローディング完了検出が行えないことが判明。割と利用する機会が多く、重要な処理であるため、書き換えてみました。

いろいろ実験してみると、documentに新規URLを設定しても、すぐにはURLが変更されないようです。その割にAppleScriptの実行は完了したものとして次の行へと進んでしまいます。普通、こんな挙動を行うアプリケーションはないのですが(OCRで見たことがあったかも?)、ただ、逆にここで処理待ちすると問題が発生するケースもありそうです。

非同期モードと同期モードの両方が存在していて、明示的に選択できるとよいのですが、現状ではそうなっていません。

仕方がないので、旧URLから新URLへの切り替えをループで見張るという処理を書いてみたら、いい感じにローディング検出できました。

AppleScript名:SafariでURLローディング検出.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/08/09
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set aURL to "http://piyocast.com/as/"
openURLWithSafari(aURL)
set aText to getBodyTextFromSafariFrontWindow() of me

on openURLWithSafari(aURL as string)
  if aURL = "" then error "URL is blank"
  
try
    tell application "Safari"
      set d to count every window
      
if d = 0 then
        make new window
        
tell front document
          set URL to aURL
        end tell
      else
        tell front document
          set oldURL to URL
          
set URL to aURL
        end tell
      end if
      
      
detectPageLoaded(10, oldURL, aURL) of me
      
    end tell
  on error
    return false
  end try
end openURLWithSafari

on detectPageLoaded(timeout_value, oldURL, newURL)
  try
    repeat with i from 1 to (timeout_value * 5)
      tell application "Safari"
        tell front document
          set curURL to URL
        end tell
      end tell
      
      
if curURL = newURL then return
      
delay 0.2
    end repeat
  on error
    return false
  end try
  
  
return false
end detectPageLoaded

on getBodyTextFromSafariFrontWindow()
  –フレームを使っていないことが前提条件
  
tell application "Safari"
    return text of front document
  end tell
end getBodyTextFromSafariFrontWindow

★Click Here to Open This Script 

Posted in Internet URL | Tagged 10.13savvy 10.14savvy 10.15savvy 11.0savvy Safari | 1 Comment

アラートダイアログ上にWebViewでChart.jsを表示(Pie Chart) v2

Posted on 6月 15, 2020 by Takaaki Naganoya

Chart.jsを用いてアラートダイアログ上に円グラフを表示するAppleScriptです。

サンプルの円グラフの色使いがいまひとつだったので、Keynoteのグラフの色設定を読み取って利用しています。

ネットワーク接続チェックなど、必要な処理はひととおり行なっている、実戦レベルに近いものです。

さまざまなJavaScript系のグラフ表示のプログラムを試してみましたが、Chart.jsはとてもいい感じです。

AppleScript名:アラートダイアログ上にWebViewでChart.jsを表示(Pie Chart) v2.scptd
set aList to {"field1", "field2", "field3", "field4", "field5"}
set cList to {38, 31, 21, 10, 1}
set dMes1 to "Pie chart Test"
set dMes2 to "This is a simple Donut chart using charts.js"

displayPieChart(aList, cList, dMes1, dMes2) of pieChartLib

script pieChartLib
  —
  
–  Created by: Takaaki Naganoya
  
–  Created on: 2020/06/12
  
—
  
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
  
—
  
use AppleScript version "2.4" — Yosemite (10.10) or later
  
use framework "Foundation"
  
use framework "AppKit"
  
use framework "WebKit"
  
use scripting additions
  
  
property |NSURL| : a reference to current application’s |NSURL|
  
property NSAlert : a reference to current application’s NSAlert
  
property NSString : a reference to current application’s NSString
  
property NSButton : a reference to current application’s NSButton
  
property WKWebView : a reference to current application’s WKWebView
  
property WKUserScript : a reference to current application’s WKUserScript
  
property NSURLRequest : a reference to current application’s NSURLRequest
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
  
property NSRunningApplication : a reference to current application’s NSRunningApplication
  
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
  
property WKUserContentController : a reference to current application’s WKUserContentController
  
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
  
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd
  
  
property returnCode : 0
  
property parent : AppleScript
  
  
  
on displayPieChart(aList, cList, dMes1, dMes2)
    –Error Check
    
if length of aList is not equal to length of cList then error "Wrong Parameter items"
    
if length of aList > 18 then error "Too much items"
    
    
set aRes to hasInternetConnection("https://cdnjs.cloudflare.com") of me
    
if aRes = false then error "Internet connection lost"
    
    
–Data convert to JSON strings
    
set aJsonStr to array2DToJSONArray(aList) of me
    
set cJsonStr to array2DToJSONArray(cList) of me
    
    
–Pie Chart Template HTML
    
set myStr to "<!DOCTYPE html>
<html lang=\"ja\">
<head>
<meta charset=\"utf-8\">
 <title>Graph</title>
</head>
<body>
<canvas id=\"myPieChart\"></canvas>
<script src=\"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js\"></script>

<script>
var ctx = document.getElementById(\"myPieChart\");
var myPieChart = new Chart(ctx, {
type: ’pie’,
data: {
labels: %@,
datasets: [{
backgroundColor: %@,
data: %@
}]
},
options: {
title: {
display: false,
text: \"\"
}
}
});
</script>
</body>
</html>"

    –Color Table From Apple Keynote
    
set bList to {"#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A", "#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A", "#118EFE", "#53D529", "#F5AD10", "#FC0007", "#8B2659", "#2A2A2A"}
    
set bJsonStr to array2DToJSONArray(bList) of me
    
    
set aString to NSString’s stringWithFormat_(myStr, aJsonStr, bJsonStr, cJsonStr) as string
    
    
set paramObj to {myMessage:dMes1, mySubMessage:dMes2, htmlStr:aString}
    
–my browseStrWebContents:paramObj–for debug
    
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true
  end displayPieChart
  
  
on browseStrWebContents:paramObj
    set aMainMes to myMessage of paramObj
    
set aSubMes to mySubMessage of paramObj
    
set htmlString to (htmlStr of paramObj)
    
    
set aWidth to 920
    
set aHeight to 500
    
    
–WebViewをつくる
    
set aConf to WKWebViewConfiguration’s alloc()’s init()
    
    
–指定HTML内のJavaScriptをFetch
    
set jsSource to pickUpFromToStr(htmlString, "<script>", "</script>") of me
    
    
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
    
set userContentController to WKUserContentController’s alloc()’s init()
    
userContentController’s addUserScript:(userScript)
    
aConf’s setUserContentController:userContentController
    
    
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) configuration:aConf
    
aWebView’s setNavigationDelegate:me
    
aWebView’s setUIDelegate:me
    
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
    
using terms from scripting additions
      set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
    end using terms from
    
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
    
    
— set up alert  
    
set theAlert to NSAlert’s alloc()’s init()
    
tell theAlert
      its setMessageText:aMainMes
      
its setInformativeText:aSubMes
      
its addButtonWithTitle:"OK"
      
–its addButtonWithTitle:"Cancel"
      
its setAccessoryView:aWebView
      
      
set myWindow to its |window|
    end tell
    
    
— show alert in modal loop
    
NSRunningApplication’s currentApplication()’s activateWithOptions:0
    
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
    
    
–Stop Web View Action
    
set bURL to |NSURL|’s URLWithString:"about:blank"
    
set bReq to NSURLRequest’s requestWithURL:bURL
    
aWebView’s loadRequest:bReq
    
    
if (my returnCode as number) = 1001 then error number -128
  end browseStrWebContents:
  
  
  
on doModal:aParam
    set (my returnCode) to (aParam’s runModal()) as number
  end doModal:
  
  
  
on viewDidLoad:aNotification
    return true
  end viewDidLoad:
  
  
  
on fetchJSSourceString(aURL)
    set jsURL to |NSURL|’s URLWithString:aURL
    
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
    
return jsSourceString
  end fetchJSSourceString
  
  
  
on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
    set a1Offset to offset of s1Str in aStr
    
if a1Offset = 0 then return false
    
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
    
set a2Offset to offset of s2Str in bStr
    
if a2Offset = 0 then return false
    
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
    
return cStr as string
  end pickUpFromToStr
  
  
  
on array2DToJSONArray(aList)
    set anArray to NSMutableArray’s arrayWithArray:aList
    
set jsonData to NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
    
set resString to NSString’s alloc()’s initWithData:jsonData encoding:(NSUTF8StringEncoding)
    
return resString
  end array2DToJSONArray
  
  
  
on parseByDelim(aData, aDelim)
    set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to aDelim
    
set dList to text items of aData
    
set AppleScript’s text item delimiters to curDelim
    
return dList
  end parseByDelim
  
  
on hasInternetConnection(aURL)
    set aURL to current application’s |NSURL|’s alloc()’s initWithString:aURL
    
set aReq to current application’s NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
    
set urlRes to (current application’s NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
    
if urlRes = missing value then
      return false
    else
      return true
    end if
  end hasInternetConnection
end script

★Click Here to Open This Script 

Posted in dialog Internet JavaScript JSON URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSJSONSerialization NSMutableArray NSRunningApplication NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

指定のドメインのIPアドレスを指定DNSで引いて返す

Posted on 5月 26, 2020 by Takaaki Naganoya

指定のドメインのIPアドレスを、指定のDNSサーバーで引いて結果を返すAppleScriptです。

DNS系のFramework(Objective-Cで書いてあるもの)はいろいろためしてみたものの、不思議とどれも動作が重くて、このようにshell commandを呼び出したほうが手軽で高速でした。

# うまく動いていなかったために遅かった、というのが正確なところかも。タイムアウトエラーを起こして処理が完了しないものばかりだったので、、、書き換えがうまく行っていなかった可能性が50%以上あります

nslookupの結果を取り出すためにいろいろやっていますが、ありもののルーチンを引っ張り出して加工してしているだけです。

apple.comのように、CDNサービスを利用してアクセス負荷分散を行なっているようなドメインだと、問い合わせごとにIPアドレスが変わるようです。

一方で、piyocast.comのように固定ホスト(バーチャルホストではありますが)で細々とホスティングしているようなドメインでは、IPアドレスが毎回変わるということはありません。

AppleScript名:指定のドメインのIPアドレスを指定DNSで引いて返す v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/25
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

property NSScanner : a reference to current application’s NSScanner
property NSMutableArray : a reference to current application’s NSMutableArray

set aDomain to "apple.com"
set aDNS to "8.8.4.4"
set dnRes to getIPAddress(aDomain, aDNS) of me
–> {serverName:"apple.com", serverAddr:{"17.172.224.47", "17.178.96.59", "17.142.160.59"}}–CDNの影響でアドレスが頻繁に変わる?

set dnRes to getIPAddress("piyocast.com", aDNS) of me
–> {serverName:"piyocast.com", serverAddr:{"157.112.183.74"}}

on getIPAddress(aDomain, aDNS)
  set searchStr to "answer:"
  
  
using terms from scripting additions
    set aRes to do shell script ("nslookup " & aDomain & " " & aDNS)
    
set bRes to offset of searchStr in aRes
  end using terms from
  
  
if bRes = 0 then return false
  
  
set cRes to text (bRes + (length of searchStr) + 1) thru -1 of aRes
  
  
set adRes1 to extractStrFromTo(cRes, "Name:", return) of me
  
set adRes2 to extractStrFromTo(cRes, "Address:", return) of me
  
  
set outList to {}
  
set erList to {}
  
repeat with i from 1 to (length of adRes2)
    set j1 to contents of (item i of adRes1)
    
set j2 to contents of (item i of adRes2)
    
if j1 is equal to aDomain then
      set the end of outList to j2
    else
      set the end of erList to {j1, j2}
    end if
  end repeat
  
  
return {serverName:j1, serverAddr:outList}
end getIPAddress

–offset命令の実行を横取りして高速実行(x2.5 faster)
on offset of searchStr in str
  set aRes to getOffset(str, searchStr) of me
  
return aRes
end offset

on getOffset(str, searchStr)
  set d to divideBy(str, searchStr)
  
if (count d) is less than 2 then return 0
  
return (length of item 1 of d) + 1
end getOffset

on divideBy(str, separator)
  set delSave to AppleScript’s text item delimiters
  
set the AppleScript’s text item delimiters to separator
  
set strItems to every text item of str
  
set the AppleScript’s text item delimiters to delSave
  
return strItems
end divideBy

–指定文字と終了文字に囲まれた内容を抽出
on extractStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to NSScanner’s scannerWithString:aParamStr
  
set anArray to NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference)
    
if theValue is missing value then set theValue to "" –>追加
    
theScanner’s scanString:toStr intoString:(missing value)
    
anArray’s addObject:theValue
  end repeat
  
  
return (anArray as list)
end extractStrFromTo

★Click Here to Open This Script 

Posted in Internet | Tagged 10.13savvy 10.14savvy 10.15savvy NSMutableArray NSScanner | Leave a comment

クリップボード内の文字種別を集計して円グラフ表示

Posted on 5月 16, 2020 by Takaaki Naganoya

クリップボード内に文字列が入っていれば、いいかえれば「文字列をコピーした状態であれば」、クリップボード内容をテキストとして取り出して文字種別ごとに集計して構成比を円グラフで表示するAppleScriptです。

# CAUTION: This script process Japanese characters. So, this script make no sense for other language users

グラフ表示部分は手抜きでGoogle Chartsを呼び出しているだけなので、Macがネットワークに接続されていない場合には表示できません。

macOS標準装備のScript Menuに入れて使っています。複数の円グラフを表示させることも可能なので、典型的な例文(新聞、論文、なろう系、技術系文章、文学作品)のグラフを一覧表示して、どの例文の使用比率に近いかといったことを見てわかるようにできそうです(やらないけど)。

ありものをただ引っ張り出してきて、Script文でつないだだけなので、オリジナルで記述した部分はほとんどありません。

とはいえ、技術的にはいろいろなハードルを乗り越えまくって動かしているものでもあります。

・メインスレッドでしか動かせないWkWebView、NSAlertをScriptから呼び出している(実行環境に左右されずに実行)
・Cocoa Scriptingを行うAppleScriptObjCをscript文でscript object化して(カプセル化して)呼び出し、再利用
・WkWebViewをdialog内に表示して、マウスオーバーでデータ内容が見えるようなインタラクティブなグラフを表示

といった、いろいろ無茶なことをやっているScriptです。ただ、すでに見慣れた光景になりつつありますけれども。

AppleScript名:クリップボード内の文字種別を集計して円グラフ表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/05/14
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSString : a reference to current application’s NSString
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property WKUserContentController : a reference to current application’s WKUserContentController
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property NSScreenSaverWindowLevel : a reference to current application’s NSScreenSaverWindowLevel
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property returnCode : 0

–Calc Clipboard
set aRes to clipAnaliticsMain() of clipboardInfoKit
if aRes = false then return —クリップボードが空だった(文字列的に)

set totalC to totalC of aRes

set aList to {{"文字種別", "構成比"}} & rating of aRes

set aJsonArrayStr to array2DToJSONArray(aList) of me

–Pie Chart Template HTML
set myStr to "<!DOCTYPE html>
<html lang=\"UTF-8\">
<body>
<div id=\"piechart\"></div>

<script type=\"text/javascript\" src=\"https://www.gstatic.com/charts/loader.js\"></script>

<script type=\"text/javascript\">
// Load google charts
google.charts.load(’current’, {’packages’:[’corechart’]});
google.charts.setOnLoadCallback(drawChart);

// Draw the chart and set the chart values
function drawChart() {
var data = google.visualization.arrayToDataTable(%@);

// Optional; add a title and set the width and height of the chart
var options = {
is3D: true,
   ’width’:600, ’height’:400
};

// Display the chart inside the <div> element with id=\"piechart\"
var chart = new google.visualization.PieChart(document.getElementById(’piechart’));
chart.draw(data, options);
}
</script>

</body>
</html>"

set aString to current application’s NSString’s stringWithFormat_(myStr, aJsonArrayStr) as string

set paramObj to {myMessage:"文字種別構成比", mySubMessage:"クリップボードの内容を集計。文字数は" & (totalC as string) & "文字", htmlStr:aString}
–my browseStrWebContents:paramObj–for debug
my performSelectorOnMainThread:"browseStrWebContents:" withObject:(paramObj) waitUntilDone:true

on browseStrWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set htmlString to (htmlStr of paramObj)
  
  
set aWidth to 600
  
set aHeight to 450
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定HTML内のJavaScriptをFetch
  
set jsSource to pickUpFromToStr(htmlString, "<script type=\"text/javascript\">", "</script>") of me
  
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s fileURLWithPath:(POSIX path of (path to me))
  
aWebView’s loadHTMLString:htmlString baseURL:(bURL)
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
–its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
    
    
set myWindow to its |window|
  end tell
  
  
myWindow’s setLevel:(NSScreenSaverWindowLevel)
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseStrWebContents:

on doModal:aParam
  set (my returnCode) to (aParam’s runModal()) as number
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

on pickUpFromToStr(aStr as string, s1Str as string, s2Str as string)
  set a1Offset to offset of s1Str in aStr
  
if a1Offset = 0 then return false
  
set bStr to text (a1Offset + (length of s1Str)) thru -1 of aStr
  
set a2Offset to offset of s2Str in bStr
  
if a2Offset = 0 then return false
  
set cStr to text 1 thru (a2Offset – (length of s2Str)) of bStr
  
return cStr as string
end pickUpFromToStr

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

on array2DToJSONArray(aList)
  set anArray to current application’s NSMutableArray’s arrayWithArray:aList
  
set jsonData to current application’s NSJSONSerialization’s dataWithJSONObject:anArray options:(0 as integer) |error|:(missing value) –0 is
  
set resString to current application’s NSString’s alloc()’s initWithData:jsonData encoding:(current application’s NSUTF8StringEncoding)
  
return resString
end array2DToJSONArray

script clipboardInfoKit
  use scripting additions
  
use framework "Foundation"
  
property parent : AppleScript
  
  
property NSString : a reference to current application’s NSString
  
property NSNumber : a reference to current application’s NSNumber
  
property NSDictionary : a reference to current application’s NSDictionary
  
property NSCountedSet : a reference to current application’s NSCountedSet
  
property NSCharacterSet : a reference to current application’s NSCharacterSet
  
property NSMutableArray : a reference to current application’s NSMutableArray
  
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
  
property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch
  
property NSNumberFormatterRoundUp : a reference to current application’s NSNumberFormatterRoundUp
  
property NSNumberFormatterRoundDown : a reference to current application’s NSNumberFormatterRoundDown
  
  
  
on clipAnaliticsMain()
    set cCount to 0
    
set hCount to 0
    
set kCount to 0
    
set oCount to 0
    
set tCount to 0
    
    
using terms from scripting additions
      set aStr to (the clipboard as «class utf8»)
      
if aStr = "" then
        display dialog "No text data in clipboard" buttons {"OK"} default button 1
        
return false
      end if
    end using terms from
    
    
set aRec to detectCharKindRating(aStr) of me
    
    
set cCount to cCount + (kanjiNum of aRec)
    
set hCount to hCount + (hiraganaNum of aRec)
    
set kCount to kCount + (katakanaNum of aRec)
    
set oCount to oCount + (otherNum of aRec)
    
set tCount to tCount + (totalCount of aRec)
    
    
return {rating:{{"漢字", cCount}, {"ひらがな", hCount}, {"カタカナ", kCount}, {"その他", oCount}}, totalC:tCount}
  end clipAnaliticsMain
  
  
  
  
on detectCharKindRating(aStr as string)
    set aList to NSMutableArray’s arrayWithArray:(characters of aStr)
    
set theCountedSet to NSCountedSet’s alloc()’s initWithArray:aList
    
set theEnumerator to theCountedSet’s objectEnumerator()
    
    
set cCount to 0
    
set hCount to 0
    
set kCount to 0
    
set oCount to 0
    
set totalC to length of aStr
    
    
repeat
      set aValue to theEnumerator’s nextObject()
      
if aValue is missing value then exit repeat
      
      
set aStr to aValue as string
      
set tmpCount to (theCountedSet’s countForObject:aValue)
      
      
set s1Res to chkKanji(aStr) of me
      
set s2Res to chkKatakana(aStr) of me
      
set s3Res to chkHiragana(aStr) of me
      
      
if s1Res = true then
        set cCount to cCount + tmpCount
      else if s2Res = true then
        set kCount to kCount + tmpCount
      else if s3Res = true then
        set hCount to hCount + tmpCount
      else
        set oCount to oCount + tmpCount
      end if
    end repeat
    
    
set ckRes to roundingUp((cCount / totalC) * 100, 1) of me
    
set kkRes to roundingUp((kCount / totalC) * 100, 1) of me
    
set hgRes to roundingUp((hCount / totalC) * 100, 1) of me
    
set otRes to roundingUp((oCount / totalC) * 100, 1) of me
    
    
return {kanjiNum:cCount, kanjiRating:ckRes, hiraganaNum:hCount, hiraganaRating:hgRes, katakanaNum:kCount, katakanaRating:kkRes, otherNum:oCount, otherRating:otRes, totalCount:totalC}
  end detectCharKindRating
  
  
  
on chkKanji(aChar)
    return detectCharKind(aChar, "[一-龠]") of me
  end chkKanji
  
  
on chkHiragana(aChar)
    return detectCharKind(aChar, "[ぁ-ん]") of me
  end chkHiragana
  
  
on chkKatakana(aChar)
    return detectCharKind(aChar, "[ァ-ヶ]") of me
  end chkKatakana
  
  
on detectCharKind(aChar, aPattern)
    set aChar to NSString’s stringWithString:aChar
    
set searchStr to NSString’s stringWithString:aPattern
    
set matchRes to aChar’s rangeOfString:searchStr options:(NSRegularExpressionSearch)
    
if matchRes’s location() = (current application’s NSNotFound) or (matchRes’s location() as number) > 9.99999999E+8 then
      return false
    else
      return true
    end if
  end detectCharKind
  
  
on roundingUp(aNum, aDigit as integer)
    set a to aNum as real
    
set aFormatter to NSNumberFormatter’s alloc()’s init()
    
aFormatter’s setMaximumFractionDigits:aDigit
    
aFormatter’s setRoundingMode:(NSNumberFormatterRoundUp)
    
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:a)
    
return (aStr as text) as real
  end roundingUp
end script

★Click Here to Open This Script 

Posted in dialog Internet JavaScript Text | Tagged 10.13savvy 10.14savvy 10.15savvy NSAlert NSButton NSCharacterSet NSCountedSet NSDictionary NSMutableArray NSNumber NSNumberFormatter NSNumberFormatterRoundDown NSNumberFormatterRoundUp NSRegularExpressionSearch NSRunningApplication NSScreenSaverWindowLevel NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

NSURLSessionでREST API呼び出しv4.4.2a

Posted on 4月 3, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。URLキャッシュが効くようになったような気がします。

–> GET method REST API v4.4.1
–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュしないかわりにURLキャッシュが効かないという特徴がありました。ただ、edama2さんと協議した結果、macOS 10.15上でクラッシュする原因と考えられていた内容にあまり根拠がないことがわかってきました(人ごとではなく自分のことなのですが)。

可能な範囲でトライアル&エラーで調査を行なったところ、本バージョンのような処理に落ち着きました。AppleScriptからのCocoa利用については明確にドキュメントがAppleから出ているわけではないので、すでに存在するObjective-Cのプログラムの処理を参考にしつつ、Objective-CからAppleScriptへの置き換えが可能かを検討しています。

URLキャッシュについては、(当然のことながら)処理1回目には効きません。なぜか2回目も効きません。3回目とか4回目あたりから効いていることが実感できる感じです(回数ではなく、前回処理時からの経過時間を見ているのかも? GUIアプリケーションに入れて使うと2回目から効いたりします)。URLキャッシュが効いていない場合には1.5秒ぐらい、URLキャッシュが効き出すと0.02秒ぐらいで結果が返ってきています。

macOS 10.13/14/15で検証を行い、繰り返し処理を行ってもクラッシュしないことを確認しています。ただ、動作保証するというレベルではないので(本Blog掲載のScriptすべてそうですが)、問題があったら知らせてください。

ためしに、Xcode上で作成したGUIベースのAppleScriptアプリケーションに本処理を導入したところ、REST APIへの問い合わせがキャッシュされて著しい高速化を実現できました。

AppleScript名:GET method REST API v4.4.2a_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-03 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLCache : a reference to current application’s NSURLCache
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSOperationQueue : a reference to current application’s NSOperationQueue
property NSURLComponents : a reference to current application’s NSURLComponents
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration
property NSURLRequestReturnCacheDataElseLoad : a reference to current application’s NSURLRequestReturnCacheDataElseLoad

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return false
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet JSON REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSOperationQueue NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLRequestReturnCacheDataElseLoad NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

NSURLSessionでREST API呼び出しv4.4.1

Posted on 4月 2, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。macOS 10.15でクラッシュしないように書き換えています。

–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

前バージョンではmacOS 10.15上でクラッシュするかわりにmacOS 10.14上で高速という特徴がありました。ただ、macOS 10.15上でクラッシュしないように調整を行っていくと、処理速度については別段速くもなく(キャッシュがヒットしていない雰囲気)、よりいっそうキャッシュについて調べる必要が出てきています。

一応、キャッシュの作り方については調べてみたものの、

キャッシュが効いている雰囲気がまったくありません。

キャッシュの内容を確認してみると、からっぽですね(^ー^; もう少し(時間のあるときに)キャッシュの連携などを調べておくといいのかもしれません。最低限、macOS 10.15でクラッシュしなくなったので、NSURLConnectionを呼び出してリジェクトを喰らわないように準備しておくという感じでしょうか。

AppleScript名:GET method REST API v4.4.1_wikipedia.scptd
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-04-02 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false
property aSession : missing value
property aCache : missing value

on run
  set retData to missing value
  
set drecF to false
  
set aSession to missing value
  
  
set aQueryKeyTitle to "AppleScript"
  
set aRes to getWikiText(aQueryKeyTitle) of me
  
return aRes
end run

on getWikiText(aQueryKeyTitle)
  set reqURLStr to "https://en.wikipedia.org/w/api.php"
  
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
  
set aURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set aRes to callRestGETAPIAndParseResults(aURL, 5) of me
  
if aRes = missing value then return "Error"
  
  
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
  
return bRes
end getWikiText

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
–if my aCache = missing value then
  
set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache"
  
set my aCache to current application’s NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath
  
–end if
  
current application’s NSURLCache’s setSharedURLCache:(my aCache)
  
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set v2 to system attribute "sys2" –> 14
  
if v2 < 15 then
    –macOS 10.14まで
    
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  else
    –macOS 10.15以降。10.15でdefaultSessionConfigurationを使うとクラッシュしやすい???
    
set identifier to "BackgroundSessionConfiguration"
    
set aConfig to NSURLSessionConfiguration’s backgroundSessionConfiguration:(identifier)
  end if
  
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
  
aConfig’s setURLCache:(my aCache)
  
–aConfig’s setTimeoutIntervalForRequest:0.5
  
–aConfig’s setTimeoutIntervalForResource:timeoutSec
  
–aConfig’s setWaitsForConnectivity:false
  
  
–どちらでも速度差がない
  
set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(current application’s NSOperationQueue’s mainQueue())
  
–set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (1000 * timeoutSec) times
    if (my drecF) is not equal to false then
      exit repeat
    end if
    
delay "0.001" as real
  end repeat
  
  
–aSession’s invalidateAndCancel() –delegateの無効化
  
my aSession’s finishTasksAndInvalidate()
  
set my aSession to missing value
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError
  if tmpError = missing value then
    set (my drecF) to true
  else
    error "Donwload Failed"
  end if
end URLSession:task:didCompleteWithError:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSString NSURL NSURLCache NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

NSURLSessionでREST API呼び出しv4.4

Posted on 3月 29, 2020 by Takaaki Naganoya

REST API呼び出しに欠かせない部品をアップデートしました。

–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4

従来、NSURLConnectionを使って同期処理を行っていましたが、これがDepreceted扱いになりました。すぐになくなることはありませんが、いつかなくなる可能性があります。

このため、NSURLConnectionから動作原理の異なるNSURLSessionを使うよう移行する必要があります(curlコマンドを利用するというルートもあります)。

とはいえ、blocks構文の使えないAppleScriptでこのNSURLSessionを使えるようにするのは大変です。非同期通信を行うNSURLSessionを非同期処理のしにくいAppleScriptで、同期処理っぽく書かなくてはなりません。

NSURLSessionによる通信では、サーバーとの間で何回かのやりとりがあって、データを小分けに複数回受信する必要がありました。NSMutableDataというオブジェクトの存在を知ったのでいい感じに処理できるようになってきました。

NSURLSessionのメリットとして喧伝されている非同期処理は、AppleScriptから呼び出しているかぎりはそれほどメリットになりません。もう少し使い込めば活用できるかもしれませんが、まだそういう段階にはありません。

NSURLSessionの導入によって得られるメリットで最大のものは、キャッシュ機構です。NSURLConnectionでもキャッシュ機構は利用できましたが、NSURLSessionではよりAPIに深く統合されているものと理解しました。

キャッシュの効き方については、設定で何段階かに設定できるとAppleのオンラインドキュメントに書かれています。本Scriptでは、キャッシュ優先でキャッシュが存在している場合にはキャッシュ内のデータを返し、キャッシュが存在していない場合にはWebサーバーに問い合わせを行うように設定しています。

キャッシュが効いている状況なら、NSURLConnectionで1.8秒ぐらいの処理がNSURLSessionで0.1秒程度と大幅に速く処理できます。キャッシュが効いていない状況(初回実行時)だと、NSURLSessionのほうがやや処理に時間がかかるぐらいです。

処理結果について、NSURLConnection版とNSURLSession版で結果の比較を行ってみましたが、とくに差異は見られませんでした。

本サンプルScriptでは、Wikipedia(英語版)へのキーワードの問い合わせを行います。NSURLConnection版では複数回実行しても同じぐらいの速度で実行されますが、NSURLSession版では2度目から早く終わります(Script Debugger上で動かすと秒以下の精度の時間がわかります)。

macOS 10.14上で作ってmacOS 10.14.6/10.13.6上で動作確認しています(スクリプトエディタ、Script Debuggerで動作確認)。ただし、macOS 10.15上だとクラッシュします。Xcodeのプロジェクトに入れてみましたが、同様にmacOS 10.15上ではクラッシュします。

ただし、自分のmacOS 10.14.6環境はSIP解除しているのと、macOS 10.15環境のクラッシュログにSIP関連のメッセージが残っているので、OSバージョンではなくSIPのためかもしれません(macOS 10.14.6でもSIPを有効にするとクラッシュするかもしれない & macOS 10.15.xでもSIPを無効にするとクラッシュしないかもしれない)。

AppleScript名:GET method REST API v4.4_wikipedia
— Created 2019-05-02 by Takaaki Naganoya
— Modified 2020-03-29 by Takaaki Naganoya
— 2020 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSURLSession : a reference to current application’s NSURLSession
property NSMutableData : a reference to current application’s NSMutableData
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration

property retData : missing value
property retCode : 0
property retHeaders : 0
property drecF : false

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string
return bRes

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer)
  set (my retData) to NSMutableData’s alloc()’s init()
  
set (my retCode) to 0
  
set (my retHeaders) to {}
  
set (my drecF) to false
  
  
set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
aConfig’s setRequestCachePolicy:(current application’s NSURLRequestReturnCacheDataElseLoad)
  
set aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value)
  
set aTask to aSession’s dataTaskWithRequest:aRequest
  
  
aTask’s resume() –Start URL Session
  
  
repeat (10 * timeoutSec) times
    if (my drecF) = true then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
return my parseSessionResults()
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  (my retData)’s appendData:tmpData
end URLSession:dataTask:didReceiveData:

on URLSession:tmpSession dataTask:tmpTask didCompleteWithError:tmpError
  set (my drecF) to true
end URLSession:dataTask:didCompleteWithError:

on URLSession:tmpSession dataTask:tmpTask willCacheResponse:cacheRes completionHandler:aHandler
  set (my drecF) to true
end URLSession:dataTask:willCacheResponse:completionHandler:

on parseSessionResults()
  set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding)
  
set jsonString to NSString’s stringWithString:(resStr)
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict
end parseSessionResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as {list, missing value}
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

AppleScript名:GET method REST API_wikipedia
— Created 2016-03-03 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set aQueryKeyTitle to "Steve Jobs" –キーワードの正規化が必要("戦場の絆"→"機動戦士ガンダム 戦場の絆" )
set reqURLStr to "https://en.wikipedia.org/w/api.php"
set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"}
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRes to callRestGETAPIAndParseResults(aURL, 10) of me
set aRESTres to json of aRes
set bRes to (aRESTres’s valueForKeyPath:"parse.wikitext.*") as string

–GET methodのREST APIを呼ぶ
on callRestGETAPIAndParseResults(aURL, timeoutSec)
  set aRequest to current application’s NSMutableURLRequest’s requestWithURL:(current application’s |NSURL|’s URLWithString:aURL)
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:timeoutSec
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aRes to current application’s NSURLConnection’s sendSynchronousRequest:aRequest returningResponse:(reference) |error|:(missing value)
  
set resList to aRes as list
  
  
set bRes to contents of (first item of resList)
  
set resStr to current application’s NSString’s alloc()’s initWithData:bRes encoding:(current application’s NSUTF8StringEncoding)
  
  
set jsonString to current application’s NSString’s stringWithString:resStr
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
  
–Get Response Code
  
set dRes to contents of second item of resList
  
set resCode to (dRes’s statusCode()) as integer
  
  
–Get Response Header
  
set resHeaders to (dRes’s allHeaderFields()) as record
  
  
return {json:aJsonDict, responseCode:resCode, responseHeader:resHeaders}
  
end callRestGETAPIAndParseResults

on retURLwithParams(aBaseURL, aRec)
  set aDic to current application’s NSMutableDictionary’s dictionaryWithDictionary:aRec
  
  
set aKeyList to (aDic’s allKeys()) as list
  
set aValList to (aDic’s allValues()) as list
  
set aLen to length of aKeyList
  
  
set qList to {}
  
repeat with i from 1 to aLen
    set aName to contents of item i of aKeyList
    
set aVal to contents of item i of aValList
    
set the end of qList to (current application’s NSURLQueryItem’s queryItemWithName:aName value:aVal)
  end repeat
  
  
set aComp to current application’s NSURLComponents’s alloc()’s initWithString:aBaseURL
  
aComp’s setQueryItems:qList
  
set aURL to (aComp’s |URL|()’s absoluteString()) as text
  
  
return aURL
end retURLwithParams

on urlencodeStr(aStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set aString to (aString’s stringByAddingPercentEncodingWithAllowedCharacters:(current application’s NSCharacterSet’s URLQueryAllowedCharacterSet())) as text
  
return aString
end urlencodeStr

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel1(aRecList as list, aPredicate as string)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
set bList to filteredArray as list
  
return bList
end filterRecListByLabel1

★Click Here to Open This Script 

Posted in Internet REST API URL | Tagged 10.13savvy 10.14savvy NSArray NSJSONSerialization NSMutableData NSMutableDictionary NSMutableURLRequest NSPredicate NSString NSURL NSURLComponents NSURLQueryItem NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 2 Comments

WebKit Utilities v2

Posted on 3月 16, 2020 by Takaaki Naganoya

AppleScriptで指定URLのページを表示する「WebKit Utilities」がmacOS 10.13以降の環境で動かなくなっていたので、書き換えて動くようにしておきました。

–> Download WebKit Utilities_archive v2

これ自体が役に立ったということはなく、単にAppleScript Librariesの書き方のサンプルと理解しています。Webサイトの表示を行うよりも1枚ものの画像やPDFにレンダリングする処理のほうがバッチ処理の中では相性がいいと思います。

また、このScriptはWkWebViewではなく古いWebViewを使っているので、じきに動かなくなります。

AppleScript名:WebKit Utilitiesで指定URLをウィンドウ表示
— Created 2017-03-24 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use webLib : script "WebKit Utilities"

set targetURL to "http://www.piyocast.com/"
display URL targetURL window size {1024, 1024}

★Click Here to Open This Script 

AppleScript名:WebKit Utilities
— An example AppleScript/Objective-C library that uses the WebKit framework.

use AppleScript
use framework "AppKit"
use framework "WebKit"

property NSURL : a reference to current application’s NSURL
property WebView : a reference to current application’s WebView
property NSScreen : a reference to current application’s NSScreen
property NSThread : a reference to current application’s NSThread
property NSWindow : a reference to current application’s NSWindow
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableDictionary : a reference to current application’s NSMutableDictionary

on _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  — Create and display a horizontally centered window with a WebView
  
  
set {thisWindowWidth, thisWindowHeight} to theWindowSize
  
set screenBounds to the NSScreen’s mainScreen’s visibleFrame as any
  
  
if class of screenBounds = record then
    set screenWidth to screenBounds’s |size|’s width
    
set screenHeight to screenBounds’s |size|’s height
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + (screenBounds’s origin’s x)
    
set windowBottom to screenHeight – thisWindowHeight + (screenBounds’s origin’s y) – 40
  else
    copy screenBounds to {{originX, originY}, {screenWidth, screenHeight}}
    
set windowLeft to ((screenWidth – thisWindowWidth) / 2) + originX
    
set windowBottom to screenHeight – thisWindowHeight + originY – 40
  end if
  
  
set theStyleMask to (get current application’s NSTitledWindowMask) + (get current application’s NSClosableWindowMask) + (get current application’s NSMiniaturizableWindowMask) + (get current application’s NSResizableWindowMask)
  
set webWindow to NSWindow’s alloc()’s initWithContentRect:(current application’s NSMakeRect(windowLeft, windowBottom, thisWindowWidth, thisWindowHeight)) ¬
    styleMask:theStyleMask backing:(current application’s NSBackingStoreBuffered) defer:false
  — set webWindow’s title to "WebView Created with AppleScript – " & theURLString
  
  
set theWebView to WebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, thisWindowWidth, thisWindowHeight)) ¬
    frameName:"WebKit Frame" groupName:"WebKit Group"
  set webWindow’s contentView to theWebView
  
  
tell webWindow to makeKeyAndOrderFront:(missing value)
  
  
— Start loading the URL
  
  
set theURL to NSURL’s URLWithString:theURLString
  
set theURLRequest to NSURLRequest’s requestWithURL:theURL
  
tell theWebView’s mainFrame to loadRequest:theURLRequest
  
  
webWindow
end _DisplayWebWindowWithURL:windowSize:

— The following two handlers exist to deal with running on a background thread.
— If we’re on a background thread, we have to run the UI code on the main thread.

on _DisplayWebWindowMainThread:parameterDictionary
  try
    set theURLString to parameterDictionary’s objectForKey:"url string"
    
set theWindowSize to parameterDictionary’s objectForKey:"window size"
    
    
set webWindow to my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
    
    
tell parameterDictionary to setObject:webWindow forKey:"result"
  on error errMsg number errNum
    using terms from scripting additions
      display alert "Error!" message errMsg & " (" & errNum & ")"
    end using terms from
    
tell parameterDictionary to setObject:{errMsg, errNum} forKey:"error"
  end try
end _DisplayWebWindowMainThread:

on display URL theURLString window size theWindowSize
  — All UI methods must be invoked on the main thread.
  
if (NSThread’s isMainThread) then
    my _DisplayWebWindowWithURL:theURLString windowSize:theWindowSize
  else
    — Parameters, results and error information are communicated between threads via a dictionary.
    
set parameterDictionary to NSMutableDictionary’s dictionary()
    
tell parameterDictionary to setObject:theURLString forKey:"url string"
    
tell parameterDictionary to setObject:theWindowSize forKey:"window size"
    
    
its performSelectorOnMainThread:"_DisplayWebWindowMainThread:" withObject:parameterDictionary waitUntilDone:true
    
    
— Propagate errors from the other thread
    
    
set errInfo to parameterDictionary’s objectForKey:"error"
    
if errInfo is not missing value then error errInfo’s first item number errInfo’s second item
    
    
parameterDictionary’s objectForKey:"result"
  end if
end display URL

★Click Here to Open This Script 

Posted in GUI Internet URL | Tagged 10.13savvy 10.14savvy 10.15savvy NSMutableDictionary NSScreen NSThread NSURL NSURLRequest NSWindow WebView | Leave a comment

Wikipedia経由で2つの単語の共通要素を計算するcommon elements Lib Script Library

Posted on 2月 28, 2020 by Takaaki Naganoya

現在作成中のアプリケーションの副産物として生まれた「common elements Lib」AppleScript Libraryです。2つの単語の共通要素を計算して返します。

# v1.1にアップデートしました(ダウンロード先URLはかわらず)。ページ下部のテンプレート部分の余計なリンクを拾わないように改善したため、テンプレート部分のリンクが多い項目に対して大きな効果を発揮します

–> Download archive

アーカイブをダウンロードして展開し、~/Library/Script Librariesフォルダに「common elements Lib.scptd」を入れるとAppleScriptから呼び出せるようになります。

macOS 10.10以降で動作するはずですが、開発は10.14上で、動作確認は10.13/10.14/10/15上でのみ行なっています。

この、2つのキーワードの共通要素を求める処理は「マッキー演算」と呼んでおり、男性アイドルグループ「SMAP」と、男性シンガーソングライター「槇原敬之」(マッキー)氏の共通要素を演算で求めることを目的として企画されました。「SMAP」はWikipedia上でも最大級の要素数を持つ項目であり、1,400項目以上のリンク要素を擁しています。

Wikipedia REST APIの仕様ではリンク要素を500項目までしか一度に取得できません。SMAPを処理するためには、複数ページにまたがるリンク取得の処理をこなすことが必要であり、「マッキー演算」は言葉のバカっぽさとは裏腹に、それなりの技術力が要求される、そこそこむずかしい処理なのです。

本ライブラリを用いて、WikipeidaにREST API経由で検索司令を出すわけですが、英語のスペルの単語を受け付けるWikipediaもあれば、日本語やアラビア語Wikipediaなどのようにその言語向けの書き換えを行ったデータで検索するものもあり、割とまちまちであることがわかりました。そのあたりは、sdefに書いておいたサンプルScriptを見ていただくのがよいでしょう。

本ライブラリでは、演算対象とする単語はWikipediaに掲載されているものに限られています。実際に、日本語環境で「スティーブ・ジョブズ」と「ラリー・テスラー」の共通項目を計算すると、

--> {"パロアルト研究所", "Smalltalk", "アメリカ合衆国", "Lisa (コンピュータ)", "アップル・ニュートン", "Macintosh", "アップル (企業)", "Macworld", "スタンフォード大学"}

「スティーブ・ジョブズ」と「ロス・ペロー」の共通項目を計算すると、

--> {"NeXT", "アル・ゴア", "統合典拠ファイル", "実業家", "IBM", "ゼネラルモーターズ", "SNAC", "アメリカ合衆国", "国際標準名称識別子", "孫正義", "ソフトバンク", "国立国会図書館", "フランス国立図書館", "アメリカ議会図書館管理番号", "CiNii", "バーチャル国際典拠ファイル"}

のような結果を返してきます。

冒頭で述べた「SMAP」と「槇原敬之」の共通項目を計算すると、

--> {"スポーツニッポン", "ABO式血液型", "テレビ朝日", "東京都", "社長", "エフエム東京", "ミュージックステーション", "J-POP", "第42回NHK紅白歌合戦", "大阪城ホール", "日本", "We are SMAP!", "ミリオンセラー", "小倉博和", "インターネットアーカイブ", "日本武道館", "ニッポン放送", "リクルートホールディングス", "日刊スポーツ", "第58回NHK紅白歌合戦", "フジテレビジョン", "世界に一つだけの花"}

のようになります。

おおよその主要言語に対応していますが、ロシア語をはじめとするキリル文字の言語を指定すると、なぜか結果が返ってきません。これが、キリル文字のエンコーディングに関する(こちら側の実装がまずい)問題なのか、サーバー側がREST APIをサポートしていないのか(Wikipediaサーバー側の問題)はわかりません。
→ ロシア語のクエリーも処理できることを確認しました

ここでは、だいたいの「いい感じのキーワード」を例として出していますが「George Lucas」と「Steven Spielberg」などの近い単語を指定すると結果が400個以上返ってきます。
→ v1.1における改良により、400個以上のリンクを66個まで減少させました(不要なフッター部分のリンクを拾わないようにした)

膨大な項目から必要な要素を選択するInterfaceをみつくろってテストをしてはいるのですが、iOS上でよさそうに見えてもMac上で動かすといまひとつだったり、なかなか合うものが見つかりません(超多項目選択UI)。

–> Watch Demo

こうした計算結果をもっと減らす方法や、これらの多項目の計算結果からGUI上で項目選択する方法などが自分たちでは見つからなかったので、ライブラリとして公開して広く意見やアイデアを募ろうと考えました。多言語のWikipediaへの問い合わせを行ったり、問題点を洗い出すことも目的の1つです。前述のとおり、ロシア語系のWikipediaに対するアクセスに問題がある点については調査が必要です。

余談ですが、Steve JobsとLarry Teslerの関連項目演算を行おうとしても、Larry Teslerの項目がなかったり、Xerox PARCへのリンクがないために演算結果にこれが含まれない言語のWikipediaがいくつか見られました。コンピュータ史上重要な偉人への敬意をこめ、ぜひ追記していただきたいと考えるものです(という話を日本語で書いても意味がない?)。

AppleScript name:sample.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/02/28
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
— http://www.piyocast.com

use comLib : script "common elements Lib"

–English
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResEN to list up common elements with {aWord, bWord} with language "en"
–> {"The New York Times", "Computer History Museum", "Alan Kay", "International Standard Book Number", "California", "Steve Jobs", "Computer mouse", "John Markoff", "Ethernet", "Stanford University", "Counterculture of the 1960s", "Fortune (magazine)", "Tablet computer", "Apple Lisa", "Apple Inc.", "Associated Press", "Graphical user interface", "International Standard Serial Number", "Apple Computer", "Macintosh 128K", "Xerox Alto"}

–日本語(Japanese)
set aWord to "スティーブ・ジョブズ" –Steve Jobs
set bWord to "ラリー・テスラー" –Larry Tesler
set commonResJP to list up common elements with {aWord, bWord} with language "jp"
–> {"パロアルト研究所", "Smalltalk", "アメリカ合衆国", "Lisa (コンピュータ)", "アップル・ニュートン", "Macintosh", "アップル (企業)", "Macworld", "スタンフォード大学"}

–中文(Simplified Chinese)
set aWord to "史蒂夫·乔布斯" –Steve Jobs
set bWord to "拉里·泰斯勒" –Larry Tesler
set commonResZH to list up common elements with {aWord, bWord} with language "zh"
–> {"母校", "美國", "帕羅奧多研究中心"}

—한국어(Korean)
set aWord to "스티브 잡스" –Steve Jobs
set bWord to "빌 게이츠" –Bill Gates
set commonResKO to list up common elements with {aWord, bWord} with language "ko"
—> {"가상 국제 전거 파일", "위키인용집", "게마인자메 노름다타이", "네덜란드 왕립도서관", "국제 표준 도서 번호", "IBM", "SNAC", "CiNii", "개인용 컴퓨터", "BIBSYS", "영어", "국제 표준 명칭 식별자", "오스트레일리아 국립도서관", "LIBRIS", "체코 국립도서관", "미국", "스페인 국립도서관", "뮤직브레인즈", "프랑스 국립도서관", "이스라엘 국립도서관", "일본 국립국회도서관", "미국 의회도서관 제어 번호", "전거 통제", "국립중앙도서관", "WorldCat Identities", "실리콘 밸리의 신화", "프랑스 대학도서관 종합목록", "위키미디어 공용"}

–svenska
set aWord to "Steve Jobs"
set bWord to "Ross Perot"
set commonResSV to list up common elements with {aWord, bWord} with language "sv"
–> {"USA", "IBM", "Forbes", "Entreprenör", "Libris (bibliotekskatalog)"}

–Deutsch
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResDE to list up common elements with {aWord, bWord} with language "de"
–> {"Objektorientierte Programmierung", "Apple", "Apple Macintosh", "Xerox PARC", "Virtual International Authority File", "The New York Times", "Kalifornien", "Apple Lisa"}

–français
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResFR to list up common elements with {aWord, bWord} with language "fr"
–> {"The New York Times", "Palo Alto Research Center", "Informaticien", "Californie", "Apple", "États-Unis", "Autorité (sciences de l’information)"}

–Nederlands
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResNL to list up common elements with {aWord, bWord} with language "nl"
–> {"Verenigde Staten (hoofdbetekenis)", "Palo Alto Research Center", "Apple Macintosh", "Xerox", "Apple Inc.", "Apple Lisa", "Apple Newton"}

–italiano
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResIT to list up common elements with {aWord, bWord} with language "it"
–>{"Apple", "Stati Uniti d’America", "Xerox Palo Alto Research Center", "Informatico"}

–español
set aWord to "Steve Jobs"
set bWord to "Ross Perot"
set commonResES to list up common elements with {aWord, bWord} with language "es"
–> {"Emprendedor", "Library of Congress Control Number", "Wikidata", "IBM", "Enciclopedia Británica", "Wikimedia Commons", "Empresario", "CiNii", "National Diet Library", "Estados Unidos", "National Library of the Czech Republic", "Virtual International Authority File", "Bibliothèque nationale de France", "International Standard Name Identifier", "Integrated Authority File", "Système universitaire de documentation", "ISBN"}

–polski
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResPL to list up common elements with {aWord, bWord} with language "pl"
–> {"Apple Inc.", "Virtual International Authority File", "Xerox PARC"}

–Tiếng Việt
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResVI to list up common elements with {aWord, bWord} with language "vi"
–> {"Hoa Kỳ", "Apple Lisa", "California", "Apple Inc."}

–Arabic
set aWord to "ستيف جوبز"
set bWord to "روس بيرو"
set commonResAR to list up common elements with {aWord, bWord} with language "ar"
–> {"مكتبة البرلمان الوطني", "رقم الضبط في مكتبة الكونغرس", "رائد أعمال", "المكتبة الوطنية لجمهورية التشيك", "ملف استنادي متكامل", "ملف استنادي دولي افتراضي", "المكتبة الوطنية الفرنسية", "سايني", "ديل", "آي بي إم", "لغة إنجليزية", "ضبط استنادي", "حزب سياسي", "مهنة", "مدرسة أم", "واي باك مشين", "الولايات المتحدة", "المحدد المعياري الدولي للأسماء", "دولار أمريكي"}

–português
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResPT to list up common elements with {aWord, bWord} with language "pt"
–> {"Macintosh", "Alan Kay", "Apple Newton", "Povo dos Estados Unidos", "Língua inglesa", "Estados Unidos", "Ciência da computação", "Apple", "Califórnia", "Base Virtual Internacional de Autoridade"}

–Català
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResCA to list up common elements with {aWord, bWord} with language "ca"
–> {"Control d’autoritats", "Virtual International Authority File", "Apple Macintosh", "Apple Inc", "Interfície gràfica d’usuari"}

–Bahasa Indonesia
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResNO to list up common elements with {aWord, bWord} with language "id"
–> {"California", "Biografi", "Amerika Serikat"}

–magyar
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResHU to list up common elements with {aWord, bWord} with language "hu"
–> {"Amerikai Egyesült Államok", "Informatikus", "Wikimédia Commons", "Stanford Egyetem", "Nemzetközi Virtuális Katalógustár"}

–euskara
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResEU to list up common elements with {aWord, bWord} with language "eu"
–> {"Xerox", "Informatikari", "Ingeles", "Apple Inc.", "Ameriketako Estatu Batuak", "Wikidata", "Smalltalk", "Virtual International Authority File", "Stanford Unibertsitatea", "Wikimedia Commons"}

–Türkçe
set aWord to "Steve Jobs"
set bWord to "Larry Tesler"
set commonResTR to list up common elements with {aWord, bWord} with language "tr"
–> {"The New York Times", "Apple", "Amerika Birleşik Devletleri", "Kaliforniya"}

★Click Here to Open This Script 

AppleScript name:sample2
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/02/28
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
— http://www.piyocast.com

use comLib : script "common elements Lib"

set sList to supported lang codes
–> {"en", "ceb", "sv", "de", "fr", "nl", "ru", "it", "es", "pl", "war", "vi", "jp", "zh", "ar", "pt", "uk", "fa", "ca", "sr", "no", "id", "ko", "fi", "hu", "sh", "cs", "ro", "eu", "tr", "ms", "eo", "hy", "bg", "he", "da", "ce", "zh-min-nan", "sk", "kk", "min", "hr", "et", "lt", "be", "el", "azb", "sl", "gl", "az", "simple", "ur", "nn", "hi", "th", "ka", "uz", "la", "ta", "vo", "arz", "cy", "mk", "tg", "lv", "ast", "mg", "tt", "af", "oc", "bs", "bn", "ky", "sq", "zh-yue", "tl", "new", "te", "be-tarask", "br", "ml", "pms", "nds", "su", "ht", "lb", "jv", "sco", "mr", "sw", "pnb", "ga", "szl", "ba", "is", "my", "fy", "cv", "lmo", "an", "ne", "pa", "yo", "bar", "io", "gu", "wuu", "als", "ku", "scn", "kn", "ckb", "bpy", "ia", "qu", "mn", "bat-smg", "vec", "wa", "si", "or", "cdo", "gd", "yi", "am", "nap", "ilo", "bug", "xmf", "mai", "hsb", "map-bms", "fo", "diq", "mzn", "sd", "li", "eml", "sah", "nv", "os", "sa", "ps", "ace", "mrj", "frr", "zh-classical", "mhr"}

–"ru", "uk", "sh", "bg" seems not to work… "ms" or later codes seems not to work (depends on Wikipedia Server spec)….

★Click Here to Open This Script 

Posted in Internet Language Natural Language Processing REST API Script Libraries sdef | Tagged 10.10savvy 10.11savvy 10.12savvy 10.13savvy 10.14savvy 10.15savvy | 1 Comment

Google Chromeで最前面のWindowで表示中のページのHTMLソースを取得する

Posted on 9月 30, 2019 by Takaaki Naganoya

Google Chromeの最前面のウィンドウで表示中のページのHTMLソースを取得するAppleScriptです。

ChromeをMacの自動処理の部品として使おうとはまったく考えませんが、命令が存在しないぐらいで「できない」というのも何なので、JavaScript経由でソースを取得できないか調べてみたら、できました。

あらかじめ、Google Chromeの「表示」>「開発/管理」>「Apple EventsからのJavaScriptを許可」を実行しておく必要があります。

AppleScript名:最前面のウィンドウのHTMLソースを取得する
tell application "Google Chrome"
  tell window 1
    tell active tab
      set htmlRes to (execute javascript "document.getElementsByTagName(’html’)[0].innerHTML")
    end tell
  end tell
end tell

★Click Here to Open This Script 

com.google.Chrome

Posted in Internet JavaScript | Tagged 10.12savvy 10.13savvy 10.14savvy Google Chrome | Leave a comment

Safariで指定のDOM Elementの情報を取得する

Posted on 9月 22, 2019 by Takaaki Naganoya

Safariで表示中の最前面のDocument内の指定Tag、指定Index(出現順、0はじまり)のDOM Elementの詳細なプロパティ値を取得するAppleScriptです。

複数のTableが存在しているページのそれぞれのプロパティ値を取得してdiffを取るための調査用Scriptです。

AppleScript名:Safariで指定のDOM Elementの情報を取得する
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

tell application "Safari"
  set jsStr to "var elementsArray = document.body.getElementsByTagName(’table’);
    aVar = window.getComputedStyle(elementsArray[1]);
  JSON.stringify(aVar);"
  
  
set aHeight to do JavaScript jsStr in front document
  
set cRes to parseJSONAsRecord(aHeight) of me
end tell

–> {|95|:"font-style", |50|:"caret-color", |96|:"font-synthesis", |51|:"clear", |97|:"font-variant", webkitMaskPosition:"0% 0%", |52|:"clip", |98|:"font-variant-alternates", webkitHyphens:"manual", |right|:"auto", |53|:"clip-path", |99|:"font-variant-caps", |54|:"clip-rule", backgroundAttachment:"scroll", willChange:"auto", |55|:"color", margin:"0px 0px 20px", marginTop:"0px", |10|:"animation-name", |56|:"color-interpolation", webkitColumnBreakBefore:"auto", baselineShift:"baseline", webkitLineSnap:"none", |11|:"animation-play-state", |57|:"color-interpolation-filters", scrollSnapMargin:"0px", transform:"none", |12|:"animation-timing-function", |58|:"color-rendering", |13|:"background-attachment", |59|:"color-scheme", fontVariantPosition:"normal", gridAutoFlow:"row", |14|:"background-blend-mode", position:"static", |15|:"background-clip", |16|:"background-color", |17|:"background-image", webkitMaskComposite:"source-over", |18|:"background-origin", justifyItems:"normal", |19|:"background-position", colorRendering:"auto", |color|:"rgb(51, 51, 51)", listStyleImage:"none", borderBottom:"0px none rgb(128, 128, 128)", backgroundOrigin:"padding-box", counterIncrement:"none", webkitMaskRepeatY:"", writingMode:"horizontal-tb", borderInlineEndStyle:"none", columnGap:"normal", textDecorationLine:"none", scrollSnapMarginBottom:"0px", strokeColor:"rgba(0, 0, 0, 0)", webkitBoxOrdinalGroup:"1", alignItems:"normal", caretColor:"rgb(51, 51, 51)", webkitMarginBottomCollapse:"collapse", paddingLeft:"0px", fontWeight:"normal", padding:"0px", scrollPaddingTop:"0px", flexGrow:"0", boxSizing:"border-box", webkitBackgroundSize:"auto", marginBottom:"20px", gridTemplateRows:"none", background:"rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box", fontDisplay:"", speakAs:"normal", |left|:"auto", webkitBoxDecorationBreak:"slice", scrollSnapAlign:"none none", backgroundPosition:"0% 0%", gridRowStart:"auto", borderBlockStartWidth:"0px", borderTopLeftRadius:"0px", webkitUserDrag:"auto", borderRightColor:"rgb(128, 128, 128)", fontVariantAlternates:"normal", breakInside:"auto", webkitTextZoom:"normal", marker:"", webkitClipPath:"none", strokeLinejoin:"miter", webkitMarquee:"", breakAfter:"auto", webkitMaskPositionX:"0%", whiteSpace:"normal", backgroundColor:"rgba(0, 0, 0, 0)", flexDirection:"row", columns:"auto auto", transformOriginX:"", clip:"auto", emptyCells:"show", transformOrigin:"413.75px 309.4021911621094px", borderLeftColor:"rgb(128, 128, 128)", flex:"0 1 auto", webkitTextStroke:"", clipRule:"nonzero", grid:"none / none / none / row / auto / auto", listStyleType:"disc", maxWidth:"none", borderInlineStartStyle:"none", webkitTextOrientation:"mixed", clipPath:"none", justifySelf:"auto", clear:"none", transformOriginY:"", overflowWrap:"break-word", webkitHyphenateLimitAfter:"auto", tabSize:"8", marginBlockStart:"0px", |120|:"image-rendering", unicodeRange:"", gridColumnEnd:"auto", webkitRubyPosition:"before", |220|:"text-rendering", animationDirection:"normal", webkitMaskOrigin:"border-box", |121|:"isolation", fontStyle:"normal", |320|:"-webkit-text-emphasis-position", |221|:"text-shadow", webkitTextFillColor:"rgb(51, 51, 51)", |122|:"justify-content", borderBottomLeftRadius:"0px", |321|:"-webkit-text-emphasis-style", |80|:"fill-rule", |222|:"text-transform", |123|:"justify-items", |81|:"filter", |322|:"-webkit-text-fill-color", transformOriginZ:"", borderRightWidth:"0px", |82|:"flex-basis", |223|:"text-underline-position", |124|:"justify-self", webkitTextSizeAdjust:"auto", |83|:"flex-direction", |323|:"-webkit-text-orientation", |224|:"top", |84|:"flex-flow", |125|:"kerning", |150|:"opacity", |85|:"flex-grow", |324|:"-webkit-text-security", borderBlockStartStyle:"none", |225|:"touch-action", |40|:"border-top-color", |86|:"flex-shrink", |126|:"left", |250|:"-apple-color-filter", |151|:"order", |41|:"border-top-left-radius", |87|:"flex-wrap", |325|:"-webkit-text-size-adjust", |226|:"transform", border:"0px none rgb(128, 128, 128)", |42|:"border-top-right-radius", |88|:"float", |127|:"letter-spacing", |152|:"orphans", |251|:"-webkit-appearance", |43|:"border-top-style", |89|:"flood-color", |227|:"transform-box", |326|:"-webkit-text-stroke-color", |252|:"-webkit-backdrop-filter", |44|:"border-top-width", |128|:"lighting-color", |153|:"outline-color", |327|:"-webkit-text-stroke-width", borderBlockEndColor:"rgb(128, 128, 128)", |45|:"bottom", |228|:"transform-origin", borderInlineEnd:"0px none rgb(128, 128, 128)", |253|:"-webkit-backface-visibility", |129|:"line-break", |46|:"box-shadow", |154|:"outline-offset", |328|:"-webkit-text-zoom", alignContent:"normal", borderLeftStyle:"none", |47|:"box-sizing", |229|:"transform-style", |254|:"-webkit-background-clip", colorScheme:"auto", shapeOutside:"none", |48|:"buffered-rendering", |155|:"outline-style", |180|:"ry", |329|:"-webkit-transform-style", minBlockSize:"0px", |49|:"caption-side", |255|:"-webkit-background-composite", inlineSize:"827.5px", |280|:"-webkit-font-kerning", |156|:"outline-width", textDecorationColor:"rgb(51, 51, 51)", |181|:"scroll-padding", transitionProperty:"all", webkitBoxDirection:"normal", webkitInitialLetter:"normal", |256|:"-webkit-background-origin", gridColumn:"auto / auto", |281|:"-webkit-font-smoothing", |157|:"overflow-wrap", listStyle:"disc outside none", |182|:"scroll-padding-bottom", webkitMaskBoxImage:"none", floodColor:"rgb(0, 0, 0)", webkitTextEmphasisPosition:"over right", |257|:"-webkit-background-size", scrollSnapMarginRight:"0px", |282|:"-webkit-hyphenate-character", |158|:"overflow-x", webkitTextSecurity:"none", |183|:"scroll-padding-left", columnRule:"0px none rgb(51, 51, 51)", |258|:"-webkit-border-fit", gridColumnStart:"auto", |283|:"-webkit-hyphenate-limit-after", |159|:"overflow-y", touchAction:"auto", |184|:"scroll-padding-right", webkitFontSizeDelta:"", webkitLocale:"ja", |259|:"-webkit-border-horizontal-spacing", |284|:"-webkit-hyphenate-limit-before", colorInterpolation:"sRGB", borderTopColor:"rgb(128, 128, 128)", |185|:"scroll-padding-top", |285|:"-webkit-hyphenate-limit-lines", hangingPunctuation:"none", |186|:"scroll-snap-align", mask:"none", borderRight:"0px none rgb(128, 128, 128)", paddingInlineStart:"0px", webkitBackgroundOrigin:"padding-box", |286|:"-webkit-hyphens", |187|:"scroll-snap-margin", pageBreakAfter:"auto", colorProfile:"", textAnchor:"start", |287|:"-webkit-initial-letter", webkitMaskSize:"auto", |188|:"scroll-snap-margin-bottom", overflowX:"visible", |288|:"-webkit-line-align", strokeLinecap:"butt", |189|:"scroll-snap-margin-left", |289|:"-webkit-line-box-contain", borderBottomColor:"rgb(128, 128, 128)", paddingRight:"0px", fontOpticalSizing:"auto", borderImage:"none", floodOpacity:"1", webkitAspectRatio:"auto", webkitColumnProgression:"normal", alignSelf:"auto", display:"table", borderRadius:"0px", maxInlineSize:"none", minHeight:"0px", strokeMiterlimit:"4", webkitBorderVerticalSpacing:"0px", webkitMaskClip:"border-box", webkitBorderHorizontalSpacing:"0px", objectPosition:"50% 50%", kerning:"0", borderStyle:"none", visibility:"visible", textShadow:"none", borderLeftWidth:"0px", shapeImageThreshold:"0", scrollSnapMarginTop:"0px", markerMid:"none", scrollPadding:"0px", markerEnd:"none", webkitFontKerning:"auto", borderBottomWidth:"0px", float:"none", placeSelf:"auto auto", webkitBackgroundComposite:"source-over", borderTop:"0px none rgb(128, 128, 128)", backgroundRepeat:"repeat", webkitMarqueeDirection:"auto", animationIterationCount:"1", backgroundPositionX:"0%", content:"", transformStyle:"flat", borderInlineEndColor:"rgb(128, 128, 128)", borderBlockStart:"0px none rgb(128, 128, 128)", overflow:"visible", webkitMaskPositionY:"0%", perspective:"none", strokeDashoffset:"0px", outlineColor:"rgb(51, 51, 51)", webkitMarqueeSpeed:"", webkitTextEmphasisStyle:"none", isolation:"auto", borderInlineStartColor:"rgb(128, 128, 128)", textDecorationSkip:"auto", outlineOffset:"0px", objectFit:"fill", textUnderlineOffset:"auto", webkitAppearance:"none", webkitMaskBoxImageWidth:"auto", animationTimingFunction:"ease", borderWidth:"0px", borderSpacing:"0px 0px", captionSide:"top", columnWidth:"auto", rowGap:"normal", webkitMaskBoxImageSource:"none", webkitRtlOrdering:"logical", |70|:"counter-reset", paddingInlineEnd:"0px", |71|:"cursor", |72|:"cx", fontSize:"14.000000953674316px", |73|:"cy", vectorEffect:"none", |74|:"direction", justifyContent:"normal", fillRule:"nonzero", |75|:"display", fontSynthesis:"style weight small-caps", |30|:"border-image-repeat", |76|:"dominant-baseline", |31|:"border-image-slice", |77|:"empty-cells", pageBreakBefore:"auto", |32|:"border-image-source", |78|:"fill", cx:"0px", webkitMaskBoxImageRepeat:"stretch", borderImageSource:"none", |33|:"border-image-width", |79|:"fill-opacity", cy:"0px", outlineStyle:"none", webkitBoxFlex:"0", |34|:"border-left-color", width:"827.5px", webkitMarginBeforeCollapse:"collapse", |35|:"border-left-style", borderRightStyle:"none", |36|:"border-left-width", |0|:"align-content", |37|:"border-right-color", |1|:"align-items", paddingBlockStart:"0px", |size|:"", |2|:"align-self", |38|:"border-right-style", |3|:"alignment-baseline", |4|:"alt", |39|:"border-right-width", webkitFontSmoothing:"auto", |5|:"animation-delay", borderTopWidth:"0px", |6|:"animation-direction", |100|:"font-variant-east-asian", |7|:"animation-duration", |8|:"animation-fill-mode", |200|:"stroke", |9|:"animation-iteration-count", webkitTransformStyle:"flat", |101|:"font-variant-ligatures", counterReset:"none", |300|:"-webkit-mask-box-image", maskType:"luminance", webkitBoxShadow:"none", |201|:"stroke-color", borderBlockEndStyle:"none", |102|:"font-variant-numeric", fontStretch:"normal", textDecorationStyle:"solid", |301|:"-webkit-mask-box-image-outset", cursor:"auto", |202|:"stroke-dasharray", webkitMarqueeStyle:"scroll", |103|:"font-variant-position", animationFillMode:"none", glyphOrientationVertical:"auto", |302|:"-webkit-mask-box-image-repeat", |203|:"stroke-dashoffset", textRendering:"auto", |104|:"font-variation-settings", borderImageRepeat:"stretch", |303|:"-webkit-mask-box-image-slice", |204|:"stroke-linecap", height:"618.8043823242188px", |105|:"font-weight", all:"", |130|:"line-height", |304|:"-webkit-mask-box-image-source", pointerEvents:"auto", textTransform:"none", |205|:"stroke-linejoin", dominantBaseline:"auto", |230|:"transition-delay", |106|:"glyph-orientation-horizontal", filter:"none", |131|:"list-style-image", |305|:"-webkit-mask-box-image-width", |330|:"-webkit-user-drag", |206|:"stroke-miterlimit", paintOrder:"normal", |231|:"transition-duration", |107|:"glyph-orientation-vertical", placeItems:"normal normal", |132|:"list-style-position", |306|:"-webkit-mask-clip", borderInlineStart:"0px none rgb(128, 128, 128)", |331|:"-webkit-user-modify", |207|:"stroke-opacity", textOverflow:"clip", |232|:"transition-property", |108|:"grid-auto-columns", webkitBackdropFilter:"none", |133|:"list-style-type", |307|:"-webkit-mask-composite", webkitMaskRepeat:"repeat", |332|:"-webkit-user-select", |208|:"stroke-width", webkitBoxReflect:"none", |233|:"transition-timing-function", |109|:"grid-auto-flow", |134|:"margin-bottom", |308|:"-webkit-mask-image", |333|:"fullscreen-inset-bottom", |209|:"tab-size", |234|:"unicode-bidi", flexWrap:"nowrap", wordSpacing:"0px", |135|:"margin-left", |309|:"-webkit-mask-origin", |160|:"padding-bottom", |334|:"safe-area-inset-bottom", flexFlow:"row nowrap", |235|:"vector-effect", |260|:"-webkit-border-image", |136|:"margin-right", |161|:"padding-left", |335|:"safe-area-inset-left", transition:"all 0s ease 0s", |236|:"vertical-align", columnFill:"balance", |261|:"-webkit-border-vertical-spacing", |137|:"margin-top", |162|:"padding-right", |336|:"fullscreen-inset-left", maxHeight:"none", |237|:"visibility", alt:"\"\"", |262|:"-webkit-box-align", |138|:"marker-end", marginInlineEnd:"0px", |163|:"padding-top", |337|:"fullscreen-inset-right", webkitMarginTopCollapse:"collapse", |238|:"white-space", gridRowEnd:"auto", |263|:"-webkit-box-decoration-break", |139|:"marker-mid", |164|:"page-break-after", |338|:"fullscreen-auto-hide-duration", fillOpacity:"1", |239|:"widows", |264|:"-webkit-box-direction", overflowY:"visible", |165|:"page-break-before", |339|:"safe-area-inset-right", |190|:"scroll-snap-margin-right", |265|:"-webkit-box-flex", animationDuration:"0s", |290|:"-webkit-line-clamp", |166|:"page-break-inside", marginRight:"0px", |191|:"scroll-snap-margin-top", |266|:"-webkit-box-flex-group", borderInlineStartWidth:"0px", |291|:"-webkit-line-grid", |167|:"paint-order", webkitNbspMode:"normal", |192|:"scroll-snap-type", |267|:"-webkit-box-lines", mixBlendMode:"normal", |292|:"-webkit-line-snap", |168|:"perspective", paddingBlockEnd:"0px", |193|:"shape-image-threshold", src:"", webkitBoxAlign:"stretch", |268|:"-webkit-box-ordinal-group", paddingTop:"0px", |293|:"-webkit-locale", |169|:"perspective-origin", borderBlockEnd:"0px none rgb(128, 128, 128)", |194|:"shape-margin", r:"0px", textAlign:"start", |269|:"-webkit-box-orient", webkitMaskBoxImageOutset:"0px", |294|:"-webkit-margin-after-collapse", webkitTextEmphasis:"", webkitTextStrokeColor:"rgb(51, 51, 51)", |195|:"shape-outside", breakBefore:"auto", wordWrap:"break-word", |295|:"-webkit-margin-before-collapse", minInlineSize:"0px", |196|:"shape-rendering", borderInlineEndWidth:"0px", webkitLineAlign:"none", webkitMaskBoxImageSlice:"0 fill", widows:"auto", perspectiveOrigin:"413.75px 309.4021911621094px", |296|:"-webkit-marquee-direction", x:"0px", y:"0px", |197|:"speak-as", perspectiveOriginX:"", |297|:"-webkit-marquee-increment", |198|:"stop-color", fontFamily:"-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif", |298|:"-webkit-marquee-repetition", |199|:"stop-opacity", animationPlayState:"running", webkitHyphenateLimitBefore:"auto", |299|:"-webkit-marquee-style", webkitBoxOrient:"horizontal", order:"0", webkitMaskSourceType:"alpha", fontVariantNumeric:"normal", webkitColumnBreakAfter:"auto", webkitColumnBreakInside:"auto", shapeMargin:"0px", webkitMaskImage:"none", top:"auto", backgroundBlendMode:"normal", listStylePosition:"outside", bottom:"auto", gridTemplateColumns:"none", strokeWidth:"0.8695652484893799px", borderTopRightRadius:"0px", direction:"ltr", webkitBackfaceVisibility:"visible", backgroundPositionY:"0%", rx:"0px", webkitHyphenateLimitLines:"no-limit", ry:"0px", lineBreak:"auto", bufferedRendering:"auto", quotes:"", gridRow:"auto / auto", webkitBorderFit:"border", borderBottomRightRadius:"0px", alignmentBaseline:"auto", textIndent:"0px", paddingBottom:"0px", columnRuleColor:"rgb(51, 51, 51)", fontVariantCaps:"normal", backgroundSize:"auto", |60|:"column-count", columnCount:"auto", |61|:"column-fill", webkitBoxLines:"single", webkitBoxFlexGroup:"1", backgroundRepeatX:"", |62|:"column-gap", glyphOrientationHorizontal:"0deg", lineHeight:"20px", |63|:"column-rule-color", borderBlockEndWidth:"0px", opacity:"1", webkitBackgroundClip:"border-box", webkitBoxPack:"start", |64|:"column-rule-style", |65|:"column-rule-width", borderImageWidth:"1", fontVariantLigatures:"normal", |20|:"background-repeat", |66|:"column-span", |21|:"background-size", |67|:"column-width", gridTemplateAreas:"none", tableLayout:"auto", |22|:"baseline-shift", |68|:"content", webkitBorderImage:"none", |23|:"border-bottom-color", |69|:"counter-increment", animationName:"none", letterSpacing:"normal", |24|:"border-bottom-left-radius", |25|:"border-bottom-right-radius", backgroundClip:"border-box", transitionDelay:"0s", |26|:"border-bottom-style", |27|:"border-bottom-width", webkitCursorVisibility:"auto", |28|:"border-collapse", webkitTextDecorationsInEffect:"none", |29|:"border-image-outset", fill:"rgb(0, 0, 0)", webkitHyphenateCharacter:"auto", animation:"", pageBreakInside:"auto", lightingColor:"rgb(255, 255, 255)", webkitLineClamp:"none", perspectiveOriginY:"", textDecorationThickness:"auto", marginInlineStart:"0px", borderTopStyle:"none", placeContent:"normal normal", backgroundRepeatY:"", textUnderlinePosition:"auto", wordBreak:"normal", columnRuleStyle:"none", webkitUserModify:"read-only", columnSpan:"none", strokeOpacity:"1", webkitMarqueeRepetition:"infinite", webkitMarginCollapse:"", flexBasis:"auto", colorInterpolationFilters:"linearRGB", gap:"normal normal", webkitMask:"", gridArea:"auto / auto / auto / auto", gridTemplate:"none / none / none", resize:"none", borderColor:"rgb(128, 128, 128)", zIndex:"auto", webkitTextCombine:"none", webkitTextStrokeWidth:"0px", borderBottomStyle:"none", fontVariant:"normal", scrollSnapType:"none", textDecoration:"none", webkitTextEmphasisColor:"rgb(51, 51, 51)", orphans:"auto", scrollPaddingRight:"0px", borderImageOutset:"0px", webkitTextDecoration:"none solid rgb(51, 51, 51)", |110|:"grid-auto-rows", marginLeft:"0px", transitionTimingFunction:"ease", |210|:"table-layout", stroke:"none", stopOpacity:"1", |111|:"grid-column-end", |310|:"-webkit-mask-position", stopColor:"rgb(0, 0, 0)", webkitPrintColorAdjust:"economy", |211|:"text-align", unicodeBidi:"normal", |112|:"grid-column-start", |311|:"-webkit-mask-repeat", page:"", |212|:"text-anchor", |113|:"grid-row-end", |312|:"-webkit-mask-size", fontFeatureSettings:"normal", |213|:"text-decoration", |114|:"grid-row-start", webkitMarqueeIncrement:"6px", webkitUserSelect:"text", |313|:"-webkit-mask-source-type", gridAutoRows:"auto", |214|:"text-decoration-color", |115|:"grid-template-areas", |140|:"marker-start", |314|:"-webkit-nbsp-mode", scrollPaddingBottom:"0px", |215|:"text-decoration-line", |240|:"width", |116|:"grid-template-columns", |141|:"mask", |315|:"-webkit-print-color-adjust", borderBlockStartColor:"rgb(128, 128, 128)", |340|:"fullscreen-inset-top", |216|:"text-decoration-skip", fontVariantEastAsian:"normal", |241|:"will-change", |117|:"grid-template-rows", fontVariationSettings:"normal", |142|:"mask-type", |316|:"-webkit-rtl-ordering", marginBlockEnd:"20px", |341|:"safe-area-inset-top", |217|:"text-decoration-style", minWidth:"0px", |242|:"word-break", |118|:"hanging-punctuation", zoom:"1", |143|:"max-height", |317|:"-webkit-text-combine", |218|:"text-indent", gridAutoColumns:"auto", |243|:"word-spacing", |119|:"height", verticalAlign:"baseline", |144|:"max-width", |318|:"-webkit-text-decorations-in-effect", imageRendering:"auto", maxBlockSize:"none", |219|:"text-overflow", outlineWidth:"0px", |244|:"word-wrap", shapeRendering:"auto", webkitLineGrid:"none", |145|:"min-height", |319|:"-webkit-text-emphasis-color", |170|:"place-content", enableBackground:"", |245|:"writing-mode", |270|:"-webkit-box-pack", |146|:"min-width", animationDelay:"0s", |171|:"place-items", boxShadow:"none", scrollSnapMarginLeft:"0px", webkitBorderRadius:"", |246|:"x", |271|:"-webkit-box-reflect", |147|:"mix-blend-mode", |172|:"place-self", |247|:"y", blockSize:"618.8043823242188px", |272|:"-webkit-box-shadow", |148|:"object-fit", columnRuleWidth:"0px", |173|:"pointer-events", backgroundImage:"none", |248|:"z-index", |273|:"-webkit-clip-path", |149|:"object-position", transitionDuration:"0s", |174|:"position", |249|:"zoom", |274|:"-webkit-column-axis", webkitColumnAxis:"auto", |175|:"r", borderImageSlice:"100%", |275|:"-webkit-column-break-after", borderCollapse:"collapse", |176|:"resize", |276|:"-webkit-column-break-before", webkitLineBoxContain:"block inline replaced", |177|:"right", |277|:"-webkit-column-break-inside", |178|:"row-gap", borderLeft:"0px none rgb(128, 128, 128)", |font|:"normal normal normal normal 14.000000953674316px/20px -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif", webkitMarginAfterCollapse:"collapse", |278|:"-webkit-column-progression", |outline|:"rgb(51, 51, 51) none 0px", scrollPaddingLeft:"0px", |90|:"flood-opacity", |179|:"rx", markerStart:"none", strokeDasharray:"none", |91|:"font-family", |279|:"-webkit-cursor-visibility", flexShrink:"1", webkitMaskRepeatX:"", |92|:"font-optical-sizing", transformBox:"border-box", |93|:"font-size", |94|:"font-stretch"}

on parseJSONAsRecord(jsRes)
  set jsonString to current application’s NSString’s stringWithString:jsRes
  
set jsonData to jsonString’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aJsonDict to current application’s NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
return aJsonDict as record
end parseJSONAsRecord

★Click Here to Open This Script 

Posted in Internet JavaScript JSON | Tagged 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSString Safari | 1 Comment

tableExtractor

Posted on 9月 15, 2019 by Takaaki Naganoya

Safariで表示中のページのうち、テキストを選択中のキーワードを含む表をCSVファイルに書き出してNumbersでオープンするAppleScriptです。

–> Download tableExtractor Run-Only (Code-Signed Executable including Framework in its bundle)

–> Watch Demo movie

実行前にSafariの「開発」メニューから、「スマート検索フィールドからのJavaScriptの実行を許可」「AppleEventからのJavaScriptの実行を許可」を実行しておく必要があります(実行済みの場合には必要ありません)。


▲Safariで表示中のページのうち、CSV書き出ししたい表のテキストを選択


▲本Scriptで表をCSVに書き出してNumbersでオープン

以前に作成した「Safariで表示中のPageの選択中の文字を含む表データを取得」Scriptがいい線を行っていた(あらかじめ表中のテキストを選択しておく、という前提条件がかったるいかと思っていたのに、そうでもなかった)ので、ありもののサブルーチンを追加して、表部分のHTMLからのタグ削除やCSV書き出しなどを行えるようにしました。

本Scriptは表データをCSV書き出しする必要はどこにもないのですが、Numbers v6.1に「表を新規作成して表のセル数を指定すると多くの場合にエラーになる」というバグがあるので、Numbersを直接操作してデータ出力させることはやっていません。

処理時間もさほどかからないので、表示中のページのすべての表オブジェクトをCSV化したり、表を選択するUIを実装して、「どの表を出力するか?」という選択処理をしてもいいかもしれません。


▲漫然とMacOS日本語で書き出ししたため文字化けしたもの(左)、UTF8を指定して書き出ししたために文字化けしなくなったもの(右)

途中でCSV書き出しした表データに文字化けが発生していたのですが、これはUTF8でファイル書き出ししていなかったためでした。

本Scriptは前バージョンよりもキーワードの検出処理をていねいに行なっています。各TableのHTMLに対してタグの除去を行なったうえでWebブラウザ上で選択中の文字列を含んでいるかどうかをチェックしています。

AppleScript名:tableExtractor.scptd
— Created 2019-09-15 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument
property NSMutableArray : a reference to current application’s NSMutableArray

tell application "Safari"
  set dList to every document –Sometimes "count every document"causes error
  
if length of dList = 0 then return
  
  
–Get URL
  
tell front document
    set aURL to URL
  end tell
  
  
–Get Selected Text
  
set aRes to do JavaScript "var selObj = window.getSelection();
  var selStr = (selObj).getRangeAt(0);
  unescape(selStr);"
in front document
  
  
if aRes = "" then return
end tell

set aRes to filterATableAndPaseCells(aURL, aRes) of me
if aRes = false then
  display notification "I could not filter table data…"
  
return
end if

–Save 2D List to temp CSV file on desktop folder
set savePath to ((path to desktop) as string) & (do shell script "uuidgen") & ".csv"
saveAsCSV(aRes, savePath) of me

tell application "Numbers"
  activate
  
open file savePath
end tell

on filterATableAndPaseCells(aURL, aKeyword)
  set aData to (do shell script "curl " & aURL)
  
set aHTML to current application’s HTMLDocument’s documentWithString:(aData as string)
  
  
–Table要素をリストアップ
  
set eList to (aHTML’s nodesMatchingSelector:"table")
  
  
–Table要素のうちSafari上で選択中の文字列を含むものをサーチ(指定データを含むものを抽出)
  
set hitF to false
  
repeat with i in eList
    set cellList to i’s children()’s array()
    
set htmlSource to i’s serializedFragment() as string –HTML source
    
set html2 to trimStrFromTo(htmlSource, "<", ">") of me
    
set html3 to repChar(html2, return, "") of me
    
    
if html3 contains aKeyword then
      set hitF to true
      
exit repeat
    end if
  end repeat
  
if hitF = false then return false
  
  
–Count columns of Table Header
  
set aTableHeader to (i’s nodesMatchingSelector:"tr")’s firstObject()
  
set hList to aTableHeader’s nodesMatchingSelector:"th"
  
set hStrList to {}
  
repeat with i1 in hList
    set the end of hStrList to i1’s textContent() as string
  end repeat
  
set hLen to length of hStrList –count columns
  
  
–Acquire whole table body contents
  
set aTableBody to (i’s nodesMatchingSelector:"tbody")’s firstObject()
  
set bList to aTableBody’s nodesMatchingSelector:"td"
  
set bbList to {}
  
repeat with i2 in bList
    set the end of bbList to i2’s textContent() as string
  end repeat
  
  
set tbList to makeList1DTo2D(bbList, hLen) of me
  
  
return {hStrList} & tbList
end filterATableAndPaseCells

–1D Listを2D化
on makeList1DTo2D(orig1DList, aMax)
  set tbList to {}
  
set tmpList to {}
  
set aCount to 1
  
  
repeat with i3 in orig1DList
    set j to contents of i3
    
set the end of tmpList to j
    
    
if aCount ≥ aMax then
      set aCount to 1
      
set the end of tbList to tmpList
      
set tmpList to {}
    else
      set aCount to aCount + 1
    end if
  end repeat
  
  
return tbList
end makeList1DTo2D

on trimStrFromTo(aParamStr, fromStr, toStr)
  set theScanner to current application’s NSScanner’s scannerWithString:aParamStr
  
set anArray to current application’s NSMutableArray’s array()
  
  
repeat until (theScanner’s isAtEnd as boolean)
    set {theResult, theKey} to theScanner’s scanUpToString:fromStr intoString:(reference)
    
    
theScanner’s scanString:fromStr intoString:(missing value)
    
set {theResult, theValue} to theScanner’s scanUpToString:toStr intoString:(reference)
    
if theValue is missing value then set theValue to ""
    
    
theScanner’s scanString:toStr intoString:(missing value)
    
    
anArray’s addObject:theValue
  end repeat
  
  
if anArray’s |count|() = 0 then return aParamStr
  
  
copy aParamStr to curStr
  
repeat with i in (anArray as list)
    set curStr to repChar(curStr, fromStr & i & toStr, "") of me
  end repeat
  
  
return curStr
end trimStrFromTo

on repChar(aStr, targStr, repStr)
  set aString to current application’s NSString’s stringWithString:aStr
  
set bString to aString’s stringByReplacingOccurrencesOfString:targStr withString:repStr
  
set cString to bString as string
  
return cString
end repChar

–2D List to CSV file
on saveAsCSV(aList, aPath)
  –set crlfChar to (ASCII character 13) & (ASCII character 10)
  
set crlfChar to (string id 13) & (string id 10)
  
set LF to (string id 10)
  
set wholeText to ""
  
  
repeat with i in aList
    set newLine to {}
    
    
–Sanitize (Double Quote)
    
repeat with ii in i
      set jj to ii as text
      
set kk to repChar(jj, string id 34, (string id 34) & (string id 34)) of me –Escape Double Quote
      
set the end of newLine to kk
    end repeat
    
    
–Change Delimiter
    
set aLineText to ""
    
set curDelim to AppleScript’s text item delimiters
    
set AppleScript’s text item delimiters to "\",\""
    
set aLineList to newLine as text
    
set AppleScript’s text item delimiters to curDelim
    
    
set aLineText to repChar(aLineList, return, "") of me –delete return
    
set aLineText to repChar(aLineText, LF, "") of me –delete lf
    
    
set wholeText to wholeText & "\"" & aLineText & "\"" & crlfChar –line terminator: CR+LF
  end repeat
  
  
if (aPath as string) does not end with ".csv" then
    set bPath to aPath & ".csv" as Unicode text
  else
    set bPath to aPath as Unicode text
  end if
  
  
writeToFileUTF8(wholeText, bPath, false) of me
  
end saveAsCSV

on writeToFileUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileUTF8

★Click Here to Open This Script 

Posted in file Internet JavaScript list Text | Tagged 10.12savvy 10.13savvy 10.14savvy HTMLDocument NSMutableArray NSString Numbers Safari | 1 Comment

FireFoxでURLをオープン(URLの間接指定)

Posted on 3月 31, 2019 by Takaaki Naganoya

FireFoxで指定URLをオープンするAppleScriptです。

FireFoxのAppleScript対応機能は、指定のURLをオープンさせるだけです。しかも、AppleScript用語辞書からアクセスできないという体たらく。2004年ごろに出回っていたサンプルScriptがそのまま最新のバージョンでも動きました。

FireFoxのAppleScript用語辞書を見てもdo javascript的な命令はないですし、ほぼ何もできない内容です(ダミーといってもいいでしょう)。なので、これをスクリプタブルだとはとても言えません。AppleScriptからコントロールする用途でFireFoxを用いることに意味はありません。

いろいろ試していたら、FireFoxが起動していない状態で本Scriptを実行すると、実行が完了しないという問題が報告されました。追試してみるとそのとおりです。あらかじめ、起動しておくなりactivateしておくなどの処理が必要です。

AppleScript名:FireFoxでURLをオープン(URLの間接指定)
set aURL to "http://piyocast.com/as"

tell application "Firefox"
  «event WWW!OURL» aURL
end tell

★Click Here to Open This Script 

Posted in Internet Raw AppleEvent Code URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy FireFox | Leave a comment

アラートダイアログ上にWebViewを表示

Posted on 3月 5, 2019 by Takaaki Naganoya

アラートダイアログ上にWKWebViewを表示するAppleScriptです。

テストのためにYouTubeのムービーの自動再生URL(戦場の絆のリプレイムービー)をオープンしています。


▲Table ViewとWeb Viewを組み合わせて、所定の場所にYouTubeムービーの頭出しを行う試作品を作ってみたものの、JavaScript経由でWKWebViewをコントロールするのが難しくて頓挫

本来であれば、WkWebViewに対してJavaScript経由でさまざまな操作を行いたいところですが、オープン中のWebコンテンツに対して新たなJavaScriptのインスタンスを生成してセキュリティチェックを行なって、実際に実行を行うのが(自分には)少々難しく感じました。WkWebViewだとあまり凝った制御はできない印象です。Safariをコントロールするほうが自由度が高いところ。

WkWebViewを「自由にこづきまわして操作できる部品」として使うためには、素のままのWkWebViewではない何かを使ったほうがいいのかも?

AppleScript名:アラートダイアログ上にWebViewを表示.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2019/03/02
—
–  Copyright © 2019 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSAlert : a reference to current application’s NSAlert
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property WKWebView : a reference to current application’s WKWebView
property NSScrollView : a reference to current application’s NSScrollView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSRunningApplication : a reference to current application’s NSRunningApplication
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property WKUserContentController : a reference to current application’s WKUserContentController
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property NSAlertSecondButtonReturn : a reference to current application’s NSAlertSecondButtonReturn
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property theResult : 0
property returnCode : 0
property theDataSource : {}

set aURL to "https://www.youtube.com/embed/GP_tVXTYdmY?autoplay=1&hd=1"
set paramObj to {myMessage:"Browse a Replay", mySubMessage:"Browse Senjo-No-Kizuna Replay Movie", targURL:aURL}
my performSelectorOnMainThread:"browseWebContents:" withObject:(paramObj) waitUntilDone:true

on browseWebContents:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set tmpURL to (targURL of paramObj)
  
  
set aWidth to 600
  
set aHeight to 450
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
  
–指定URLのJavaScriptをFetch
  
set jsSource to my fetchJSSourceString(tmpURL)
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s URLWithString:tmpURL
  
set aReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:aReq –Webコンテンツのローディング
  
  
— set up alert  
  
set theAlert to NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aWebView
  end tell
  
  
— show alert in modal loop
  
NSRunningApplication’s currentApplication()’s activateWithOptions:0
  
my performSelectorOnMainThread:"doModal:" withObject:(theAlert) waitUntilDone:true
  
  
–Stop Web View Action
  
set bURL to |NSURL|’s URLWithString:"about:blank"
  
set bReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:bReq
  
  
if (my returnCode as number) = 1001 then error number -128
end browseWebContents:

on doModal:aParam
  set (my returnCode) to aParam’s runModal()
end doModal:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

★Click Here to Open This Script 

Posted in Internet URL | Tagged 10.11savvy 10.12savvy 10.13savvy NSAlert NSAlertSecondButtonReturn NSBackingStoreBuffered NSButton NSColor NSMomentaryLightButton NSRunningApplication NSScreen NSString NSURL NSURLRequest NSUTF8StringEncoding WKUserContentController WKUserScript WKUserScriptInjectionTimeAtDocumentEnd WKWebView WKWebViewConfiguration | Leave a comment

アラートダイアログ上にMap Viewを表示

Posted on 2月 19, 2019 by Takaaki Naganoya

アラートダイアログを作成し、その上にMap Viewを表示して位置座標の選択を行うAppleScriptです。

Map Viewを使用するためには、インターネット接続が必要です。

もしこれをAppleScriptのコマンドのように表現するなら「choose geo location」とかいうコマンドになるでしょうか。本当は地図.appのように地図中でクリックした場所にピンを打って選択箇所を明示するようなものを考えていたのですが、実際にASだけで作ろうとすると難しいものがありそうで。

こうした「ざっくり場所を選ぶ」ダイアログのほか、複数の地点をピンで表示し、そのうちのどれかを地図上で選択するといったコマンドがあると使いでがありそうです。

AppleScript名:アラートダイアログ上のMap Viewを表示
— Created 2019-02-14 by Takaaki Naganoya
— 2019 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "MapKit"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSData : a reference to current application’s NSData
property MKMapView : a reference to current application’s MKMapView
property NSURLRequest : a reference to current application’s NSURLRequest
property NSURLConnection : a reference to current application’s NSURLConnection

property theResult : 0
property returnCode : 0

set nRes to hasInternetConnection("http://www.google.com") of me
if nRes = false then error "No Internet Connection…."

–地図表示初期座標。一般的にはWiFi経由でAssistive-GPSから現在位置を拾って指定
set aLong to 130.55723797
set aLat to 31.57868838

set paramObj to {myMessage:"場所の選択", mySubMessage:"目標の場所を地図中央に入れてください", aLongitude:aLong, aLatitude:aLat}
my performSelectorOnMainThread:"chooseCoordinate:" withObject:(paramObj) waitUntilDone:true
return theResult
–> {latitude:31.57868838, longitude:130.55723797}

on chooseCoordinate:paramObj
  set aMainMes to myMessage of paramObj
  
set aSubMes to mySubMessage of paramObj
  
set aLong to aLongitude of paramObj
  
set aLat to aLatitude of paramObj
  
  
–MKMapViewをつくる
  
set aMapView to MKMapView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 500, 300))
  
tell aMapView
    its setMapType:(current application’s MKMapTypeStandard)
    
its setZoomEnabled:true
    
its setScrollEnabled:true
    
its setPitchEnabled:true
    
its setRotateEnabled:true
    
its setShowsCompass:true
    
its setShowsZoomControls:true
    
its setShowsScale:true
    
its setShowsUserLocation:true
    
    
set aLocation to current application’s CLLocationCoordinate2DMake(aLat, aLong)
    
its setCenterCoordinate:aLocation zoomLevel:17 animated:false
    
its setDelegate:me
  end tell
  
  
— set up alert  
  
set theAlert to current application’s NSAlert’s alloc()’s init()
  
tell theAlert
    its setMessageText:aMainMes
    
its setInformativeText:aSubMes
    
its addButtonWithTitle:"OK"
    
its addButtonWithTitle:"Cancel"
    
its setAccessoryView:aMapView
  end tell
  
  
— show alert in modal loop
  
current application’s NSRunningApplication’s currentApplication()’s activateWithOptions:(current application’s NSApplicationActivateIgnoringOtherApps)
  
set returnCode to theAlert’s runModal()
  
if returnCode = (current application’s NSAlertSecondButtonReturn) then error number -128
  
  
set (my theResult) to (aMapView’s centerCoordinate()) as record
end chooseCoordinate:

–Internet Connection Check
on hasInternetConnection(aURLString)
  set aURL to |NSURL|’s alloc()’s initWithString:aURLString
  
set aReq to NSURLRequest’s alloc()’s initWithURL:aURL cachePolicy:(current application’s NSURLRequestReloadIgnoringLocalCacheData) timeoutInterval:5.0
  
set urlRes to (NSURLConnection’s sendSynchronousRequest:aReq returningResponse:(missing value) |error|:(missing value))
  
if urlRes = missing value then
    return false
  else
    return true
  end if
end hasInternetConnection

★Click Here to Open This Script 

Posted in geolocation GUI Internet | Tagged 10.11savvy 10.12savvy 10.13savvy NSData NSURL NSView | Leave a comment

WebView+ボタンを作成 v3(URLから読み込み)

Posted on 11月 28, 2018 by Takaaki Naganoya

WkWebViewを動的に生成して、YouTube上の指定ムービーを再生するAppleScriptです。

# AppleScriptでは、Webブラウザに命令を出せば数行のコマンドで簡単に任意のURLのWebコンテンツを表示させられますが、本ScriptはAppleScriptから他のアプリケーションを介さずに直接Cocoaの機能を呼び出して自前でWebコンテンツを表示させるものです

NSWindow+NSSplitView+WKWebViewを作成して、Webサーバー上の内容を表示します。WkWebViewでWebの内容を表示させるのにかなり苦労しましたが、Objective-Cのサンプル数本を比較してテストし実現しました。

WkWebViewでコンテンツを表示するのにこんなに大変だと思いませんでしたが、これができるようになったおかげで、AppleScriptの処理結果のURLを(Webブラウザを利用せずに)プレビューできます。

グラフ描画のプログラムがJavaScript+WebViewで作られているケースが多々あるため、凝ったインタラクティブなグラフの表示を行ったり画像やPDFに出力できるようにもなったわけで、たいへんけっこうなことです。


▲Auto StartでYouTube上のムービーの再生を開始する

まだ解決できていないのは、YouTubeのムービー再生が始まるとウィンドウをクローズしてAppleScriptの実行が終了していても再生中の音声が停止しないあたりでしょうか。メモリ上からWebブラウザのオブジェクトを明示的にパージする方法についてはまだ実装できていません。

あと、Script Debugger上で動かすと、WkWebView上のコンテンツの操作(YouTube映像の再生コントロールとか)ができなくなります。ねんのため。

AppleScript名:WebView+ボタンを作成 v3(URLから読み込み)
— Created 2018-11-27 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "WebKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSColor : a reference to current application’s NSColor
property NSString : a reference to current application’s NSString
property NSScreen : a reference to current application’s NSScreen
property NSButton : a reference to current application’s NSButton
property NSWindow : a reference to current application’s NSWindow
property NSSplitView : a reference to current application’s NSSplitView
property NSTextView : a reference to current application’s NSTextView
property NSScrollView : a reference to current application’s NSScrollView
property WKWebView : a reference to current application’s WKWebView
property WKUserScript : a reference to current application’s WKUserScript
property NSURLRequest : a reference to current application’s NSURLRequest
property NSMutableString : a reference to current application’s NSMutableString
property NSWindowController : a reference to current application’s NSWindowController
property NSTitledWindowMask : a reference to current application’s NSTitledWindowMask
property NSRoundedBezelStyle : a reference to current application’s NSRoundedBezelStyle
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSBackingStoreBuffered : a reference to current application’s NSBackingStoreBuffered
property WKUserContentController : a reference to current application’s WKUserContentController
property NSMomentaryLightButton : a reference to current application’s NSMomentaryLightButton
property WKWebViewConfiguration : a reference to current application’s WKWebViewConfiguration
property NSScreenSaverWindowLevel : a reference to current application’s NSScreenSaverWindowLevel
property WKUserScriptInjectionTimeAtDocumentEnd : a reference to current application’s WKUserScriptInjectionTimeAtDocumentEnd

property windisp : false
property wController : false

set aWidth to 1100
set aHeight to 600

set aTitle to "WkWebView test"
set aButtonMSG to "OK"
–set aURL to "https://www.youtube.com/watch?v=GP_tVXTYdmY&autoplay=1&hd=1"
set aURL to "https://www.youtube.com/embed/GP_tVXTYdmY?autoplay=1&hd=1"

set paramObj to {aWidth, aHeight, aTitle, aURL, aButtonMSG, "600"}
my performSelectorOnMainThread:"dispWebView:" withObject:(paramObj) waitUntilDone:true

on dispWebView:paramObj
  set my windisp to false
  
copy (paramObj as list) to {aWidth, aHeight, aTitle, tmpURL, aButtonMSG, timeOutSecs}
  
  
set (my windisp) to true
  
  
set aWidth to aWidth as integer
  
set aHeight to aHeight as integer
  
set tmpURL to tmpURL as string
  
  
–WebViewをつくる
  
set aConf to WKWebViewConfiguration’s alloc()’s init()
  
set jsSource to my fetchJSSourceString(tmpURL)
  
set userScript to WKUserScript’s alloc()’s initWithSource:jsSource injectionTime:(WKUserScriptInjectionTimeAtDocumentEnd) forMainFrameOnly:true
  
set userContentController to WKUserContentController’s alloc()’s init()
  
userContentController’s addUserScript:(userScript)
  
aConf’s setUserContentController:userContentController
  
  
set aWebView to WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight – 100)) configuration:aConf –フレームの大きさは根拠レス
  
aWebView’s setNavigationDelegate:me
  
aWebView’s setUIDelegate:me
  
aWebView’s setTranslatesAutoresizingMaskIntoConstraints:true
  
  
set bURL to |NSURL|’s URLWithString:tmpURL
  
set aReq to NSURLRequest’s requestWithURL:bURL
  
aWebView’s loadRequest:aReq
  
  
  
–Buttonをつくる
  
set bButton to (NSButton’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, 40)))
  
bButton’s setTitle:aButtonMSG
  
bButton’s setTarget:me
  
bButton’s setAction:("clicked:")
  
bButton’s setKeyEquivalent:(return)
  
  
–SplitViewをつくる
  
set aSplitV to NSSplitView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, aWidth, aHeight))
  
aSplitV’s setVertical:false
  
  
aSplitV’s addSubview:aWebView
  
aSplitV’s addSubview:bButton
  
aSplitV’s setNeedsDisplay:true
  
  
set aWin to makeWinWithView(aSplitV, aWidth, aHeight, aTitle, 1.0)
  
  
–NSWindowControllerを作ってみた
  
set my wController to NSWindowController’s alloc()
  
my (wController’s initWithWindow:aWin)
  
  
my (wController’s showWindow:me)
  
  
set aCount to (timeOutSecs as string as number) * 10 –timeout seconds * 10
  
repeat aCount times
    if (my windisp) = false then
      exit repeat
    end if
    
delay 0.1
  end repeat
  
  
–Purge Web Objects (not success)
  
set aWebView to ""
  
set userContentController to ""
  
set aConf to ""
  
set userScript to ""
  
set my wController to ""
  
  
my closeWin:bButton
end dispWebView:

–Button Clicked Event Handler
on clicked:aSender
  set (my windisp) to false
  
my closeWin:aSender
end clicked:

–make Window for Input
on makeWinWithView(aView, aWinWidth, aWinHeight, aTitle, alphaV)
  set aScreen to NSScreen’s mainScreen()
  
set aFrame to {{0, 0}, {aWinWidth, aWinHeight}}
  
set aBacking to NSTitledWindowMask –NSBorderlessWindowMask
  
set aDefer to NSBackingStoreBuffered
  
  
— Window
  
set aWin to NSWindow’s alloc()
  (
aWin’s initWithContentRect:aFrame styleMask:aBacking backing:aDefer defer:false screen:aScreen)
  
  
aWin’s setTitle:aTitle
  
aWin’s setDelegate:me
  
aWin’s setDisplaysWhenScreenProfileChanges:true
  
aWin’s setHasShadow:true
  
aWin’s setIgnoresMouseEvents:false
  
aWin’s setLevel:(NSScreenSaverWindowLevel)
  
aWin’s setOpaque:false
  
aWin’s setAlphaValue:alphaV –append
  
aWin’s setReleasedWhenClosed:true
  
aWin’s |center|()
  
  
— Set Custom View
  
aWin’s setContentView:aView
  
  
return aWin
end makeWinWithView

–close win
on closeWin:aSender
  set tmpWindow to aSender’s |window|()
  
  
repeat with n from 10 to 1 by -1
    (tmpWindow’s setAlphaValue:n / 10)
    
delay 0.02
  end repeat
  
  
my wController’s |close|()
end closeWin:

on viewDidLoad:aNotification
  return true
end viewDidLoad:

on fetchJSSourceString(aURL)
  set jsURL to |NSURL|’s URLWithString:aURL
  
set jsSourceString to NSString’s stringWithContentsOfURL:jsURL encoding:(NSUTF8StringEncoding) |error|:(missing value)
  
return jsSourceString
end fetchJSSourceString

★Click Here to Open This Script 

Posted in Internet URL | Tagged 10.12savvy 10.13savvy 10.14savvy NSButton NSMomentaryLightButton NSMutableString NSScreen NSScrollView NSSplitView NSString NSTextView NSURL NSURLRequest NSWindow NSWindowController WKUserContentController WKUserScript WKWebView WKWebViewConfiguration | 1 Comment

指定URLをロードしてtitleを取得 v2

Posted on 11月 20, 2018 by Takaaki Naganoya

指定URLのWebページのtitleを取得するAppleScriptです。

この手の処理を記述するには、お手軽にshell scriptでーとか、Cocoaの機能を利用してチクチク記述するとか、SafariにURLをロードしてtitleを読み込むとか、いろいろやり方があって悩むところです。

技術的な難易度が低そう(に見える)やり方を考え、ダウンロード部分はお手軽にcurlコマンドで、取得したHTMLの解析はオープンソースのFramework「HTMLReader」を併用することで高度な処理(URLエンコーディング文字列のデコード)を実現してみました。

–> HTMLReader.framework(To ~/Library/Frameworks/)

AppleScript名:指定URLをロードしてtitleを取得 v2
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property NSString : a reference to current application’s NSString
property HTMLDocument : a reference to current application’s HTMLDocument

set aURL to "http://piyocast.com/as/"
set aTItle to getPageTItleFromURL(aURL) of me
–> "AppleScriptの穴 – Useful & Practical AppleScript archive"

on getPageTItleFromURL(aURL)
  set aRes to (do shell script "curl -s " & aURL)
  
set aData to NSString’s stringWithString:aRes
  
if aData = missing value then return false
  
  
set aHTML to HTMLDocument’s documentWithString:aData
  
  
set aTitleRes to ((aHTML’s nodesMatchingSelector:"title")’s textContent’s firstObject()) as string
  
return aTitleRes
end getPageTItleFromURL

★Click Here to Open This Script 

Posted in Internet Tag Text | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSString | Leave a comment

Numbersの表の選択範囲をHTML化 v2

Posted on 11月 1, 2018 by Takaaki Naganoya

Numbersの最前面の書類で選択中の表の範囲をHTML化してファイルに書き出すAppleScriptです。

Numbers v5.1+macOS 10.12.6、Numbers v5.2+macOS 10.13.6、Numbers v5.2+macOS 10.14.1で確認しています。

Numbers v5.xでは書類の書き出し(export)形式にPDF、Microsoft Excel、CSV、Numbers 09の4形式を指定できるようになっていますが、HTMLの表(table)に書き出してくれたりはしません。

GUI側(↑)にその機能がありませんし、AppleScript用語辞書(↓)にもそういう機能は見当たりません。

ただ、HTMLの表に書き出すという処理自体はとても初歩的で簡単な内容なので、「なければ作ればいい」ということになるでしょう。

そこで、ありもののルーチンを組み合わせて、選択範囲をHTMLの表(table)として書き出すScriptを書いて、OS標準装備のScript Menuに入れて利用しています。書き出すHTMLの内容は個人の趣味や用途に応じて大きく変わってきますので、そのあたりは自由に書き換えるとよいと思われます。

本Scriptは、電子書籍「AppleScript最新リファレンス」の正誤表(2018/1のBlog消失事件の影響で、書籍内で参照していたURLリンクが切れてしまったことへの対処)を作成するために、すでに存在していたものにほんの少しの修正を加えたものです。

データベースやデータからHTMLを作成するという処理は、自分がAppleScriptを覚えようと思ったきっかけでもあり(当時は、FileMaker Pro Server経由でLAN上でデータを共有して処理)、感慨深いものがあります。

AppleScript名:表の選択範囲をHTML化 v2
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use bPlus : script "BridgePlus"

script spd
  property uniqList : {}
end script

set (uniqList of spd) to {}

–Numbersからデータを取得する
set aList to get2DListFromNumbersSelection() of me
if aList = false then return

set colCount to (length of first item of first item of aList) + 1

set aHeader to "<!DOCTYPE html><html lang=\"ja\" ><head><meta charset=\"utf-8\"><title>First</title><style>table , td, table , tr, th{border:1px solid #333333;padding:1px;}</style></head><body><table >"
set aTable to "<tr><td>%@</td><td> </td><td>%@</td><td>%@</td><td>%@</td></tr>"
set aFooter to "</table></body></html>"

set aHTMLres to retTableHTML(aList, aHeader, aTable, aFooter) of me

set tFile to choose file name with prompt "Select Output File Name and Folder"
set fRes to writeToFileAsUTF8(aHTMLres, tFile, false) of me

on retTableHTML(aList, aHeaderHTML, aTableHTML, aFooterHTML)
  set allHTML to current application’s NSMutableString’s stringWithString:aHeaderHTML
  
  
set aCounter to 1
  
repeat with i in aList
    set j to contents of i
    
    
set aRowHTML to "<tr>"
    
repeat with ii in j
      set jj to contents of ii
      
if jj = missing value then
        set jj to " "
      else
        try
          set aURL to (current application’s |NSURL|’s URLWithString:jj)
          
if aURL is not equal to missing value then
            set jj to "<a href=\"" & jj & "\">" & jj & "</a>"
          end if
        end try
      end if
      
      
set aTmpHTML to "<td>" & jj & "</td>"
      
set aRowHTML to aRowHTML & aTmpHTML
    end repeat
    
set aRowHTML to aRowHTML & "</tr>"
    
    (
allHTML’s appendString:aRowHTML)
    
set aCounter to aCounter + 1
  end repeat
  
  (
allHTML’s appendString:aFooterHTML)
  
  
return allHTML as list of string or string
end retTableHTML

–テキストを指定デリミタでリスト化
on parseByDelim(aData, aDelim)
  set aText to current application’s NSString’s stringWithString:aData
  
set aList to aText’s componentsSeparatedByString:aDelim
  
return aList as list
end parseByDelim

on get2DListFromNumbersSelection()
  –Numbersで選択範囲を縦に区切ったリストを返す
  
tell application "Numbers"
    tell front document
      tell active sheet
        set theTable to first table whose class of selection range is range
        
        
tell theTable
          try
            set selList to value of every cell of selection range –選択範囲のデータを取得
          on error
            return "" –何も選択されてなかった場合
          end try
          
          
set selName to name of selection range –選択範囲のrange情報を取得
          
set {s1, s2} to parseByDelim(selName, ":") of me
          
          
–始点の情報を取得する
          
set s1Row to (address of row of range s1) as integer
          
set s1Column to (address of column of range s1) as integer
          
          
–終点の情報を取得する
          
set s2Row to (address of row of range s2) as integer
          
set s2Column to (address of column of range s2) as integer
          
          
–選択範囲の情報を取得する
          
set selHeight to s2Row – s1Row + 1 –高さ(Height of selection range)
          
set selWidth to s2Column – s1Column + 1 –幅(Width of selection range)
          
        end tell
      end tell
    end tell
  end tell
  
  
set aLen to length of selList
  
set aaLen to selHeight
  
  
set bList to {}
  
repeat with i from 1 to aaLen
    set aHoriList to {}
    
    
repeat with ii from 1 to selWidth
      set j1 to ii + (i – 1) * selWidth
      
set tmpCon to contents of item j1 of selList
      
      
set aClass to class of tmpCon
      
if aClass = number or aClass = integer or aClass = real then
        set tmpCon to tmpCon as integer
      end if
      
      
set the end of aHoriList to tmpCon
    end repeat
    
    
set the end of bList to aHoriList
  end repeat
  
  
return bList
  
end get2DListFromNumbersSelection

on writeToFileAsUTF8(this_data, target_file, append_data)
  tell current application
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
if append_data is false then set eof of the open_target_file to 0
      
write this_data as «class utf8» to the open_target_file starting at eof
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end tell
end writeToFileAsUTF8

★Click Here to Open This Script 

Posted in Internet list | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy Numbers | Leave a comment

Post navigation

  • Older posts

電子書籍(PDF)をオンラインストアで販売中!

Google Search

Popular posts

  • macOS 13, Ventura(継続更新)
  • アラートダイアログ上にWebViewで3Dコンテンツを表示(WebGL+three.js)v3
  • UI Browserがgithub上でソース公開され、オープンソースに
  • macOS 13 TTS Voice環境に変更
  • Xcode 14.2でAppleScript App Templateを復活させる
  • 2022年に書いた価値あるAppleScript
  • ChatGPTで文章のベクトル化(Embedding)
  • 新発売:AppleScriptからSiriを呼び出そう!
  • iWork 12.2がリリースされた
  • 従来と異なるmacOS 13の性格?
  • 新発売:CotEditor Scripting Book with AppleScript
  • macOS 13対応アップデート:AppleScript実践的テクニック集(1)GUI Scripting
  • AS関連データの取り扱いを容易にする(はずの)privateDataTypeLib
  • macOS 13でNSNotFoundバグふたたび
  • macOS 12.5.1、11.6.8でFinderのselectionでスクリーンショット画像をopenできない問題
  • ChatGPTでchatに対する応答文を取得
  • 新発売:iWork Scripting Book with AppleScript
  • Finderの隠し命令openVirtualLocationが発見される
  • macOS 13.1アップデートでスクリプトエディタの挙動がようやくまともに
  • あのコン過去ログビューワー(暫定版)

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1390) 10.14savvy (586) 10.15savvy (434) 11.0savvy (277) 12.0savvy (185) 13.0savvy (55) CotEditor (60) Finder (47) iTunes (19) Keynote (98) NSAlert (60) NSArray (51) NSBezierPath (18) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (51) NSDictionary (27) NSFileManager (23) NSFont (18) NSImage (41) NSJSONSerialization (21) NSMutableArray (62) NSMutableDictionary (21) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (117) NSURL (97) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (56) Pages (37) Safari (41) Script Editor (20) WKUserContentController (21) WKUserScript (20) WKUserScriptInjectionTimeAtDocumentEnd (18) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • Clipboard
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • drive
  • exif
  • file
  • File path
  • filter
  • folder
  • Font
  • Font
  • GAME
  • geolocation
  • GUI
  • GUI Scripting
  • Hex
  • History
  • How To
  • iCloud
  • Icon
  • Image
  • Input Method
  • Internet
  • iOS App
  • JavaScript
  • JSON
  • JXA
  • Keychain
  • Keychain
  • Language
  • Library
  • list
  • Locale
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • PDF
  • Peripheral
  • PRODUCTS
  • QR Code
  • Raw AppleEvent Code
  • Record
  • rectangle
  • recursive call
  • regexp
  • Release
  • Remote Control
  • Require Control-Command-R to run
  • REST API
  • Review
  • RTF
  • Sandbox
  • Screen Saver
  • Script Libraries
  • sdef
  • search
  • Security
  • selection
  • shell script
  • Shortcuts Workflow
  • Sort
  • Sound
  • Spellchecker
  • Spotlight
  • SVG
  • System
  • Tag
  • Telephony
  • Text
  • Text to Speech
  • timezone
  • Tools
  • Update
  • URL
  • UTI
  • Web Contents Control
  • WiFi
  • XML
  • XML-RPC
  • イベント(Event)
  • 未分類

アーカイブ

  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年2月
  • 2023年1月
  • 2022年12月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年12月
  • 2019年11月
  • 2019年10月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年11月
  • 2018年10月
  • 2018年9月
  • 2018年8月
  • 2018年7月
  • 2018年6月
  • 2018年5月
  • 2018年4月
  • 2018年3月
  • 2018年2月

https://piyomarusoft.booth.pm/items/301502

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org

Forum Posts

  • 人気のトピック
  • 返信がないトピック

メタ情報

  • ログイン
  • 投稿フィード
  • コメントフィード
  • WordPress.org
Proudly powered by WordPress
Theme: Flint by Star Verte LLC