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

タグ: NSURL

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

teratailの指定IDのユーザー情報を取得する_curl

Posted on 11月 27, 2018 by Takaaki Naganoya

プログラミング系質問サイトteratailのREST APIを呼び出して、指定ユーザー名の情報を取得するAppleScriptです。

TeratailのREST APIは、タグ、ユーザー、質問の3ジャンルの情報取得を行えるように整備されており、特定カテゴリ(タグで分類)の新規質問が投稿されたかどうかを定期的に確認するようなAppleScriptを作って運用することもできます(そこまでやっていないですけれども)。

REST API呼び出しにはNSURLConnectionからNSURLSessionに移行していますが、どうもNSURLSessionだと呼び出せない(AppleScriptからの呼び出し処理が完了しない)サービスがあったりするので、結局shellのcurlコマンドを呼び出すのが手短にすむケースが多いようです。

Teratailの場合も、NSURLSessionで呼び出せるAPIもあれば、結果が返ってこないAPIもあり、NSURLConnectionよりも使い勝手がよくないと感じています(個人の感想です)。

このあたり、将来的なmacOSのアップデートでNSURLConnectionが使えなくなる日が来るのかもしれませんが、curlコマンドを使うように集約するべきなのか、NSURLSessionで書き換えるべきなのか悩ましいところです。

AppleScript名:teratailの指定IDのユーザー情報を取得する_curl
— Created 2018-11-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

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 NSURLQueryItem : a reference to current application’s NSURLQueryItem
property NSJSONSerialization : a reference to current application’s NSJSONSerialization
property NSURLComponents : a reference to current application’s NSURLComponents
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

set aUserRes to searchOneUserByDisplayName("Piyomaru") of me
–> {meta:{limit:20, message:"success", hit_num:1, total_page:1, page:1}, users:{{score:43, photo:"https://teratail.storage.googleapis.com/uploads/avatars/u6/66639/MSIS21by_thumbnail.jpg", display_name:"Piyomaru"}}}

on searchOneUserByDisplayName(aName)
  set aRec to {q:aName}
  
set reqURLStr to "https://teratail.com/api/v1/users/search"
  
set bURL to retURLwithParams(reqURLStr, aRec) of me
  
  
set tmpData to (do shell script "curl -X GET \"" & bURL & "\"")
  
set jsonString to NSString’s stringWithString:tmpData
  
set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding)
  
set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value)
  
if aJsonDict = missing value then return false
  
return (aJsonDict as record)
end searchOneUserByDisplayName

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 Network Record REST API shell script URL | Tagged 10.11savvy 10.12savvy 10.13savvy 10.14savvy NSJSONSerialization NSMutableDictionary NSString NSURL NSURLComponents NSURLQueryItem | 1 Comment

機械学習で学習したMSの画像を連邦・ジオン軍判定してフォルダ分け v2

Posted on 11月 20, 2018 by Takaaki Naganoya

Create MLでガンダムのMS画像(連邦、ジオン区分け)を学習したCore ML Modelをもとに、画像をどちらの軍所属機体かを判定してフォルダ分けするAppleScriptです。

機械学習(深層学習)データをもとに判定を行って対話型処理ではなくバッチ処理的なフローでデータを「なんとなく」推論して区分けを行うサンプルです。非力なIOT機器が機械学習データをもとに推論処理できるぐらいなので、機械学習データを使ってAppleScriptで推論処理できないはずがありません。推論処理時間もさほどかからず、機械学習データを一括処理的なワークフローの中で利用することが可能です。

例によって「戦場の絆」の公式ページから落としてきたMSの画像を連邦軍とジオン軍、および両軍の鹵獲機体の4フォルダに分けてCreate MLで学習させてみました。

実行するとMS画像が入っているフォルダ(各自ご用意ください)と、連邦軍機体(efsf)およびジオン軍機体(zeon)を仕分けるフォルダを聞かれます。あとはプログラム側がなんとなく推論して仕分けを行います。

前回掲載のモデルもそうですが、きちんと学習後にテストデータで評価を行っています。だいたい8割ぐらいのヒット率ではあるものの、特定の画像については間違えることがあらかじめわかっています。

実行にあたっては、macOS 10.14上でCoreML Modelを組み込んだフレームワーク「msDetector.framework」をインストールして、本ScriptをScript Debugger上で動作させてください。

–> Download msDetector.framework (To ~/Library/Frameworks/)

–> Download msDetector (Code Signed executable AppleScript applet with Framework and libraries in its bundle)

Core MLで判定時に詳細なデータを出力させ、その可能性が0.8を上回るものだけを処理するようにしてみました。ただ、全力で間違った判定を行うケースもあるため、単なる「気休め」です。

テストデータでは、連邦軍側が72機体中間違いが9個(正解87.5%)、ジオン軍側が57機体中間違いが3個(正解95%)。鹵獲機体のデータを排除すると、もう少しいい値が出るかもしれません。ただ、学習させたデータとほぼ同じデータ(数が少ない)で再度判定を行っているだけなので、このぐらいの確度が出ないと逆に困ります。

また、確度が高くないものは排除するように処理したので、確度が低い機体の画像バリエーションを増やして学習画像数を足すと正解の確率が上がるのではないか、などと「なんとなく」考えています。

Create MLでは、もっときちんとした表データやタグ付き自然言語テキストデータ(日本語だと形態素への区分けはあらかじめやっておく必要アリ?)の学習が行えるようなので(自然言語テキストの学習例は英語のものしか見かけないけれども)いろいろやっておきたいところです。

今回は「アニメとかゲームに出てくるMSの画像」の判定という、実用性をまったく考えないで行なってみたものですが、自分の身の回りで有用性の高そうな処理といえば……アイコンやプレゼン用資料の作成画像を学習させておおまかなジャンル分けをしておき(メール系のアイコンとか)、未知のアイコン素材をダウンロードしてきたら機械学習データをもとに自動でフォルダ分けするとかでしょうか。

さすがにアイコン画像だとデフォルメされすぎていて、MicrosoftのAzure Computer Vision APIとかでも画像認識してくれなさそうなので。

AppleScript名:機械学習で学習したMSの画像の連邦軍、ジオン軍判定してフォルダ分け v2.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/11/20
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.7" — Mojave (10.14) or later & Script Debugger
use framework "Foundation"
use framework "AppKit"
use framework "msDetector"
use scripting additions

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableArray : a reference to current application’s NSMutableArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey

set aFol to POSIX path of (choose folder with prompt "Choose MS Image folder to go!")
set efsfFol to POSIX path of (choose folder with prompt "EFSF folder")
set zeonFol to POSIX path of (choose folder with prompt "Zeon folder")

–指定フォルダ以下のファイルをすべて取得(再帰ですべて取得)
set aSel to retFullpathsWithinAFolderWithRecursive(aFol) of me

–取得したファイルリストを指定UTIでフィルタリング
set filRes2 to filterPOSIXpathListByUTI(aSel, "public.image") of me

–機械学習モデルを用いて区分けを行い、任意の画像の連邦軍(efsf)、ジオン軍(zeon)へのフォルダ分け(コピー)
set msClassifier to current application’s msClassify’s alloc()’s init()

repeat with i in filRes2
  set aFile to contents of i
  
set aImage to (current application’s NSImage’s alloc()’s initWithContentsOfFile:aFile)
  
  
set resDict to (msClassifier’s ImageClassifierWithImageAndRetDict:aImage) –returns NSDictionary
  
  
–Dictinaryのvalueをソートして、最も値の大きいvalueのkeyを求める
  
set sortedArray to (current application’s NSMutableArray’s arrayWithArray:(resDict’s allValues()))
  (
sortedArray’s sortUsingSelector:"compare:")
  
set aRes to (last item of (sortedArray as list)) –末尾のアイテムが一番値の大きい数値
  
set resKey to first item of ((resDict’s allKeysForObject:aRes) as list) –最大値をもとにKeyを求める
  
  
–可能性の高いものだけ処理してみる(自信たっぷりに全力で間違えることもけっこうある)
  
if (aRes as real) > 0.8 then
    if resKey begins with "efsf" then
      –efsf & efsf_stolen
      
set aRes to (my copyFileAt:aFile toFolder:efsfFol)
    else
      –zeon & zeon_stolen
      
set aRes to (my copyFileAt:aFile toFolder:zeonFol)
    end if
  end if
end repeat

–POSIX path listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterPOSIXpathListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to contents of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterPOSIXpathListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

–指定フォルダ以下のすべてのファイルを再帰で取得
on retFullpathsWithinAFolderWithRecursive(aFol)
  set anArray to NSMutableArray’s array()
  
set aPath to NSString’s stringWithString:aFol
  
set dirEnum to NSFileManager’s defaultManager()’s enumeratorAtPath:aPath
  
  
repeat
    set aName to (dirEnum’s nextObject())
    
if aName = missing value then exit repeat
    
set aFullPath to aPath’s stringByAppendingPathComponent:aName
    
anArray’s addObject:(aFullPath as string)
  end repeat
  
  
return anArray as list
end retFullpathsWithinAFolderWithRecursive

on copyFileAt:POSIXPath toFolder:folderPath
  set POSIXPath to NSString’s stringWithString:POSIXPath
  
set folderPOSIXPath to NSString’s stringWithString:folderPath
  
set theName to POSIXPath’s lastPathComponent()
  
set newPath to folderPOSIXPath’s stringByAppendingPathComponent:theName
  
set fileManager to NSFileManager’s defaultManager()
  
set theResult to fileManager’s copyItemAtPath:POSIXPath toPath:newPath |error|:(missing value)
  
return (theResult as integer = 1)
end copyFileAt:toFolder:

★Click Here to Open This Script 

Posted in file File path Image list Machine Learning Record | Tagged 10.14savvy NSArray NSFileManager NSMutableArray NSPredicate NSSortDescriptor NSString NSURL NSURLTypeIdentifierKey | 1 Comment

指定URLをロード_WKWebView版 v2

Posted on 11月 4, 2018 by Takaaki Naganoya

指定のURLを読み込んでページのタイトルを取得するAppleScriptです。

オリジナルはControl+Command+Rの操作が必要でしたが、本バージョンでは必要ありません。ただ、Script Debuggerとの相性はよろしくないようで。

AppleScript名:指定URLをロード_WKWebView版 v2
— Created 2015-09-16 by Takaaki Naganoya
— 2015 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "WebKit"

property theWebView : missing value

set aURL to "http://www.apple.com/jp/shop/browse/home/specialdeals/mac"

my performSelectorOnMainThread:"getPage:" withObject:(aURL) waitUntilDone:true

set aTitle to (theWebView)’s title()
return aTitle as text
–>  "Mac整備済製品 – Apple(日本)"

–Download the URL page to WkWebView
on getPage:aURL
  set thisURL to current application’s |NSURL|’s URLWithString:aURL
  
set theRequest to current application’s NSURLRequest’s requestWithURL:thisURL
  
  
set aConf to current application’s WKWebViewConfiguration’s alloc()’s init()
  
  
set (my theWebView) to current application’s WKWebView’s alloc()’s initWithFrame:(current application’s NSMakeRect(0, 0, 800, 600)) configuration:aConf –フレームの大きさは根拠レス
  (
my theWebView)’s setNavigationDelegate:me
  (
my theWebView)’s loadRequest:theRequest
  
  
set waitLoop to 100 * 60 –60 seconds
  
  
set hitF to false
  
repeat waitLoop times
    set aLoadF to ((my theWebView)’s estimatedProgress()) as number
    
if aLoadF = 1.0 then
      set hitF to true
      
exit repeat
    end if
    
current application’s NSThread’s sleepForTimeInterval:(0.01)
    
–delay 0.1
  end repeat
  
  
return hitF
end getPage:

★Click Here to Open This Script 

Posted in URL | Tagged 10.11savvy 10.12savvy 10.13savvy NSThread NSURL NSURLRequest WKWebView WKWebViewConfiguration | Leave a comment

NSURLからBookmarkを作成するじっけん

Posted on 10月 3, 2018 by Takaaki Naganoya

NSURLからbookmarkDataを作成、あるいはbookmarkDataからNSURLを復元する実験を行うAppleScriptです。

POSIX pathのファイルパスをplistに保存するような場合に、元のファイルの場所が変わったり名前が変わったりすると、追跡できなくなってしまいます。

 「aliasをpropertyに保存していた時代には、自動で追跡してもらえたんだけどなー」

そのため、plistからPOSIX pathを取り出したあとは逐一「本当にそのパスにファイルが存在するか」をチェックしていたのですが、

 「もっといいものがあるよ」

と教えていただいたのが、このbookmarkDataです。

NSURL(filePathのほう)をbookmarkDataにすると、元のファイルの名前が変わったり場所(パス)が変わったりしても追跡してくれます。ファイルのノード番号をベースに追跡しているのでしょうか。とにかく、追跡してもらえるのはいいことです。

本AppleScriptでは、POSIX pathをNSURLを経由してboookmarkDataに変換し、オリジナルのファイルをリネームして、bookmarkDataからNSURL–> POSIX pathを取得。得られたパスがリネーム後のものと同じかどうかをチェックするものです。

テストを行った範囲では、想定どおりに使えているようです。

AppleScript名:POSIX path–>Bookmark & bookmark –> POSIX path.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/10/02
—
–  Copyright © 2018 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 NSString : a reference to current application’s NSString
property NSFileManager : a reference to current application’s NSFileManager
property NSURLBookmarkResolutionWithoutUI : a reference to current application’s NSURLBookmarkResolutionWithoutUI

set aFile to POSIX path of (choose file)
–> "/Users/me/Desktop/9E37BC8B-3920-4844-A6D1-0DCA183D744D.png"

–POSIX path –> URL –> Bookmark
set aURL to |NSURL|’s fileURLWithPath:aFile
set aBookmarkData to aURL’s bookmarkDataWithOptions:0 includingResourceValuesForKeys:(missing value) relativeToURL:(missing value) |error|:(missing value)

–Rename Original File
set fRes to renameFileItem(aFile, "test_test_test") of me
if fRes = false then error "Error: File already exists."

–Bookmark –> URL –> POSIX path
set bURL to |NSURL|’s URLByResolvingBookmarkData:aBookmarkData options:(NSURLBookmarkResolutionWithoutUI) relativeToURL:(missing value) bookmarkDataIsStale:(missing value) |error|:(missing value)
set bPath to (bURL’s |path|()) as string
–> "/Users/me/Desktop/test_test_test.png"

–File Rename Routine
on renameFileItem(aPOSIX, newName)
  set theNSFileManager to NSFileManager’s defaultManager()
  
set POSIXPathNSString to NSString’s stringWithString:(aPOSIX)
  
  
–Make New File Path
  
set anExtension to POSIXPathNSString’s pathExtension()
  
set newPath to (POSIXPathNSString’s stringByDeletingLastPathComponent()’s stringByAppendingPathComponent:newName)’s stringByAppendingPathExtension:anExtension
  
  
–Rename
  
if theNSFileManager’s fileExistsAtPath:newPath then
    return false
  else
    set theResult to theNSFileManager’s moveItemAtPath:POSIXPathNSString toPath:newPath |error|:(missing value)
    
if (theResult as integer = 1) then
      return (newPath as string)
    else
      return false
    end if
  end if
end renameFileItem

★Click Here to Open This Script 

Posted in file URL | Tagged 10.11savvy 10.12savvy 10.13savvy NSFileManager NSString NSURL NSURLBookmarkResolutionWithoutUI | 1 Comment

ZipZap frameworkを使ってZipアーカイブ内の情報を取得しファイルタイプごとに対応出力

Posted on 9月 29, 2018 by Takaaki Naganoya

オープンソースのZipZap frameworkを用いて、指定Zipアーカイブ内の情報を取得し、ファイルタイプごとに対応した出力を行うAppleScriptです。

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

客観的に動作内容を書くとわかりにくいですが、「目的」を書くと非常にわかりやすい部品です。

「バンドル内にパスワード付きのZipアーカイブ化したAppleScript書類を入れておいて、実行時にアーカイブからAppleScriptのソースを取り出して実行する」

というのが、その用途です。

プレーンテキストと画像を取り出せるような記述になっていますが、それらはあくまでも実験用で、AppleScript書類のソースを取り出すのが本来の目的です。

AppleScriptでGUIアプリケーションを作成したときに、GUIまわりは普通にXcode上で記述して(あるいは、外部エディタ上で記述して)おきますが、外部のアプリケーションをコントロールするコードは、実行専用の.scpt形式でかつ書き込み禁止状態にしてバンドル内に入れておいたりします(SandBox対応のため)。

ただ、さまざまな要求を満たすようにGUIアプリケーション操作用のScriptを呼び出そうとすると、load scriptで読み込んで実行させていたのでは、都合がよくない場合があります(何らかのキーを長押しすると実行を停止できるとか、システム内の別の要素……たとえばCPUの温度が上がりすぎたら停止させるとか)。

load scriptで実行すると、

(1)途中で実行停止しにくい
(2)セキュリティ上の制約がきつい(とくにGUI Scriptingまわり)
(3)スクリプトエディタ上で動かしていた時と挙動が変わる箇所がある(Finder上のselectionを取得していた場合とか)

といった問題がありますが、OSAScriptView上にAppleScriptのソースを展開して実行すると、これらの問題を解決できる一方、ソースが見える形式でアプリケーションバンドル内に入れるのはためらわれます。

その問題を解決するために書いたものです。展開したデータをファイル出力せず、すべて変数上で(オンメモリで)処理できるので都合がいいです。

Mac App Storeで販売するアプリケーションでこの部品を使ったことはありませんが、客先に納品するアプリケーションでは使えるといったところでしょうか。ここまで手の込んだプログラムだとリジェクトできないとは思っています(もっとレベルの低い指摘しか来ないので)。

AppleScript名:ZipZap frameworkを使ってZipアーカイブ内の情報を取得してファイルタイプごとに対応出力 v2
— Created 2018-09-28 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "OSAKit"
use framework "ZipZap" –https://github.com/pixelglow/zipzap
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property ZZArchive : a reference to current application’s ZZArchive
property OSAScript : a reference to current application’s OSAScript
property NSPredicate : a reference to current application’s NSPredicate
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey

set aPassword to "piyomarusoftware"
set aPath to POSIX path of (choose file of type {"public.zip-archive"})
set aList to extractArchive(aPath, aPassword) of me

on extractArchive(aPath, aPass)
  set oldArchive to ZZArchive’s archiveWithURL:(|NSURL|’s fileURLWithPath:aPath) |error|:(missing value)
  
set aList to oldArchive’s entries() as list
  
  
set outList to {}
  
  
repeat with i in aList
    set encF to i’s encrypted() as boolean
    
    
set aFileName to i’s fileName()
    
    
if (aFileName as string) does not start with "__MACOSX/" then
      set aExt to (aFileName’s pathExtension()) as string
      
set aUTI to my retFileFormatUTI(aExt)
      
set aData to (i’s newDataWithError:(missing value)) –Uncompressed raw data
      
      
if aData = missing value then
        set aData to (i’s newDataWithPassword:(aPass) |error|:(missing value))
        
if aData is equal to (missing value) then
          error "Internal archive error in extracting"
        end if
      end if
      
      
if aUTI = "public.plain-text" then
        –Plain Text
        
set aStr to (NSString’s alloc()’s initWithData:aData encoding:(NSUTF8StringEncoding)) as string
        
      else if aUTI = "com.apple.applescript.script" then
        –AppleScript .scpt file
        
set aScript to (OSAScript’s alloc()’s initWithCompiledData:aData |error|:(missing value))
        
set aStr to (aScript’s source()) as string
        
      else if (my filterUTIList({aUTI}, "public.image")) is not equal to {} then
        –Various Images
        
set aStr to (NSImage’s alloc()’s initWithData:aData)
        
      end if
      
      
set the end of outList to aStr
    end if
  end repeat
  
  
return outList
end extractArchive

on retFileFormatUTI(aExt as string)
  tell script "BridgePlus"
    load framework
    
return (current application’s SMSForder’s UTIForExtension:aExt) as string
  end tell
end retFileFormatUTI

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

★Click Here to Open This Script 

Posted in file OSA Text URL UTI | Tagged 10.11savvy 10.12savvy 10.13savvy NSArray NSImage NSPredicate NSString NSURL NSURLTypeIdentifierKey NSUTF8StringEncoding OSAScript ZZArchive | Leave a comment

Stickiesからのデータ取り出し v2

Posted on 9月 6, 2018 by Takaaki Naganoya

スティッキーズ(Stickies.app)のデータをまとめて引っこ抜いてListに入れるAppleScriptです。色情報、1行目の内容をタイトルとみなしてタイトル情報も付加して出力するようにしてみました。

オープンソースのStickiesViewerをFramework化したstickiesLib.frameworkを経由してデータを読み出します。データベースファイルから情報を直接読み取るので、Stickies.appが起動している必要はありません。

–> Download stickiesLib.framework(To ~/Library/Frameworks/)

–> {creationDate:date “2006年1月15日日曜日 11:02:32″, aTitle:”WX-310Kの画像サイズ”, modificationDate:date “2006年1月15日日曜日 11:03:09″, aContents:”WX-310Kの画像サイズ
ケータイ:120×160
壁紙:240×320″, colorName:”Yellow”}

StickiesDatabaseからまとめて一括で全部抽出するので、個別に何かのIDで指定して抽出するといった動作にはなりません。

93個のスティッキーズ書類(93個のウィンドウが表示されている状態、1つのDBを指定)から、全データを取得して本AppleScriptで0.1秒程度です。

AppleScript名:Stickiesからのデータ取り出し v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/09/05
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use framework "AppKit"
use framework "stickiesLib"
use scripting additions

property NSColor : a reference to current application’s NSColor
property |NSURL| : a reference to current application’s |NSURL|
property SVReader : a reference to current application’s SVReader
property NSFileManager : a reference to current application’s NSFileManager
property NSMutableArray : a reference to current application’s NSMutableArray

set sRes to retStickiesData() of me
–>
(*
{{creationDate:date "2006年1月15日日曜日 11:02:32", aTitle:"WX-310Kの画像サイズ", modificationDate:date "2006年1月15日日曜日 11:03:09", aContents:"WX-310Kの画像サイズ
ケータイ:120×160
壁紙:240×320", colorName:"Yellow"}, ….}
*)

on retStickiesData()
  set dbPath to POSIX path of (path to library folder from user domain) & "StickiesDatabase"
  
set aExt to (NSFileManager’s defaultManager()’s fileExistsAtPath:dbPath) as boolean
  
  
if aExt = false then
    set dbPath to POSIX path of (choose file with prompt "Select StickiesDatabase file")
  end if
  
  
set aURL to |NSURL|’s fileURLWithPath:dbPath
  
set aStickDB to SVReader’s notesWithContentsOfURL:aURL
  
  
set aList to aStickDB as list
  
  
–スティッキーズの色データ
  
set cList to {{"Yellow", {254, 244, 156}}, {"Blue", {173, 244, 255}}, {"Green", {178, 255, 161}}, {"Pink", {255, 199, 199}}, {"Purple", {182, 202, 255}}, {"Gray", {238, 238, 238}}}
  
  
  
set outArray to NSMutableArray’s new()
  
  
repeat with i in aList
    set anAttrStr to i’s attributedString()
    
set aStr to (anAttrStr’s |string|()) as string
    
    
set curTitle to first paragraph of aStr
    
    
set aColor to i’s |color|()
    
set cDate to i’s dateCreated() as date
    
set mDate to i’s dateModified() as date
    
    
set c1List to retColListFromNSColor(aColor, 255) of me
    
    
–Find Color Name
    
set hitF to false
    
repeat with ii in cList
      set {colName, colList} to ii
      
if c1List = colList then
        set hitF to true
        
exit repeat
      end if
    end repeat
    
    
if hitF = false then error "Color name did not hit"
    
    
set curName to colName
    (
outArray’s addObject:{creationDate:cDate, modificationDate:mDate, aContents:aStr, colorName:curName, aTitle:curTitle})
    
  end repeat
  
  
return outArray as list
end retStickiesData

on retColorFromRGBnum(r, g, b)
  return (NSColor’s colorWithCalibratedRed:r / 255.0 green:g / 255.0 blue:b / 255.0 alpha:1.0)
end retColorFromRGBnum

–NSColorからrgbの8bitの値を取り出す
on retColListFromNSColor(aCol, aMAX as integer)
  set aRed to round ((aCol’s redComponent()) * aMAX) rounding as taught in school
  
set aGreen to round ((aCol’s greenComponent()) * aMAX) rounding as taught in school
  
set aBlue to round ((aCol’s blueComponent()) * aMAX) rounding as taught in school
  
return {aRed, aGreen, aBlue}
end retColListFromNSColor

★Click Here to Open This Script 

Posted in Color File path RTF System | Tagged 10.11savvy 10.12savvy 10.13savvy NSColor NSFileManager NSMutableArray NSURL Stickies | Leave a comment

Stickiesからのデータ取り出し

Posted on 9月 5, 2018 by Takaaki Naganoya

スティッキーズ(Stickies.app)のデータをまとめて引っこ抜いてListに入れるAppleScriptです。

オープンソースのStickiesViewerをFramework化したstickiesLib.frameworkを経由してデータを読み出します。データベースファイルから情報を直接読み取るので、Stickeys.appが起動している必要はありません。

–> Download stickiesLib.framework(To ~/Library/Frameworks/)

昔はいろいろ苦労したような気がするのですが、あっさりデータを取り出せて驚きます。

色情報も取り出していますが、色名を取り出すにはややScriptがおおげさになるので、とりあえず作成日、修正日、テキストを取り出してみました。

AppleScript名:Stickiesからのデータ取り出し v1.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2018/09/05
—
–  Copyright © 2018 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "stickiesLib" –https://github.com/kainjow/StickiesViewer

set aFile to POSIX path of (choose file default location (path to library folder from user domain) with prompt "Select StickiesDatabase file")

set aURL to current application’s |NSURL|’s fileURLWithPath:aFile
set aList to (current application’s SVReader’s notesWithContentsOfURL:aURL) as list

set outList to {}

repeat with i in aList
  set anAttrStr to i’s attributedString()
  
set aStr to (anAttrStr’s |string|()) as string
  
  
set aColor to i’s |color|()
  
set cDate to i’s dateCreated() as date
  
set mDate to i’s dateModified() as date
  
  
set the end of outList to {creationDate:cDate, modificationDate:mDate, aContents:aStr}
end repeat

return outList

★Click Here to Open This Script 

Posted in RTF System | Tagged 10.11savvy 10.12savvy 10.13savvy NSURL Stickies | 3 Comments

WordPressの指定IDの記事にリンクされているapplescriptからCocoa Classのproperty宣言を抽出

Posted on 7月 30, 2018 by Takaaki Naganoya

WordPressで稼働しているBlog(AppleScriptの穴)の、指定記事IDの本文を取得し、本文内でリンクしているURLのうち指定schemeのものを抽出し、URLリンクされているAppleScriptのソースをデコードしてproperty宣言文のうちCocoa Classの宣言を行っているものを抽出するAppleScriptです。

HTMLReader.frameworkを用いてBlog本文からのリンク抽出、リンクURL抽出を行っています。

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

本Blogで、Tagの運用を変更しようと思い立ち、手作業で修正をはじめました。アプリケーション名のほかにCocoa Class名をTagにしようという試みです。

ただ、数個の記事のTag付け直しを行っただけで「手作業では終わらない」ことが判明。2月に再構築をはじめて1,000本ぐらいの記事をアップしているので、手作業ではとても無理です

本Blogの記事にURLリンクされているAppleScriptソースプログラムを(XML-RPC経由で)AppleScriptから自動で取得し、

その中のproperty宣言文を抽出して、

Cocoa Classの宣言文のみをリストアップして、

Blog記事のTagに自動で指定できないか、と試してみたものです。

現時点で、

  (1)指定Blog記事の本文を取得
  (2)(1)から指定URL SchemeのリンクURLを抽出
  (3)(2)のURL EncodeされているAppleScriptソースをDecode
  (4)property宣言文のみ抽出
  (5)property宣言ラベルがCocoa Classのものかをチェックして抽出

というところまでできています。本プログラムは、BlogのUser NameとPasswordが必要なので、リストのまま動かしてもエラーになり動作しません。同様にWordPressで運用されているBlogがあれば、そちらで試してみるのもよいでしょう。

XML-RPCでWordPressと通信するのには、記事アップロード自動化に使ったFrameworkもありますが、ためしにAppleScript標準搭載のcall xmlrpcコマンドを使ってみました。記事新規投稿コマンドだとクラッシュを起こしますが、この程度の用途ならクラッシュせずに使えるようです。

また、property文の抽出は構文要素を考慮していないため、コメントアウトされているものも拾ってくる可能性があります(単に行頭のproperty宣言文を拾っているだけなので、複数行コメントになっているものは拾われてくることでしょう)。

(*
property NSArray: a reference to current application’s NSArray
property NSString: a reference to current application’s NSString
*)

これを防ぐために、URLリンクされたAppleScriptをデコードした後で、いったんAppleScriptとして構文確認(コンパイル)を実施して、実際のAppleScriptとして評価すべきなのでしょう。

AppleScript名:WordPressの指定IDの記事にリンクされているapplescriptからCocoa Classのproperty宣言を抽出 v2
— Created 2018-07-30 by Takaaki Naganoya
— Modified 2018-07-31 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "HTMLReader" –https://github.com/nolanw/HTMLReader

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSBundle : a reference to current application’s NSBundle
property NSPredicate : a reference to current application’s NSPredicate
property NSDictionary : a reference to current application’s NSDictionary
property NSMutableArray : a reference to current application’s NSMutableArray
property NSMutableDictionary : a reference to current application’s NSMutableDictionary
property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding

–PostID
set postID to 3826
set aScheme to "applescript://"

–WordPressの指定Post IDの記事を取得してリンクされているURLからURL Schemeでフィルタして、リンクされているAppleScriptのソースを
–取得し、AS Sourceからproperty宣言文のみ抽出
set pList to getASSouceLinkedInWordPressPost(postID, aScheme) of me
–>  {"property NSBundle : a reference to current application’s NSBundle", "property |NSURL| : a reference to current application’s |NSURL|", "property HTMLDocument : a reference to current application’s HTMLDocument", "property NSMutableDictionary : a reference to current application’s NSMutableDictionary", "property NSPredicate : a reference to current application’s NSPredicate", "property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding", "property NSMutableSet : a reference to current application’s NSMutableSet", "property NSRegularExpressionSearch : a reference to current application’s NSRegularExpressionSearch", "property NSString : a reference to current application’s NSString", "property NSSortDescriptor : a reference to current application’s NSSortDescriptor"}

–property宣言文リストから、propetyがCocoa Classの宣言であるものだけを抽出
set p2List to filterPropertySentenseWhetherCocoaOrNot(pList) of me
–>  {"NSBundle", "HTMLDocument", "NSMutableDictionary", "NSPredicate", "NSMutableSet", "NSString", "NSSortDescriptor"}

on filterPropertySentenseWhetherCocoaOrNot(pList)
  set outList to {}
  
  
repeat with i in pList
    set j to contents of i
    
set j2 to repChar(j, "|", "") of me
    
    
–Parse String Into Words by Space
    
set aTmpStr to (NSString’s stringWithString:j2)
    
set wList to (aTmpStr’s componentsSeparatedByString:" ") as list
    
    
if wList contains {"a", "reference", "to", "current", "application’s"} then
      –通常のクラス名の場合(クラス名以外のpropertyの場合もある)
      
set aTarg to contents of item 2 of wList
      
      
–property値がCocoa Classかどうかを判定    
      
set fRes to searchClassInFrameworks(aTarg) of me
      
      
if fRes is not equal to false then
        set the end of outList to aTarg
      end if
    end if
  end repeat
  
  
return outList
end filterPropertySentenseWhetherCocoaOrNot

–指定クラスがいずれかのCocoa Frameworkに所属しているかを検索
on searchClassInFrameworks(aTarget)
  set aClass to current application’s NSClassFromString(aTarget)
  
if aClass = missing value then return false
  
set theComponenents to (NSBundle’s bundleForClass:aClass)’s bundleURL’s pathComponents()
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == ’framework’"
  
set aRes to (theComponenents’s filteredArrayUsingPredicate:thePred)’s firstObject() as list of string or string
  
return aRes
end searchClassInFrameworks

–指定Post IDのWordPress記事から、指定SchemeのURLを抽出し、AS Sourceをdecodeしてproperty行のみ抽出
on getASSouceLinkedInWordPressPost(postID, aScheme)
  set {myUser, myPass} to getAcountData() of me
  
  
tell application "http://piyocast.com/as/xmlrpc.php"
    set wRes to (call xmlrpc {method name:"wp.getPost", parameters:{"1", myUser, myPass, postID as string}})
  end tell
  
set aBody to post_content of wRes –Blog本文
  
  
–記事中でリンクしているURLを取得し、指定のURL Schemeでフィルタする
  
set urlList to filterURLLinksByScheme(aBody, aScheme) of me
  
  
set propList to {}
  
  
repeat with i in urlList
    set j to contents of i
    
set urlRec to parseQueryDictFromURLString(j) of me
    
set tmpScript to (urlRec’s |script|) as string –Get AppleScript Source
    
    
set tList to paragraphs of tmpScript
    
set pList to filterListUsingPredicate(tList, "SELF BEGINSWITH[c] %@", "property") –後方一致
    
    
set propList to propList & pList
  end repeat
  
  
return propList
end getASSouceLinkedInWordPressPost

on filterListUsingPredicate(aList as list, aPredicateStr as string, targStr as string)
  set setKey to current application’s NSMutableSet’s setWithArray:aList
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_(aPredicateStr, targStr)
  
set aRes to (setKey’s filteredSetUsingPredicate:aPredicate)
  
set bRes to aRes’s allObjects()
  
set cRes to bRes as {list, list of string or string}
  
return cRes
end filterListUsingPredicate

on parseQueryDictFromURLString(aURLStr as string)
  if aURLStr = "" then error "No URL String"
  
  
set aURL to |NSURL|’s URLWithString:aURLStr
  
set aQuery to aURL’s query() –Get Query string part from URL
  
if aQuery’s |length|() = 0 then return false
  
  
set aDict to NSMutableDictionary’s alloc()’s init()
  
set aParamList to (aQuery’s componentsSeparatedByString:"&") as list
  
  
repeat with i in aParamList
    set j to contents of i
    
if length of j > 0 then
      set tmpStr to (NSString’s stringWithString:j)
      
set eList to (tmpStr’s componentsSeparatedByString:"=")
      
set anElement to (eList’s firstObject()’s stringByReplacingPercentEscapesUsingEncoding:(NSUTF8StringEncoding))
      
set aValStr to (eList’s lastObject()’s stringByReplacingPercentEscapesUsingEncoding:(NSUTF8StringEncoding))
      (
aDict’s setObject:aValStr forKey:anElement)
    end if
  end repeat
  
  
return aDict
end parseQueryDictFromURLString

–指定のHTML文字列から、Link URLを抽出し、schemeで再抽出する
on filterURLLinksByScheme(aBody, aScheme)
  set conType to "text/html"
  
  
–HTML文字列をいったんNSDataにしているのは、HTMLReader.frameworkの仕様のため
  
set aData to (current application’s NSString’s stringWithString:aBody)’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aHTML to current application’s HTMLDocument’s documentWithData:aData contentTypeHeader:conType
  
  
set aTextArray to ((aHTML’s nodesMatchingSelector:"a")’s textContent) as list –リンク文字
  
set aLinkList to ((aHTML’s nodesMatchingSelector:"a")’s attributes’s valueForKeyPath:"href") as list –URL文字列
  
  
set outList to {}
  
repeat with i in aLinkList
    set j to contents of i
    
if j begins with aScheme then
      set the end of outList to j
    end if
  end repeat
  
  
return outList
end filterURLLinksByScheme

–文字置換
on repChar(origText as string, targChar as string, repChar as string)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to targChar
  
set tmpList to text items of origText
  
set AppleScript’s text item delimiters to repChar
  
set retText to tmpList as string
  
set AppleScript’s text item delimiters to curDelim
  
return retText
end repChar

on getAcountData()
  return {"xxxxxxxx_xx", "XXXXXXXXXXXXXXXXXXXXXXXX"}
end getAcountData

★Click Here to Open This Script 

Posted in list Network Record URL XML-RPC | Tagged 10.11savvy 10.12savvy 10.13savvy NSArray NSBundle NSString NSURL | Leave a comment

Finder上で選択中の画像のうち、最小のものに合わせて各画像の左上を原点にサイズ統一

Posted on 7月 27, 2018 by Takaaki Naganoya

Finderで選択中の画像のうち、最小のものに合わせて各画像の左上を原点にサイズを統一するAppleScriptです。

Finderで選択中のファイルから画像のみ抽出し、そのうちサイズが最小のものに合わせて他の画像をトリミングし、変更したものをデスクトップフォルダに出力します。


▲大きさを揃える画像をFinder上で選択


▲処理前の画像。大きさがまちまち


▲処理後の画像。大きさが最小の画像に合わせてそろっている

スクリーンショット画像を複数撮った場合に、厳密に同じサイズに固定することは(各種スクリーンショット作成ユーティリティを使わないと)行いづらいところです。

そこで、最小の画像を計算で求めて、それに合わせて自動トリミングするようにしてみました。Cocoaの機能を用いて画像処理しているため、Photoshopは必要ありません。

最小の画像を求めるのに、幅+高さの値でソートして最小のものを求めています(widthとheightによる2 key sortではなく1 Keyで済ませたかったので)。

Blogや書籍用の掲載画面図の作成用、といったところでしょうか。Retina画面で撮ったスクリーンショットと非Retina画面のスクリーンショットが混在するとうまく動きません(スクリーンショット画像からはRetina環境で撮った画像であるかどうかを取得できません)。

スクリーンショットの画像からRetina/非Retina環境で撮ったかを判定するのは、(Retina対応機であるかをMachine IDから取得したあとで)Syslogにアクセスしてスクリーンが接続されたか、取り外されたかといった状態を追っていくしかないのかも。

本ScriptをmacOS 10.13.6上で動作確認して驚いたのですが、いままでRecordが返ってくるべき箇所でlistが返ってくる盛大なバグが直って、本ScriptがmacOS 10.13用に書き換えずに動きました(動かないことを確認しようとして動いたので驚いた)。

AppleScript名:Finder上で選択中の画像のうち、最小のものに合わせて各画像の左上を原点にサイズ統一 v2
— Created 2018-07-23 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "QuartzCore"

property |NSURL| : a reference to current application’s |NSURL|
property NSUUID : a reference to current application’s NSUUID
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSZeroRect : a reference to current application’s NSZeroRect
property NSPredicate : a reference to current application’s NSPredicate
property NSPNGFileType : a reference to current application’s NSPNGFileType
property NSMutableArray : a reference to current application’s NSMutableArray
property NSCompositeCopy : a reference to current application’s NSCompositeCopy
property NSGraphicsContext : a reference to current application’s NSGraphicsContext
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSCalibratedRGBColorSpace : a reference to current application’s NSCalibratedRGBColorSpace

tell application "Finder"
  set selList to selection as alias list
end tell

–指定のAlias listのうち画像のみ抽出
set filRes1 to filterAliasListByUTI(selList, "public.image") of me
if filRes1 = {} then
  tell current application
    –Error Message (No Selection)
    
display dialog "Finder上で選択されているファイルはありません。" buttons {"OK"} default button 1 with icon 1 with title "画像リサイズ処理できません"
  end tell
  
return
end if

–各種情報を入れたArrayを作成
set anArray to NSMutableArray’s new()
repeat with i in selList
  set imgPath to (POSIX path of i)
  
  
set aImage to makeNSImageFromFile(i) of me
  
set sizeInfo to |size|() of aImage
  
set sizeInfo to sizeInfo & {aImg:aImage, total:(width of sizeInfo) + (height of sizeInfo), myPath:imgPath}
  (
anArray’s addObject:sizeInfo)
end repeat

–最小のサイズの画像の算出
set aRes to anArray’s valueForKeyPath:("@min.total")
set bRes to first item of (filterRecListByLabel(anArray, "total == " & aRes as string) of me) –最小サイズの画像

–最小サイズ画像のwidthとheight
set minWidth to bRes’s width
set minHeight to bRes’s height

–環境情報の取得
set aPath to POSIX path of (path to desktop)
set retinaF to (NSScreen’s mainScreen()’s backingScaleFactor()) as real
–>  2.0 (Retina) / 1.0 (Non Retina)

set cRes to filterRecListByLabel(anArray, "total != " & aRes as string) of me –最小サイズ以外の画像

repeat with i in cRes
  set j to contents of i
  
set anImage to aImg of j
  
set fRes to myPath of j
  
  
set cropedImage to (my cropNSImageBy:{0, 0, minWidth, minHeight} fromImage:anImage) –v1で間違っていた
  
  
–Retina環境対策
  
if retinaF > 1.0 then
    set cropedImage to (my resizedImage:cropedImage toScale:(1.0))
  end if
  
  
–ファイル書き込み
  
set fRes to retUUIDfilePathFromDir(aPath, "png") of me
  
set sRes to saveNSImageAtPathAsPNG(cropedImage, fRes) of me
end repeat

–リストに入れたレコードを、指定の属性ラベルの値で抽出
on filterRecListByLabel(aRecList as list, aPredicate as string)
  –ListからNSArrayへの型変換
  
set aArray to NSArray’s arrayWithArray:aRecList
  
  
–抽出
  
set aPredicate to NSPredicate’s predicateWithFormat:aPredicate
  
set filteredArray to aArray’s filteredArrayUsingPredicate:aPredicate
  
  
–NSArrayからListに型変換して返す
  
set bList to filteredArray as list
  
return bList
end filterRecListByLabel

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

on cropNSImageTo:{x1, y1, x2, y2} fromImage:theImage
  set newWidth to x2 – x1
  
set newHeight to y2 – y1
  
set theSize to (theImage’s |size|()) as record
  
set oldHeight to height of theSize
  
  
— transpose y value for Cocoa coordintates
  
set y1 to oldHeight – newHeight – y1
  
set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}}
  
theImage’s lockFocus()
  
set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect
  
theImage’s unlockFocus()
  
  
set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|())
  
outImage’s addRepresentation:theRep
  
  
return outImage
end cropNSImageTo:fromImage:

on makeNSImageFromFile(anAlias)
  set imgPath to (POSIX path of anAlias)
  
set aURL to (|NSURL|’s fileURLWithPath:(imgPath))
  
return (NSImage’s alloc()’s initWithContentsOfURL:aURL)
end makeNSImageFromFile

–NSImageを指定の大きさでトリミング
on cropNSImageBy:{x1, y1, newWidth, newHeight} fromImage:theImage
  set theSize to (theImage’s |size|()) as record
  
set oldHeight to height of theSize
  
  
— transpose y value for Cocoa coordintates
  
set y1 to oldHeight – newHeight – y1
  
set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}}
  
theImage’s lockFocus()
  
set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect
  
theImage’s unlockFocus()
  
  
set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|())
  
outImage’s addRepresentation:theRep
  
  
return outImage
end cropNSImageBy:fromImage:

on retUUIDfilePathFromDir(aPath, aEXT)
  set aUUIDstr to (NSUUID’s UUID()’s UUIDString()) as string
  
set aPath to ((NSString’s stringWithString:aPath)’s stringByAppendingPathComponent:aUUIDstr)’s stringByAppendingPathExtension:aEXT
  
return aPath
end retUUIDfilePathFromDir

–NSImageを指定パスにPNG形式で保存
on saveNSImageAtPathAsPNG(anImage, outPath)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value))
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsPNG

on resizedImage:aSourceImg toScale:imgScale
  if (aSourceImg’s isValid()) as boolean = false then error "Invalid NSImage"
  
  
set aSize to aSourceImg’s |size|()
  
–>  {​​​​​width:32.0, ​​​​​height:32.0​​​}
  
  
set aWidth to (aSize’s width) * imgScale
  
set aHeight to (aSize’s height) * imgScale
  
  
set aRep to NSBitmapImageRep’s alloc()’s initWithBitmapDataPlanes:(missing value) pixelsWide:aWidth pixelsHigh:aHeight bitsPerSample:8 samplesPerPixel:4 hasAlpha:true isPlanar:false colorSpaceName:(NSCalibratedRGBColorSpace) bytesPerRow:0 bitsPerPixel:0
  
  
set newSize to {width:aWidth, height:aHeight}
  
aRep’s setSize:newSize
  
  
NSGraphicsContext’s saveGraphicsState()
  
NSGraphicsContext’s setCurrentContext:(NSGraphicsContext’s graphicsContextWithBitmapImageRep:aRep)
  
  
aSourceImg’s drawInRect:(current application’s NSMakeRect(0, 0, aWidth, aHeight)) fromRect:(NSZeroRect) operation:(NSCompositeCopy) fraction:(1.0)
  
  
NSGraphicsContext’s restoreGraphicsState()
  
  
set newImg to NSImage’s alloc()’s initWithSize:newSize
  
newImg’s addRepresentation:aRep
  
  
return newImg
end resizedImage:toScale:

★Click Here to Open This Script 

Posted in file Image | Tagged 10.11savvy 10.12savvy 10.13savvy Finder NSArray NSBitmapImageRep NSImage NSMutableArray NSPredicate NSScreen NSString NSURL NSUUID | 1 Comment

note.muで指定のユーザーのノートを取得する

Posted on 7月 22, 2018 by Takaaki Naganoya

note.muの非公開REST API(でも、みんな知っている)を呼び出して、指定ユーザーのノート(投稿記事)を取得するAppleScriptです。

使い慣れたNSURLConnectionがmacOS 10.11で非推奨APIになって久しく、頻繁に使っているREST API呼び出し処理がいきなり動かなくなるのは困るため、NSURLSessionを用いてREST APIを呼び出すよう徐々に変更しています。

当初、REST APIの呼び出し部分は共通ルーチン化して、さまざまなREST APIを共通ルーチンで処理できるとよいだろうかと思っていました。実際にさまざまなREST APIを呼び出してみると、APIごとに意外なほど癖があって、なかなか「すべてのREST APIの共通処理ルーチン」というところまで共通化する段階までには至っていないところ。

左がNSURLSessionを用いた呼び出し、右がNSURLConnectionを用いた呼び出しを行なったものです。せっかくNSURLSessionを使ってみてはいるものの、同一の処理でもNSURLConnectionの方が40%ぐらい高速です。同一ネットワーク環境(iPhone経由のテザリング接続)でNSURLConnectionが0.4秒ぐらい、NSURLSessionでだいたい0.5から0.7秒といったところ。有線ネットワーク接続だともう少し速度が改善するかもしれません。

NSURLSessionに明示的な同期処理が存在しないため、NSURLSessionが受けわたすdelegateイベントをAppleScript側でループしつつ待っており、NSURLConnectionで素直に同期処理メソッドを呼び出すよりもオーバーヘッドが大きくなっているものと推測しています。

NSURLSessionでREST APIを呼び出すあたりの処理をまるごと独立したFrameworkにでも追い出すとよいのではないか、といったところです。

AppleScript名:(GET)指定のユーザーのノート v2
— Created 2018-06-16 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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 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

set retData to missing value

set reqURLStr to "https://note.mu/api/v1/notes"
set aRec to {urlname:"140software"} –note ID
set aURL to retURLwithParams(reqURLStr, aRec) of me

set aRESTres to callRestGETAPIAndParseResults(aURL) of me

on callRestGETAPIAndParseResults(reqURLStr)
  set aURL to |NSURL|’s URLWithString:reqURLStr
  
set aRequest to NSMutableURLRequest’s requestWithURL:aURL
  
aRequest’s setHTTPMethod:"GET"
  
aRequest’s setTimeoutInterval:10
  
aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding"
  
aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type"
  
  
set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration()
  
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 10000 times
    if retData is not equal to missing value then exit repeat
    
current application’s NSThread’s sleepForTimeInterval:("0.001" as real) –delay 0.001
  end repeat
  
  
retData
end callRestGETAPIAndParseResults

on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData
  set aStat to (tmpTask’s state()) as list of string or string
  
  
set resStr to NSString’s alloc()’s initWithData:tmpData 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)
  
  
set retData to aJsonDict as list of string or string
end URLSession:dataTask:didReceiveData:

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 JSON list REST API URL | Tagged 10.11savvy 10.12savvy 10.13savvy NSJSONSerialization NSMutableURLRequest NSString NSURL NSURLSession NSURLSessionConfiguration NSUTF8StringEncoding | 1 Comment

PDFから指定ページ以降を削除

Posted on 7月 10, 2018 by Takaaki Naganoya

PDFから指定ページ以降を削除するAppleScriptです。

こんな(↑)418ページもあるPDFから、おためし版の、冒頭から40ページだけ抽出したPDFを作成する際に使用したものです。

もともとは418ページありましたが、、、

実行後は40ページに、、、

AppleScript名:PDFから指定ページ以降を削除
— Modified 2018-07-08 by Takaaki Naganoya
–Original By Shane Stanley
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "QuartzCore"
use aBplus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property NSSet : a reference to current application’s NSSet
property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property SMSForder : a reference to current application’s SMSForder
property NSIndexSet : a reference to current application’s NSIndexSet
property PDFDocument : a reference to current application’s PDFDocument
property NSSortDescriptor : a reference to current application’s NSSortDescriptor

load framework

set sPage to 41 –ここから末尾までのページを削除
set inFile to (choose file of type {"pdf"} with prompt "Choose your PDF files:")
set pRes to removePDFPageAfter(inFile, sPage) of me

–指定パスのPDFの指定ページ以降をすべて削除
on removePDFPageAfter(inFile, sPage)
  set pCount to pdfPageCount(inFile) of me
  
set eCount to pCount – sPage + 1
  
  
set aindexSet to NSIndexSet’s indexSetWithIndexesInRange:(current application’s NSMakeRange(sPage, eCount))
  
set targPageList to (SMSForder’s arrayWithIndexSet:aindexSet) as list
  
  
return removeSpecificPagesFromPDF(inFile, targPageList) of me
end removePDFPageAfter

–指定PDF書類の複数ページの一括削除
on removeSpecificPagesFromPDF(inFileAlias, targPageNumList as list)
  set inNSURL to |NSURL|’s fileURLWithPath:(POSIX path of inFileAlias)
  
set theDoc to PDFDocument’s alloc()’s initWithURL:inNSURL
  
  
–削除対象ページリストをユニーク化して降順ソート(後方から削除)
  
set pRes to theDoc’s pageCount()
  
set t3List to relativeToAbsNumList(targPageNumList, pRes) of me
  
  
repeat with i in t3List
    copy i to targPageNum
    (
theDoc’s removePageAtIndex:(targPageNum – 1))
  end repeat
  
  
–Overwrite Exsiting PDF
  
set aRes to (theDoc’s writeToURL:inNSURL) as boolean
  
  
return aRes
end removeSpecificPagesFromPDF

–絶対ページと相対ページが混在した削除対象ページリストを絶対ページに変換して重複削除して降順ソート
on relativeToAbsNumList(aList, aMax)
  set newList to {}
  
  
repeat with i in aList
    set j to contents of i
    
if i < 0 then
      set j to aMax + j
    end if
    
    
if (j ≤ aMax) and (j is not equal to 0) then
      set the end of newList to j
    end if
  end repeat
  
  
set t1List to uniquify1DList(newList, true) of me
  
set t2List to sort1DNumListWithOrder(t1List, false) of me
  
  
return t2List
end relativeToAbsNumList

–1D/2D Listをユニーク化
on uniquify1DList(theList as list, aBool as boolean)
  set aArray to NSArray’s arrayWithArray:theList
  
set bArray to aArray’s valueForKeyPath:"@distinctUnionOfObjects.self"
  
return bArray as list
end uniquify1DList

–Sort 1-Dimension List(String Number List)
on sort1DNumListWithOrder(theList as list, aBool as boolean)
  tell NSSet to set theSet to setWithArray_(theList)
  
tell NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_("floatValue", aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumListWithOrder

–指定PDFのページ数をかぞえる(10.9対応。普通にPDFpageから取得)
–返り値:PDFファイルのページ数(整数値)
on pdfPageCount(aFile)
  set aFile to POSIX path of aFile
  
set theURL to |NSURL|’s fileURLWithPath:aFile
  
set aPDFdoc to PDFDocument’s alloc()’s initWithURL:theURL
  
set aRes to aPDFdoc’s pageCount()
  
return aRes as integer
end pdfPageCount

★Click Here to Open This Script 

Posted in file PDF | Tagged 10.11savvy 10.12savvy 10.13savvy NSArray NSIndexSet NSSet NSSortDescriptor NSURL PDFDocument | Leave a comment

Finder上で選択中のMarkdown書類をファイル名で昇順ソート(A→Z)して、各書類のタイトル見出しを取得する

Posted on 7月 8, 2018 by Takaaki Naganoya

Finder上で選択中のMarkdown書類を取得し、ファイル名で昇順ソート(A→Z)して、各Markdown書類中のタイトルのうち最もレベルの高い(重要な)ものを抽出し、まとめてテキストにしてクリップボードに転送するAppleScriptです。

大量にあるMarkdown書類の本文中から一番重要なタイトルを抽出する作業を……さすがに手作業で行うわけには行かなかったので、AppleScriptを書いて処理してみました。ただし、新規に書いた処理はほとんどなく、既存のルーチンの寄せ合わせで構成しています。

Finder上でMarkdown書類を選択した状態で本Scriptを実行すると(Markdown書類以外は除外して)、AppleScriptでMarkdown書類を読み込んで(Markdown書類がUTF-8固定なのでUTF-8を指定して読み込み)、正規表現で書類中のタイトルを抽出し、重要なタイトル(#の個数が少ない)をピックアップ。これをすべての書類について行います。

処理結果をクリップボードに転送します。

最終的には、(手作業で加工して)このようになります。

若干の手作業は発生してしまいますが、このScriptを組まなかったら、とてもその手作業を行う気も起こらなかったわけで、、、

AppleScript名:Finder上で選択中のMarkdown書類をファイル名で昇順ソート(A→Z)して、各書類のタイトル見出しを取得する
— Created 2018-06-26 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use mdLib : script "Metadata Lib" version "1.0.0"
use bPlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

property |NSURL| : a reference to current application’s |NSURL|
property NSArray : a reference to current application’s NSArray
property NSString : a reference to current application’s NSString
property SMSForder : a reference to current application’s SMSForder
property NSIndexSet : a reference to current application’s NSIndexSet
property NSPredicate : a reference to current application’s NSPredicate
property NSMutableSet : a reference to current application’s NSMutableSet
property NSFileManager : a reference to current application’s NSFileManager
property NSCountedSet : a reference to current application’s NSCountedSet
property NSURLPathKey : a reference to current application’s NSURLPathKey
property NSMutableArray : a reference to current application’s NSMutableArray
property NSURLNameKey : a reference to current application’s NSURLNameKey
property NSSortDescriptor : a reference to current application’s NSSortDescriptor
property NSURLIsPackageKey : a reference to current application’s NSURLIsPackageKey
property NSRegularExpression : a reference to current application’s NSRegularExpression
property NSURLIsDirectoryKey : a reference to current application’s NSURLIsDirectoryKey
property NSURLTypeIdentifierKey : a reference to current application’s NSURLTypeIdentifierKey
property NSURLContentModificationDateKey : a reference to current application’s NSURLContentModificationDateKey
property NSRegularExpressionAnchorsMatchLines : a reference to current application’s NSRegularExpressionAnchorsMatchLines
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles
property NSRegularExpressionDotMatchesLineSeparators : a reference to current application’s NSRegularExpressionDotMatchesLineSeparators

load framework

–set inFiles to (choose file of type {"pdf"} with prompt "Choose your PDF files:" with multiple selections allowed)
tell application "Finder"
  set inFiles to selection as alias list
end tell

if inFiles = {} then return

–指定のAlias listのうちMarkdown書類のみ抽出
set filRes1 to filterAliasListByUTI(inFiles, "net.daringfireball.markdown") of me

–指定のPOSIX path listから、各Markdown書類中の一番重要な見出しを抽出して返す
set tRes to listTitlesFromMarkdownDocPathList(filRes1) of me

–取得したタイトル一覧リストをテキストに変換
set t2Res to retStrFromArrayWithDelimiter(tRes, return) of me

–クリップボードに結果を転送
set the clipboard to t2Res

on listTitlesFromMarkdownDocPathList(inFiles)
  set outList to {}
  
set inFilesSorted to my filesInListSortAscending(inFiles)
  
  
repeat with i in inFilesSorted
    –POSIX pathからaliasにパス変換してテキスト読み込み
    
set j to POSIX file (contents of i)
    
set jj to j as alias
    
set aStr to (read jj as «class utf8»)
    
    
set aList to retHeaders(aStr) of me –Markdown書類中の見出しをリストアップ
    
–>  {​​​​​{​​​​​​​1, ​​​​​​​" 2008/3/9 5桁の乱数を生成"​​​​​}​​​}
    
    
if aList is not equal to {} then
      –2D Listの昇順ソート
      
set sortIndexes to {0} –Key Item id: begin from 0
      
set sortOrders to {true} –ascending = true
      
set sortTypes to {"compare:"}
      
set resList to (current application’s SMSForder’s subarraysIn:(aList) sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list
      
      
set aCon to contents of second item of first item of resList
      
set the end of outList to aCon
    end if
  end repeat
  
return outList
end listTitlesFromMarkdownDocPathList

on filesInListSortAscending(aliasList as list)
  set cList to {}
  
repeat with i in aliasList
    set j to contents of i
    
set aFileName to ((current application’s NSString’s stringWithString:j)’s valueForKeyPath:"lastPathComponent")
    
set the end of cList to {fileName:aFileName, pathDat:j}
  end repeat
  
  
set aResList to sortRecListByLabel(cList, "fileName", true) of me –昇順ソート
  
set bResList to (aResList’s valueForKeyPath:"pathDat") as list of string or string
  
return bResList
end filesInListSortAscending

–Alias listから指定UTIに含まれるものをPOSIX pathのリストで返す
on filterAliasListByUTI(aList, targUTI)
  set newList to {}
  
repeat with i in aList
    set j to POSIX path of i
    
set tmpUTI to my retUTIfromPath(j)
    
set utiRes to my filterUTIList({tmpUTI}, targUTI)
    
if utiRes is not equal to {} then
      set the end of newList to j
    end if
  end repeat
  
return newList
end filterAliasListByUTI

–指定のPOSIX pathのファイルのUTIを求める
on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

–UTIリストが指定UTIに含まれているかどうか演算を行う
on filterUTIList(aUTIList, aUTIstr)
  set anArray to NSArray’s arrayWithArray:aUTIList
  
set aPred to NSPredicate’s predicateWithFormat_("SELF UTI-CONFORMS-TO %@", aUTIstr)
  
set bRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
return bRes
end filterUTIList

on returnNumberCharsOnly(aStr)
  set anNSString to current application’s NSString’s stringWithString:aStr
  
set anNSString to anNSString’s stringByReplacingOccurrencesOfString:"[^0-9]" withString:"" options:(current application’s NSRegularExpressionSearch) range:{0, anNSString’s |length|()}
  
return anNSString as text
end returnNumberCharsOnly

–リストに入れたレコードを、指定の属性ラベルの値でソート
on sortRecListByLabel(aRecList as list, aLabelStr as string, ascendF as boolean)
  set aArray to current application’s NSArray’s arrayWithArray:aRecList
  
  
set sortDesc to current application’s NSSortDescriptor’s alloc()’s initWithKey:aLabelStr ascending:ascendF
  
set sortDescArray to current application’s NSArray’s arrayWithObjects:sortDesc
  
set sortedArray to aArray’s sortedArrayUsingDescriptors:sortDescArray
  
return sortedArray
end sortRecListByLabel

–見出し抽出用サブルーチン群
on retHeaders(aCon)
  set tList to {}
  
set regStr to "^#{1,6}[^#]*?$"
  
  
set headerList to my findPattern:regStr inString:aCon
  
repeat with i in headerList
    set j to contents of i
    
set regStr2 to "^#{1,6}[^#]*?"
    
set headerLevel to length of first item of (my findPattern:regStr2 inString:j)
    
set the end of tList to {headerLevel, text (headerLevel + 1) thru -1 in j}
  end repeat
  
  
return tList
end retHeaders

on findPattern:thePattern inString:theString
  set theOptions to ((NSRegularExpressionDotMatchesLineSeparators) as integer) + ((NSRegularExpressionAnchorsMatchLines) as integer)
  
set theRegEx to NSRegularExpression’s regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
  
set theFinds to theRegEx’s matchesInString:theString options:0 range:{location:0, |length|:length of theString}
  
set theFinds to theFinds as list — so we can loop through
  
set theResult to {} — we will add to this
  
set theNSString to NSString’s stringWithString:theString
  
repeat with i from 1 to count of items of theFinds
    set theRange to (item i of theFinds)’s range()
    
set end of theResult to (theNSString’s substringWithRange:theRange) as string
  end repeat
  
return theResult
end findPattern:inString:

–リストを指定デリミタをはさんでテキスト化
on retStrFromArrayWithDelimiter(aList, aDelim)
  set anArray to current application’s NSArray’s arrayWithArray:aList
  
set aRes to anArray’s componentsJoinedByString:aDelim
  
return aRes as list of string or string
end retStrFromArrayWithDelimiter

★Click Here to Open This Script 

Posted in file list Markdown regexp Sort Text | Tagged 10.11savvy 10.12savvy 10.13savvy Finder NSArray NSCountedSet NSDirectoryEnumerationSkipsHiddenFiles NSFileManager NSIndexSet NSMutableArray NSMutableSet NSPredicate NSRegularExpression NSRegularExpressionAnchorsMatchLines NSRegularExpressionDotMatchesLineSeparators NSSortDescriptor NSString NSURL NSURLContentModificationDateKey NSURLIsDirectoryKey NSURLIsPackageKey NSURLNameKey NSURLPathKey NSURLTypeIdentifierKey | 3 Comments

Mac Blue-ray Playerで表示中の内容をKeynoteに追記

Posted on 7月 3, 2018 by Takaaki Naganoya

Mac Blue-ray Playerで表示中のディスクの映像を1コマキャプチャして、その画像をオープン中のKeynote書類の末尾に追記するAppleScriptです。

–> Watch Demo Movie

Mac Blue-ray Playerには表示中の映像を静止画像のスナップショットを作成する機能があり、保存先のフォルダは「環境設定」で指定できるようになっています。

本ScriptはmacOS標準搭載のScript Menuに入れて実行することを想定しています。また、自分はMac Blue-ray PlayerでBru-rayディスクではなくDVDを再生することが多く、本検証もDVDディスクで行なっています(たぶんBlu-rayでも大丈夫です)。

キャプチャ先のKeynote書類をあらかじめ作成してオープンしておきます。次に、Mac Blue-ray Playerでディスクを再生して、キャプチャしたい場所で一時停止し、本Scriptをメニューから呼び出して実行すると、Playerの表示内容をキャプチャして、Keynote書類の末尾に新規スライドを追加し、そこにキャプチャした画像をインポートします。

Mac Blue-ray Playerは発売直後(2011年)に購入し、そのままアップデートして利用していたのですが、発売後7年以上経過した現在ではサポートが終了。

アプリケーションを作る側の人間から言わせれば、ひんぱんにオンラインアップデートを行い、6年以上も同一製品ラインナップを維持してきたというのは(品質について批判もないことはないですが)、素直に尊敬に値します。

話が横道に入ってしまいましたが、Mac Blue-ray Playerは現在では「Mac Blu-ray Player Pro」「Mac Blu-ray Player Standard」そして無料版の「Free Mac Media Player」へと別れたようです。

「Free Mac Media Player」は機能面からMac Blue-ray Playerとほぼ同じものに見えます。AppleScript用語辞書もMac Blue-ray Playerと同じものであり、Mac Blue-ray Player用のAppleScriptはFree Mac Media Playerでも使えます(tell application名を直すだけです)。

実際に、本Scriptを「Free Mac Media Player」向けに書き換えて実行できることを確認しています。

AppleScript名:Mac Blue-ray Playerで表示中の内容をKeynoteに追記
— Created 2018-07-02 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSUserDefaults : a reference to current application’s NSUserDefaults
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set aExtension to "png" — Mac Blue-ray Player’s Snapshot file name extension
set aKeyword to "スナップショット" –Mac Blue-ray Player’s Snapshot file name’s pre-fix (@Japanese User environment), maybe this is localized string

–Mac Blueray Playerの設定からスナップショットの設定値を取得する
set theID to "com.macblurayplayer.Mac Blu-ray Player"
set theTargKey to "Preferences.snapshotSavePath"
set vRes to defaultsReadFromPlistEntry(theID, theTargKey) of me

–Mac Blueray Playerの環境設定に「~」(チルダ)が入っていた場合に備えて展開
set pathString to current application’s NSString’s stringWithString:vRes
set sourceFolder to pathString’s stringByExpandingTildeInPath()

–処理前にスナップショットのファイルを削除
set file1Res to getFilePathListByExtAndKeyword(sourceFolder, aExtension, aKeyword) of me –ファイル一覧取得
trashItemsByList(file1Res) of me –削除

–Mac Blueray Playerで表示している内容を設定中のフォルダに「スナップショット -YYYY-MM-DD at hh_mm_ss AM-9999999999.png」のファイル名で保存
tell application "Blu-ray Player"
  snapshot –こんだけ
end tell

–処理前にスナップショットのファイルを削除
set file2Res to getFilePathListByExtAndKeyword(sourceFolder, aExtension, aKeyword) of me –ファイル一覧取得
if file2Res = file1Res or file2Res = {} then return –No Snap

–Add Snapshot images to Keynote
repeat with i in file2Res
  set tmpFile to POSIX file i
  
set tmpAlias to tmpFile as alias
  
  
tell application "Keynote"
    tell front document
      set endSlide to make new slide at end
      
      
set blankMaster to master slide "空白" –"Blank" in Japanese. This string is *localized*
      
      
tell endSlide
        set base slide to blankMaster
        
set thisImage to make new image with properties {file:tmpAlias}
      end tell
    end tell
  end tell
  
  
–ファイル削除(ゴミ箱に移動)
  
trashItemAt(tmpAlias) of me
end repeat

–指定フォルダ内のファイルを、拡張子と先頭キーワードで抽出
on getFilePathListByExtAndKeyword(aFol, aExt, aKeyword)
  set aFM to NSFileManager’s defaultManager()
  
set aURL to |NSURL|’s fileURLWithPath:aFol
  
set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:(NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == [c]%@ && lastPathComponent BEGINSWITH %@" argumentArray:{aExt, aKeyword}
  
set anArray to (urlArray’s filteredArrayUsingPredicate:thePred)
  
if anArray = missing value then return {}
  
return (anArray’s valueForKeyPath:"path") as list
end getFilePathListByExtAndKeyword

–ファイル削除(ゴミ箱に移動) POSIX path listで指定
on trashItemsByList(posixPathList)
  repeat with i in posixPathList
    set fRes to trashItemAt(i) of me
    
if fRes = false then error "Error deleting a path:" & (i as string)
  end repeat
end trashItemsByList

–ファイル削除(ゴミ箱に移動)
on trashItemAt(anAlias)
  set theNSFileManager to NSFileManager’s defaultManager()
  
set anNSURL to |NSURL|’s fileURLWithPath:(POSIX path of anAlias)
  
set theResult to theNSFileManager’s trashItemAtURL:anNSURL resultingItemURL:(missing value) |error|:(missing value)
  
return (theResult as integer = 1) as boolean
end trashItemAt

–指定IDのplistから指定キーの内容を取り出す
on defaultsReadFromPlistEntry(theID, theTargKey)
  set storedDefaults to (NSUserDefaults’s standardUserDefaults()’s persistentDomainForName:theID)
  
set keyList to storedDefaults’s allKeys() as list
  
if theTargKey is not in keyList then return false
  
set aRes to (storedDefaults’s valueForKeyPath:theTargKey) as list of string or string — as anything
  
return aRes
end defaultsReadFromPlistEntry

★Click Here to Open This Script 

Posted in Image | Tagged 10.11savvy 10.12savvy 10.13savvy Free Mac Media Player Keynote Mac Blu-ray Player NSDirectoryEnumerationSkipsHiddenFiles NSFileManager NSPredicate NSURL NSUserDefaults | Leave a comment

指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものを

Posted on 7月 3, 2018 by Takaaki Naganoya

指定フォルダ(デスクトップ)内の指定拡張子のファイルのうち、ファイル名が指定キーワードではじまるものを抽出するAppleScriptです。

AppleScriptでは定番の処理ですが、Finderが10.7あたりでCocoa化されて書き直しが行われたあたりからフィルタ参照を併用した条件抽出のパフォーマンスが大幅に低下。

アプリケーション間通信でパフォーマンスを低下させないための機能であるフィルタ参照が、かえって処理速度を低下させるというたいへん皮肉な事態に。

AppleScript名:指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものをaliasリストで返す(Finder Version)
tell application "Finder"
  tell folder (path to desktop)
    set aList to (every file whose name starts with "スナップショット" and kind of it is "PNGイメージ") as alias list
  end tell
end tell

★Click Here to Open This Script 

Finder経由で行うと、処理時間は驚愕の4.6秒(67項目から1項目を抽出するだけの処理です)。これをCocoaの機能を用いて処理すると0.002秒。同じAppleScriptなのに2,000倍以上高速。逆にいえば、現在のFinder経由でのファイル処理の速度は遅すぎです。

macOS 10.10以降では、各種ファイル処理についてはFinderではなくCocoaの機能を用いたほうがよいでしょう。

その他、Finder上で選択中のファイルの一覧を取得するとか、Finder上で選択中のフォルダを取得するといった処理であればパフォーマンスの低下はないので、使っても(処理速度上の)問題はありません。

AppleScript名:指定フォルダ内の指定拡張子のファイルのうち、指定キーワードで始まるものをPOSIX pathリストで返す
— Created 2015-10-01 by Takaaki Naganoya
— Modified 2015-10-01 by Shane Stanley–With Cocoa-Style Filtering
— Modified 2018-07-03 by Takaaki Naganoya–Added filtering feature
use AppleScript version "2.5"
use scripting additions
use framework "Foundation"

property |NSURL| : a reference to current application’s |NSURL|
property NSPredicate : a reference to current application’s NSPredicate
property NSFileManager : a reference to current application’s NSFileManager
property NSDirectoryEnumerationSkipsHiddenFiles : a reference to current application’s NSDirectoryEnumerationSkipsHiddenFiles

set aExtension to "png" — no dot
set aKeyword to "スナップショット" –"Snapshot" in Japanese
set aTargetFolder to POSIX path of (path to desktop folder)

set fList to getFilePathListByExtAndKeyword(aTargetFolder, aExtension, aKeyword) of me
–>  {"/Users/me/Desktop/スナップショット-2018-07-03 at 11_42_12 AM-1696613812.png"}

on getFilePathListByExtAndKeyword(aFol, aExt, aKeyword)
  set aFM to NSFileManager’s defaultManager()
  
set aURL to |NSURL|’s fileURLWithPath:aFol
  
set urlArray to aFM’s contentsOfDirectoryAtURL:aURL includingPropertiesForKeys:{} options:(NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
  
set thePred to NSPredicate’s predicateWithFormat:"pathExtension == [c]%@ && lastPathComponent BEGINSWITH %@" argumentArray:{aExt, aKeyword}
  
set anArray to (urlArray’s filteredArrayUsingPredicate:thePred)
  
if anArray = missing value then return {}
  
return (anArray’s valueForKeyPath:"path") as list
end getFilePathListByExtAndKeyword

★Click Here to Open This Script 

Posted in file | Tagged 10.11savvy 10.12savvy 10.13savvy Finder NSDirectoryEnumerationSkipsHiddenFiles NSFileManager NSPredicate NSURL | Leave a comment

Skimで現在表示中のPDFのページをJPEG画像で書き出す

Posted on 6月 30, 2018 by Takaaki Naganoya

オープンソースのPDFビューワー「Skim」で現在表示中のPDFの現在表示中のページをJPEG画像で書き出すAppleScriptです。

macOS標準装備のPreview.appはつい最近AppleScriptからの制御が公式に行えるようになった程度で、対応度も最低限です。Skimであれば、こうした「現在オープン中のPDFの表示中のページ」の番号を取得することもできます。

macOS標準装備のScript Menuから呼び出して利用することを前提に作成してあります。

Skimでオープン中の最前面のPDFと同じフォルダに、元ファイル名に対してページの数値をゼロパディングして追加したものをJPEG画像のファイル名に指定しています。ファイル名の重複回避などは行っていません。

ただし、Skimで表示モードが「単一」(1ページ分のみビューワーに表示)以外になっていると、カレントページ(現在表示中のページ)が画面上とアプリケーション側で管理しているものがズレることがあるので、表示モードを「単一」に切り替えてから「このページでよいか?」といった確認をユーザーに対して行うとよいかもしれません。

AppleScript名:Skimで現在表示中のPDFのページをJPEG画像で書き出す
— Created 2018-06-30 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "Quartz"
use framework "AppKit"

property |NSURL| : a reference to current application’s |NSURL|
property NSString : a reference to current application’s NSString
property NSImage : a reference to current application’s NSImage
property NSScreen : a reference to current application’s NSScreen
property NSNumber : a reference to current application’s NSNumber
property NSZeroPoint : a reference to current application’s NSZeroPoint
property PDFDocument : a reference to current application’s PDFDocument
property NSJPEGFileType : a reference to current application’s NSJPEGFileType
property NSCompositeCopy : a reference to current application’s NSCompositeCopy
property NSGraphicsContext : a reference to current application’s NSGraphicsContext
property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep
property NSNumberFormatter : a reference to current application’s NSNumberFormatter
property NSImageInterpolationHigh : a reference to current application’s NSImageInterpolationHigh

tell application "Skim"
  set docCount to count every document
  
if docCount = 0 then return
  
  
tell front document
    set curInd to index of current page
    
set docFile to file of it
  end tell
end tell

set aPOSIX to POSIX path of docFile
set aURL to (|NSURL|’s fileURLWithPath:aPOSIX)

set aPDFdoc to PDFDocument’s alloc()’s initWithURL:aURL
set pCount to aPDFdoc’s pageCount()

set compFactor to 1.0 –1.0 — 0.0 = max jpeg compression, 1.0 = none

–Detect Retina Environment
set retinaF to NSScreen’s mainScreen()’s backingScaleFactor()
if retinaF = 1.0 then
  set aScale to 2.0 –Non Retina Env
else
  set aScale to 1.0 –Retina Env
end if

–PDFをページごとに分割してJPEGでファイル書き出し
set i to (curInd – 1) –AppleScript index (1 based) to Cocoa index (0 based) conversion

–Pick Up a PDF page as an image
set thisPage to (aPDFdoc’s pageAtIndex:(i))
set thisDoc to (NSImage’s alloc()’s initWithData:(thisPage’s dataRepresentation()))
if thisDoc = missing value then error "Error in getting imagerep from PDF in page:" & (i as string)

–Resize Image
set pointSize to thisDoc’s |size|()
set newSize to current application’s NSMakeSize((pointSize’s width) * aScale, (pointSize’s height) * aScale)
set newImage to (NSImage’s alloc()’s initWithSize:newSize)

newImage’s lockFocus()
(
thisDoc’s setSize:newSize)
(
NSGraphicsContext’s currentContext()’s setImageInterpolation:(NSImageInterpolationHigh))
(
thisDoc’s drawAtPoint:(NSZeroPoint) fromRect:(current application’s CGRectMake(0, 0, newSize’s width, newSize’s height)) operation:(NSCompositeCopy) fraction:2.0)
newImage’s unlockFocus()

–Save Image as JPEG
set theData to newImage’s TIFFRepresentation()
set newRep to (NSBitmapImageRep’s imageRepWithData:theData)
set targData to (newRep’s representationUsingType:(NSJPEGFileType) |properties|:{NSImageCompressionFactor:compFactor, NSImageProgressive:false})
set zText to retZeroPaddingText((i + 1), 4) of me
set outPath to addString_beforeExtensionIn_addingExtension_("_" & zText, aPOSIX, "jpg")

(targData’s writeToFile:outPath atomically:true) –書き出し

–ファイルパス(POSIX path)に対して、文字列(枝番)を追加。任意の拡張子を追加
on addString:extraString beforeExtensionIn:aPath addingExtension:aExt
  set pathString to NSString’s stringWithString:aPath
  
set theExtension to pathString’s pathExtension()
  
set thePathNoExt to pathString’s stringByDeletingPathExtension()
  
  
set newPath to (thePathNoExt’s stringByAppendingString:extraString)’s stringByAppendingPathExtension:aExt
  
return newPath as string
end addString:beforeExtensionIn:addingExtension:

on retZeroPaddingText(aNum as integer, aDigitNum as integer)
  if aNum > (((10 ^ aDigitNum) as integer) – 1) then return "" –Range Check
  
set aFormatter to NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setUsesGroupingSeparator:false
  
aFormatter’s setAllowsFloats:false
  
aFormatter’s setMaximumIntegerDigits:aDigitNum
  
aFormatter’s setMinimumIntegerDigits:aDigitNum
  
aFormatter’s setPaddingCharacter:"0"
  
set aStr to aFormatter’s stringFromNumber:(NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

Posted in Image PDF | Tagged 10.11savvy 10.12savvy 10.13savvy NSBitmapImageRep NSImage NSNumber NSNumberFormatter NSScreen NSString NSURL PDFDocument Skim | Leave a comment

ファイルパスの変換(Alias→POSIX path→NSURL→POSIX path→file→Alias)

Posted on 2月 19, 2018 by Takaaki Naganoya

AppleScriptで使用するファイルパスには、alias(hfs形式)、file(hfs形式)、POSIX path形式(shell commandとのやりとりに使う)、URL形式(ほとんど使わないがごくまれに)などがありますが、macOS 10.10以降はCocoaのオブジェクトを扱えるようになったので、Cocoaオブジェクトとの間でも変換する必要が出てきました。

CocoaもPath形式にPOSIX path(NSString)、URL(NSURL)という複数のパス表現形式があり、AppleScript側のファイルパス情報と相互変換する必要があります。相互変換が一発でできれば楽ですが、たとえばaliasならalias→POSIX path→CocoaのNSStringのpathと2段階で変換する必要があります。

難しいかといわれれば、別に慣れればそんなもんでしょう。技術的な難易度はそれほど高くありません。こうした全体像を知っているかどうか、ということがキーです。

AppleScript名:ファイルパスの変換(Alias→POSIX path→NSURL→POSIX path→file→Alias)
— Created 2016-02-19 by Takaaki Naganoya
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

–Get Alias (AppleScript native file path format)
set anAlias to choose file
–>  alias "Macintosh HD:Users:me:Documents:……"

–Get POSIX path from Alias
set aPOSIX to POSIX path of anAlias
–>  "/Users/me/Documents/……"

–Get NSURL from POSIX path
set aURL to current application’s |NSURL|’s fileURLWithPath:aPOSIX
–>  (NSURL) file:///Users/me/Documents/………%83%88%EF%BC%92.scptd/

–Get NSURL string
set bPath to aURL’s absoluteString()
–>  (NSString) "file:///Users/me/Documents/A….9C%EF%BC%89.scptd/"

–Get file path (POSIX path) NSString
set cPath to aURL’s |path|()
–>  (NSString) "/Users/me/Documents/……scptd"

–Get POSIX file path string from NSString
set dPath to cPath as string
–>  "/Users/me/Documents/……..scptd"

–Get file from POSIX path
set aFile to POSIX file dPath
–>  file "Macintosh HD:Users:me:Documents:….scptd"

–Get Alias from file
set bAlias to aFile as alias
–>  alias "Macintosh HD:Users:me:Documents:….scptd"

★Click Here to Open This Script 

Posted in File path | Tagged 10.11savvy 10.12savvy 10.13savvy NSString NSURL | Leave a comment

指定ファイルのUTIを取得

Posted on 2月 13, 2018 by Takaaki Naganoya
AppleScript名:Vanilla Scriptで指定ファイルのUTIを求める
set aFile to choose file

tell application "System Events"
  set aUTI to type identifier of aFile
  
return aUTI
end tell

★Click Here to Open This Script 

AppleScript名:指定ファイルのUTIを取得
— Created 2016-10-24 by Takaaki Naganoya
— Modified 2016-10-25 by Shane Stanley
— 2016 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use BridgePlus : script "BridgePlus" –https://www.macosxautomation.com/applescript/apps/BridgePlus.html

set aFile to POSIX path of (choose file)
set aUTI to retFileFormatUTIFromPath(aFile) of me

on retFileFormatUTIFromPath(aPOSIXpath as string)
  load framework
  
set aPath to current application’s NSString’s stringWithString:aPOSIXpath
  
set aExt to (aPath’s pathExtension()) as string
  
return (current application’s SMSForder’s UTIForExtension:aExt) as list of string or string –as anything
end retFileFormatUTIFromPath

★Click Here to Open This Script 

AppleScript名:指定ファイルのUTIを取得 v2.scptd
use AppleScript version "2.5" — El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

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

set aPath to POSIX path of (choose file)
set utiRes to retUTIfromPath(aPath) of me

on retUTIfromPath(aPOSIXPath)
  set aURL to |NSURL|’s fileURLWithPath:aPOSIXPath
  
set {theResult, theValue} to aURL’s getResourceValue:(reference) forKey:NSURLTypeIdentifierKey |error|:(missing value)
  
  
if theResult = true then
    return theValue as string
  else
    return theResult
  end if
end retUTIfromPath

★Click Here to Open This Script 

Posted in file System URL UTI | Tagged 10.11savvy 10.12savvy 10.13savvy NSURL NSURLTypeIdentifierKey | Leave a comment

Post navigation

  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 13.6.5 AS系のバグ、一切直らず
  • CotEditorで2つの書類の行単位での差分検出
  • Apple純正マウス、キーボードのバッテリー残量取得
  • macOS 15, Sequoia
  • 初心者がつまづきやすい「log」コマンド
  • 指定のWordファイルをPDFに書き出す
  • Adobe AcrobatをAppleScriptから操作してPDF圧縮
  • メキシカンハットの描画
  • 与えられた文字列の1D Listのすべての順列組み合わせパターン文字列を返す v3(ベンチマーク用)
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • 2023年に書いた価値あるAppleScript
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • Cocoa Scripting Course 続刊計画
  • Numbersで選択範囲のセルの前後の空白を削除
  • NaturalLanguage.frameworkでNLEmbeddingの処理が可能な言語をチェック
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScriptによる並列処理

Tags

10.11savvy (1102) 10.12savvy (1243) 10.13savvy (1392) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (207) 13.0savvy (177) 14.0savvy (127) 15.0savvy (104) CotEditor (64) Finder (51) iTunes (19) Keynote (115) NSAlert (61) NSArray (51) NSBitmapImageRep (20) NSBundle (20) NSButton (34) NSColor (53) NSDictionary (28) NSFileManager (23) NSFont (21) NSImage (41) NSJSONSerialization (21) NSMutableArray (63) NSMutableDictionary (22) NSPredicate (36) NSRunningApplication (56) NSScreen (30) NSScrollView (22) NSString (119) NSURL (98) NSURLRequest (23) NSUTF8StringEncoding (30) NSView (33) NSWorkspace (20) Numbers (74) Pages (54) Safari (44) Script Editor (27) WKUserContentController (21) WKUserScript (20) WKWebView (23) WKWebViewConfiguration (22)

カテゴリー

  • 2D Bin Packing
  • 3D
  • AirDrop
  • AirPlay
  • Animation
  • AppleScript Application on Xcode
  • Beginner
  • Benchmark
  • beta
  • Bluetooth
  • Books
  • boolean
  • bounds
  • Bug
  • Calendar
  • call by reference
  • check sum
  • Clipboard
  • Cocoa-AppleScript Applet
  • Code Sign
  • Color
  • Custom Class
  • dialog
  • diff
  • drive
  • Droplet
  • 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
  • Localize
  • Machine Learning
  • Map
  • Markdown
  • Menu
  • Metadata
  • MIDI
  • MIME
  • Natural Language Processing
  • Network
  • news
  • Noification
  • Notarization
  • Number
  • Object control
  • OCR
  • OSA
  • parallel processing
  • 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)
  • 未分類

アーカイブ

  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2024年2月
  • 2024年1月
  • 2023年12月
  • 2023年11月
  • 2023年10月
  • 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