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

PostScript名で指定したフォントのウェイトを上げるループ処理のテスト

Posted on 10月 19, 2024 by Takaaki Naganoya

NSFontManagerを用いて、指定フォントのウェイト(太さ)を上げたり下げたりする処理ができますが、実際にやってみると「見えなかったもの」が見えてきます。

macOSには「ヒラギノ角ゴシック」のW0(PostScript名:HiraginoSans-W0)からW9(PostScript名:HiraginoSans-W9)まで異なるウェイトのフォントがインストールされています。そこで、W0から順次W9までウェイトを上げる処理を行なってみると、「ヒラギノ角ゴシックW2」にウェイトが割り振られていないことがわかります。

バグなのか、意図的なものなのか……多分バグだと思うのですが……。

AppleScript名:PostScript名で指定のフォントのウェイトを上げるループ.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/19
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

property NSFont : a reference to current application’s NSFont
property NSFontManager : a reference to current application’s NSFontManager

set aName to "HiraginoSans-W0"
set aFont to current application’s NSFont’s fontWithName:aName |size|:9.0
–> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98"

set fontM to current application’s NSFontManager’s sharedFontManager()
set fRes to fontM’s weightOfFont:(aFont)
–> 2

repeat 12 times
  set fRes to fontM’s weightOfFont:(aFont)
  
log (fRes as number)
  
  
set aFontName to aFont’s fontName()
  
log aFontName
  
  
(*2*)
  
(*(NSString) "HiraginoSans-W0"*)
  
  
(*3*)
  
(*(NSString) "HiraginoSans-W1"*)
  
  
— <– W2は?????
  
  
(*4*)
  
(*(NSString) "HiraginoSans-W3"*)
  
  
(*5*)
  
(*(NSString) "HiraginoSans-W4"*)
  
  
(*6*)
  
(*(NSString) "HiraginoSans-W5"*)
  
  
(*8*)
  
(*(NSString) "HiraginoSans-W6"*)
  
  
(*9*)
  
(*(NSString) "HiraginoSans-W7"*)
  
  
(*10*)
  
(*(NSString) "HiraginoSans-W8"*)
  
  
(*12*)
  
(*(NSString) "HiraginoSans-W9"*)
  
set aFont to fontM’s convertWeight:true ofFont:aFont
end repeat

★Click Here to Open This Script 

ヒラギノ角ゴシックW2のウェイトを取得したら3が返ってきました。ウェイトがW2とW3で重なっているんですね。

AppleScript名:PostScript名で指定のフォントのウェイトを取得.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/19
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

property NSFont : a reference to current application’s NSFont
property NSFontManager : a reference to current application’s NSFontManager

set aName to "HiraginoSans-W2"
set aFont to current application’s NSFont’s fontWithName:aName |size|:9.0
–> (NSCTFont) "HiraginoSans-W0 9.00 pt. P [] (0x12870af00) fobj=0x11b1e90d0, spc=1.98"

set fontM to current application’s NSFontManager’s sharedFontManager()

set fRes to fontM’s weightOfFont:(aFont)
–> 3

★Click Here to Open This Script 

Posted in Bug Font | Tagged 15.0savvy NSFont NSFontManager | Leave a comment

macOS 15:スクリプトエディタでFinderのAppleScript用語辞書が閲覧できない

Posted on 10月 18, 2024 by Takaaki Naganoya

Betaのときには起こっていなかった現象で、macOS 15.1で確認されています。

スクリプトエディタでFinderのAppleScript用語辞書を閲覧できません。

Finderは/System/Library/CoreServicesフォルダに入っており、このフォルダへのアクセスが「より厳しく」なったのでしょう。

ただ、実際にFinderがAppleScript対応しなくなったわけでもなければ、FinderのSDEFが除去されたわけでもありません。

実際にFinderの(パッケージ内容をコンテクストメニューから表示させたうえで)SDEFをコピーして、コピーしたものをスクリプトエディタで閲覧するとよいでしょう。

Posted in Bug | Tagged 15.0savvy Finder Script Editor | Leave a comment

macOS 15 リモートApple Eventsにバグ?

Posted on 10月 17, 2024 by Takaaki Naganoya

macOS 13.7.1が動作中のMac mini M1から、LAN経由でmacOS 15.1が動いているM2 MacBook AirのFinderにRemote Apple Eventsで操作を行なってみたら、M2 Air(macOS 15.1)側のFinderがクラッシュするという症状に直面しています。

同じ操作をM2 Air側からM1 Mac miniに対して実行すると、問題なく結果が返ってきます。

バグ?


▲M1 Mac mini上で書いたAppleScript。コンパイル(構文確認)を行おうとすると、ユーザー認証までは進むものの、直後にmacOS 15環境側のFinderがクラッシュする


▲M2 MacBook Air上で書いたAppleScript。ほぼコピペ。問題なく動く

Posted in Bug Remote Control | Tagged 15.0savvy | Leave a comment

指定のSDEFファイルからコマンドを抽出

Posted on 10月 17, 2024 by Takaaki Naganoya

アプリからスクリプトエディタを用いて書き出したSDEFファイル(AppleScript用語説明ファイル)から、コマンドを抽出するAppleScriptです。

–> Download sdef command lister.scptd (Including AS Lib in its bundle)

個人的に、SDEFの差分を確認するために極力アプリの各バージョンのSDEFを書き出して保存するようにしており、

用語辞書ベースで機能追加や変更が行われたことを確認しています。


▲Skim v1.0のAppleScript用語辞書


▲Skim v1.7.5のAppleScript用語辞書

こうしたSDEFのままでは比較できないので、FileMerge(XcodeについてくるGUI版diffの傑作)を使ってバージョン間の差分を取って確認するのが「通常営業」なわけです。

これがv1.0から最新版までの経緯をおおまかに把握したい、といったときには細かすぎますし、用途に合っていません。

そこで本Scriptを書いて利用することにしました。各バージョンごとにコマンドを抽出して、存在する/しないといった比較ができれば全体的な傾向を把握できます。

Apple純正アプリのSDEF、Adobe Creative Cloudアプリ、Microsoft OfficeのSDEFなどひととおり処理してみましたが、自分が使った範囲ではとくに問題は見つかっていません。ただ、まだ間違いがあるかもしれないため、処理ミスが見られた場合にはコメントで報告してください。


▲本Scriptを用いて、Skim各バージョンのAppleScript用語辞書からコマンドの分布を表にしたもの

AppleScript名:指定のSDEFファイルからコマンドを抽出.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/16
—
–  Copyright © 2022-2024 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use xmlLib : script "piyoXML"
use scripting additions

script myDict
  property sdefDict : {}
end script

set sdefPath to (POSIX path of (choose file of type {"com.apple.scripting-definition"} with prompt "SDEFファイルを選択"))

set comRes to {}

set (sdefDict of myDict) to {}
set comList to parseSdefAndRetObjects(sdefPath) of me

repeat with i in comList
  set j to contents of i
  
set aRes to parseSdefFileAndRetCommandStructure(sdefPath, j) of me
  
if aRes is not equal to "" then set aRes to "OK"
  
set the end of comRes to j
end repeat

set aStr to listToStringUsingTextItemDelimiter(comRes, return) of me

on parseSdefFileAndRetCommandStructure(targSDEFPath, aTargCom)
  set suitesList to ((sdefDict of myDict)’s valueForKeyPath:"dictionary.suite.command")
  
  
repeat with i in suitesList –SuitesでLoop
    set j to contents of i
    
    
try
      if j is not equal to missing value and j is not equal to current application’s NSNull then
        repeat with ii in j –CommandでLoop
          set jj to contents of ii
          
set tmpName to jj’s attributes’s |name|
          
          
if aTargCom is in (tmpName as list) then return jj
        end repeat
      end if
    on error
      return ""
    end try
    
  end repeat
  
return false
end parseSdefFileAndRetCommandStructure

–指定Bundle IDのコマンド一覧を取得する
on parseSdefAndRetObjects(sdefPath)
  if (sdefDict of myDict) = {} then
    set aRes to parseSDEFfileAndRetXMLStr(sdefPath) of me
    
set (sdefDict of myDict) to (xmlLib’s makeRecordWithXML:aRes)
  end if
  
  
set e1Res to (sdefDict of myDict)’s valueForKeyPath:"dictionary.suite.command.attributes.name"
  
  
set fRes to FlattenList(e1Res as list) of me
  
set bList to cleanUp1DList(fRes, {"missing value"}) of me
  
set gRes to uniquify1DList(bList, true) of me
  
return gRes
end parseSdefAndRetObjects

–SDEFをXincludeを考慮しつつ展開
on parseSDEFfileAndRetXMLStr(sdefFullPath)
  set sdefAlias to (POSIX file sdefFullPath) as alias –sdefのフルパスを求める
  
  
–SDEF読み込み(Xincludeの展開が必要な状態)
  
tell current application
    set theXML to read sdefAlias as «class utf8»
  end tell
  
  
–NSXMLDocumentの生成、Xincludeを有効に
  
set {theXMLDoc, theError} to current application’s NSXMLDocument’s alloc()’s initWithXMLString:theXML options:(current application’s NSXMLDocumentXInclude) |error|:(reference)
  
  
–XMLを文字データ化
  
set aDocStr to (theXMLDoc’s XMLData)
  
set aDocStr2 to (current application’s NSString’s alloc()’s initWithData:(aDocStr) encoding:(current application’s NSUTF8StringEncoding)) as string
  
  
return aDocStr2
end parseSDEFfileAndRetXMLStr

–By Paul Berkowitz
–2009年1月27日 2:24:08:JST
–Re: Flattening Nested Lists
on FlattenList(aList)
  set oldDelims to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {"????"}
  
set aString to aList as text
  
set aList to text items of aString
  
set AppleScript’s text item delimiters to oldDelims
  
return aList
end FlattenList

on cleanUp1DList(aList as list, cleanUpItems as list)
  set bList to {}
  
repeat with i in aList
    set j to contents of i
    
if j is not in cleanUpItems then
      set the end of bList to j
    end if
  end repeat
  
return bList
end cleanUp1DList

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

–1D Listを指定デリミタをはさんでテキスト化(Shane Stanley)
on listToStringUsingTextItemDelimiter(sourceList, textItemDelimiter)
  set CocoaArray to current application’s NSArray’s arrayWithArray:sourceList
  
set CocoaString to CocoaArray’s componentsJoinedByString:textItemDelimiter
  
return (CocoaString as string)
end listToStringUsingTextItemDelimiter

★Click Here to Open This Script 

Posted in sdef XML | 1 Comment

Numbersの選択範囲で空欄でないセルに指定の文字を入れる

Posted on 10月 17, 2024 by Takaaki Naganoya

Numbersの表を書き換えるためのAppleScriptです。表の選択範囲のうち、空欄でないセルに指定の文字(「●」)を入れます。

電子書籍掲載の「表」を作るのに、割と必要なものです。

「表」をまとめる段階では、

のように、生データをそのままセルに記載しておきますが、場所の利用効率でいえばそのまま生データで掲載していると無駄があります。

そこで、空欄ではないセルについては、「●」などの記号を記入することで、コンパクトな「表」に作り変える作業が発生します。本AppleScriptはそれを自動化したものです。

AppleScript名:選択範囲で空欄でないセルに指定の文字を入れる.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/17
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

script spd
  property uniqList : {}
end script

set strMark to "●"

tell application "Numbers"
  tell front document
    tell active sheet
      try
        set theTable to first table whose class of selection range is range
      on error
        display notification "Numbers: There is no selection"
        
return
      end try
      
      
tell theTable
        set (uniqList of spd) to cells of selection range
        
repeat with i in (uniqList of spd)
          set j to contents of i
          
set tmpVal to value of j
          
if tmpVal is not equal to missing value then
            set value of j to strMark
          end if
        end repeat
      end tell
    end tell
  end tell
end tell

★Click Here to Open This Script 

Posted in list Text | Tagged 13.0savvy 14.0savvy 15.0savvy Numbers | Leave a comment

指定Bundle IDのアプリの各言語のローカライズ名称を取得して出力

Posted on 10月 17, 2024 by Takaaki Naganoya

指定アプリの各ローカライズ言語における名称(CFBundleName)を取得するAppleScriptです。

まだテスト実装レベルのため、無駄な処理が入っています。

もともと本Scriptは、電子書籍に掲載する表を作成するために書いたものです。


▲電子書籍「AppleScriptによるWebブラウザ自動操縦ガイド」より

こうした資料を掲載する際に、手で調査するのは大変なので、AppleScriptを書いて資料を作成しています。ただ、macOS 13以降で(正確にいえばXcode 15以降で)はローカライズの方法が変更されたため、新たに作られた.loctableデータにアクセスしています。

従来のローカライズ方式と、新方式が混在している状況なので、旧方式でアクセスして値が得られなかった場合には、このScriptを使うとよいのでしょう。

AppleScript名:指定Bundle IDのアプリの各言語のローカライズ名称を取得して出力.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/16
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript version "2.8"
use scripting additions
use framework "Foundation"

property NSArray : a reference to current application’s NSArray
property NSPredicate : a reference to current application’s NSPredicate

set targAppBundleID to "com.apple.ScriptEditor2"
set targKey to "CFBundleName"
set aLocale to (current application’s NSLocale’s currentLocale())

set locResList to getAppInfoPlistValueInEveryLocalizedLangs(targAppBundleID, targKey, aLocale) of me
–> {{"ヘブライ語", "עורך התסריטים"}, {"韓国語", "스크립트 편집기"}, {"インドネシア語", "Editor Skrip"}, {"オランダ語", "Scripteditor"}, {"トルコ語", "Betik Düzenleyici"}, {"フィンランド語", "Skriptieditori"}, {"ハンガリー語", "Szkriptszerkesztő"}, {"ロシア語", "Редактор скриптов"}, {"イタリア語", "Script Editor"}, {"スペイン語(ラテンアメリカ)", "Editor de Scripts"}, {"ギリシャ語", "Επεξεργασία σκριπτ"}, {"カタロニア語", "Editor de Scripts"}, {"フランス語(カナダ)", "Éditeur de script"}, {"中国語(台湾)", "工序指令編寫程式"}, {"中国語(香港)", "程式碼編寫程式"}, {"ポーランド語", "Edytor skryptów"}, {"スウェーデン語", "Skriptredigerare"}, {"ノルウェー語", "Prosedyreredigering"}, {"アラビア語", "محرر البرامج النصية"}, {"英語", "Script Editor"}, {"デンマーク語", "Instruksværktøj"}, {"ヒンディー語", "स्क्रिप्ट संपादक"}, {"タイ語", "ตัวแก้ไขสคริปต์"}, {"中国語(中国本土)", "脚本编辑器"}, {"英語(イギリス)", "Script Editor"}, {"マレー語", "Editor Skrip"}, {"チェコ語", "Editor skriptů"}, {"スロバキア語", "Script Editor"}, {"英語(オーストラリア)", "Script Editor"}, {"スロベニア語", "Skriptni urejevalnik"}, {"ドイツ語", "Skripteditor"}, {"ベトナム語", "Trình soạn thảo tập lệnh"}, {"ポルトガル語(ブラジル)", "Editor de Scripts"}, {"スペイン語", "Editor de Scripts"}, {"ウクライナ語", "Редактор скриптів"}, {"ルーマニア語", "Editor scripturi"}, {"フランス語", "Éditeur de script"}, {"クロアチア語", "Urednik skripte"}, {"ポルトガル語(ポルトガル)", "Editor de Scripts"}, {"日本語", "スクリプトエディタ"}}

on getAppInfoPlistValueInEveryLocalizedLangs(targAppBundleID, targKey, aLocale)
  script spd
    property urlList : {}
  end script
  
  
–macOS 13以降がターゲット
  
set v1 to system attribute "sys1" –> 10, 11, 12, 13, 14, 15….
  
if v1 < 13 then error "This Script require macOS 13 or later"
  
  
–指定アプリのバンドル内のResourceから「InfoPlist.loctable」で終わるファイル名のパスを抽出
  
tell application "Finder"
    set defPath to application file id targAppBundleID
  end tell
  
  
set defPath to (POSIX path of (defPath as alias)) & "Contents/Resources" –Cocoa流のPOSIX path
  
set fList to getFilesIn(defPath) of me
  
  
set anArray to NSArray’s arrayWithArray:fList
  
set aPred to NSPredicate’s predicateWithFormat:"SELF ENDSWITH ’InfoPlist.loctable’"
  
set locRes to (anArray’s filteredArrayUsingPredicate:aPred) as list
  
  
set resList to {}
  
  
  
–.loctableファイルでループ(1つだけだが)
  
repeat with i in locRes
    set j to contents of i
    
set (urlList of spd) to (my readPlistAt:(j))
    
set langKeys to ((urlList of spd)’s allKeys()) as list
    
    
–Language Codeでループ
    
repeat with ii in langKeys
      set jj to contents of ii
      
set aLangDat to ((urlList of spd)’s valueForKey:jj)
      
      
—plist(=loctable)のlabelでループ
      
set allLangKeys to (aLangDat’s allKeys()) as list
      
repeat with iii in allLangKeys
        set jjj to contents of iii
        
set aVal to (aLangDat’s valueForKey:(jjj))
        
        
if jjj = targKey then
          set locLangName to getLangNameWithLocale(jj, aLocale) of me
          
set the end of resList to {locLangName, aVal as string}
          
exit repeat
        end if
      end repeat
    end repeat
  end repeat
  
  
return resList
end getAppInfoPlistValueInEveryLocalizedLangs

–Read Plist
on readPlistAt:thePath
  set thePath to current application’s NSString’s stringWithString:thePath
  
set thePath to thePath’s stringByExpandingTildeInPath()
  
set theDict to current application’s NSDictionary’s dictionaryWithContentsOfFile:thePath
  
return theDict
end readPlistAt:

–指定フォルダ内のファイルのフルパス一覧を返す
on getFilesIn(posixPath)
  script spd
    property allItems : {}
  end script
  
  
set allItems of spd to {}
  
  
— make URL
  
set theNSURL to current application’s |NSURL|’s fileURLWithPath:posixPath
  
  
— make file manager
  
set theNSFileManager to current application’s NSFileManager’s new()
  
  
— get URL enumerator
  
set theNSFileEnumerator to theNSFileManager’s enumeratorAtURL:theNSURL includingPropertiesForKeys:{current application’s NSURLIsDirectoryKey, current application’s NSURLIsPackageKey} options:((current application’s NSDirectoryEnumerationSkipsPackageDescendants) + (current application’s NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value)
  
  
— get all items from enumerator
  
set (allItems of spd) to theNSFileEnumerator’s allObjects()
  
set theFolders to {} — to store folders
  
  
— loop through
  
repeat with i from 1 to count of (allItems of spd)
    — is it a directory?
    
set {theResult, isDirectory} to ((item i of (allItems of spd))’s getResourceValue:(reference) forKey:(current application’s NSURLIsDirectoryKey) |error|:(missing value))
    
if isDirectory as boolean = false then
      set {theResult, isPackage} to ((item i of (allItems of spd))’s getResourceValue:(reference) forKey:(current application’s NSURLIsPackageKey) |error|:(missing value))
      
      
— is it not a package?
      
if not isPackage as boolean then
        set end of theFolders to (item i of (allItems of spd))’s |path|() as string –«class furl»
      end if
    end if
  end repeat
  
  
return theFolders
end getFilesIn

on getLangNameWithLocale(langCode, aLocale)
  set aLangName to (aLocale’s displayNameForKey:(current application’s NSLocaleIdentifier) value:langCode) as string
  
return aLangName
end getLangNameWithLocale

★Click Here to Open This Script 

Posted in File path Localize System | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

マウントしたディスクイメージから元のdmgファイルのパスを取得

Posted on 10月 16, 2024 by Takaaki Naganoya

マウント中のディスクイメージ(.dmg)ファイルのパスを求めるAppleScriptです。

macOS 13.7.1上で作成し、15.1上でも動作確認していますが、それほど込み入った機能は使っていないので、OSバージョン依存はないことでしょう。

実際に、オープンソースのPDFビューワー「Skim」の各バージョンのdmgファイルをダウンロードして、sdef(AppleScript用語説明)ファイルを収集してバージョンごとの変化を追う作業を行なったときに、バージョン判定を行うために元のdmgファイルのパスを求める処理を行なったものです。


▲マウントしたディスクイメージ(Skim)


▲マウント元のディスクイメージファイル


▲マウントしたディスクイメージからパス情報を取得することで、一部ファイルを取り出してコピーする際にバージョン情報を反映させた

AppleScript名:マウントしたディスクイメージから元のdmgファイルのパスを取得.scpt
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/16
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript
use framework "Foundation"
use scripting additions

set dName to "Skim"

–Disk Imageのマウントを確認
tell application "Finder"
  set dexRes to (get exists of disk dName)
end tell
if dexRes = false then error "指定のディスクイメージ「" & dName & "」はマウントされていません。" –マウントされていなかった

set aRes to getMountedDiskImageInfo("image-path : ") of me
–> "/Users/me/Downloads/Skim-1.4.6.dmg"

on getMountedDiskImageInfo(targMark)
  try
    set aRes to do shell script "hdiutil info"
  on error
    return false
  end try
  
  
set aResList to paragraphs of aRes
  
repeat with i in aResList
    set j to contents of i
    
if j begins with targMark then
      set aOff to offset of targMark in j
      
set aLen to length of targMark
      
set aRes to text (aLen + 1) thru -1 of j
      
return aRes
    end if
  end repeat
  
return false
end getMountedDiskImageInfo

★Click Here to Open This Script 

Posted in drive File path shell script | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

Numbersで選択中の2列のセルを比較して並べ直して書き戻す v2

Posted on 10月 14, 2024 by Takaaki Naganoya

Numbers上でデータを整理しているときに、必要になって組んでみたものです。少し大きいAppleScriptですが、ありもののルーチンをつなぎ合わせて書いたので、とくに画期的な何かを書いたということはありません。

もともと、Numbers上にまとめたデータ(2列分)があって、それらを同じものは同じ行に並べ、削除されたものは空欄、追加されたものは下に列挙するという整理を行なっていました。


▲処理前の状態。2列x処理を行う分の行を選択した状態で本AppleScriptを実行する(スクリプトメニューなどを推奨)


▲処理後の状態。このように整理を行う

この作業をまとめて行うものです。そんなに高速化に配慮しているわけではないので、巨大なデータを扱うのには(このままでは)向いていないかもしれません。ただ、高速化の余地はいろいろあります。

もう、これは分かりきっていた話ですが、Numbers向けに凝ったAppleScriptを書くと、Numbersの機能はほとんど使わずに、AppleScriptの配列やらNSObjectのNSArrayやらを使いまくった「Cocoaの機能のオンパレード」みたいなAppleScriptになります。これは、Numbersに絶望的に何も機能がないためで、データの入出力しか行う余地がありません。

AppleScript名:選択中の2列のセルを比較して並べ直して書き戻す v2
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/14
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set curTable to getCurTable() of me
if curTable = "" then return

set {s1Row, s1Column, e1Row, e1Column} to getSelectionRange(curTable) of me
–> {73, 3, 86, 4}

set colWidth to e1Column – s1Column + 1
–> 2

if colWidth is not equal to 2 then
  display dialog "Numbers上の表の選択幅が2ではないので、処理終了します" buttons {"OK"} default button 1
  
return
end if

set rowHeight to e1Row – s1Row + 1
–> 15

–縦方向に列のセルの値を取得(左側)
set v1List to getValueByRange(curTable, s1Column, s1Row, e1Row) of me

–スイープ(空白セルのmissing valueを除去)
set v1aList to sweepList(v1List, missing value) of me
–> {"com.apple.eloquence.fr-CA.Grandpa", "com.apple.eloquence.fi-FI.Grandpa", " com.apple.eloquence.de-DE.Grandpa", " com.apple.eloquence.pt-BR.Grandpa", "com.apple.eloquence.en-US.Grandpa", "com.apple.eloquence.es-ES.Grandpa", " com.apple.eloquence.en-GB.Grandpa", " com.apple.eloquence.it-IT.Grandpa", " com.apple.eloquence.es-MX.Grandpa"}

–縦方向に列のセルの値を取得(右側)
set v2List to getValueByRange(curTable, e1Column, s1Row, e1Row) of me

–スイープ(空白セルのmissing valueを除去)
set v2aList to sweepList(v2List, missing value) of me
–> {"com.apple.eloquence.de-DE.Grandpa", "com.apple.eloquence.en-GB.Grandpa", "com.apple.eloquence.en-US.Grandpa", "com.apple.eloquence.es-ES.Grandpa", "com.apple.eloquence.es-MX.Grandpa", "com.apple.eloquence.fi-FI.Grandpa", "com.apple.eloquence.fr-CA.Grandpa", "com.apple.eloquence.fr-FR.Grandpa", "com.apple.eloquence.it-IT.Grandpa", "com.apple.eloquence.pt-BR.Grandpa", "com.apple.eloquence.ja-JP.Grandpa", "com.apple.eloquence.ko-KR.Grandpa", "com.apple.eloquence.zh-CN.Grandpa", "com.apple.eloquence.zh-TW.Grandpa"}

set dList to getDiffBetweenLists(v1aList, v2aList) of me
–> {addItems:{"com.apple.eloquence.zh-TW.Grandpa", "com.apple.eloquence.ko-KR.Grandpa", "com.apple.eloquence.ja-JP.Grandpa", "com.apple.eloquence.zh-CN.Grandpa"}, minusItems:{}}

set newList to {}
set minusList to minusItems of dList

repeat with i in v1aList
  set j to contents of i
  
if j is not in minusList then
    if j is in v2aList then
      set the end of newList to j
    else
      set the end of newList to ""
    end if
  else
    set the end of newList to ""
  end if
end repeat

set addList to addItems of dList
set addList to sort1DNumList(addList, true) of me –昇順ソート

set new2List to newList & addList

set newLen to length of new2List
if newLen > rowHeight then
  display dialog "新規データが大きいため(" & (rowHeight as string) & "行に対して、データが" & (newLen as string) & "件)データをNumbersに描き戻せません"
  
return –元のデータ範囲よりも、新規データ範囲(行)が多かったら処理を打ち切る(将来アップデート予定。行挿入などで対処)
end if

repeat (rowHeight – newLen + 1) times
  set the end of new2List to ""
end repeat

setValueByRange(curTable, e1Column, s1Row, e1Row, new2List) of me

on setValueByRange(curTable, s1Column, s1Row, e1Row, vList)
  tell application "Numbers"
    tell curTable
      tell column s1Column
        set cList to cells s1Row thru e1Row
      end tell
      
      
set aCount to 1
      
repeat with i in cList
        set aVal to item aCount of vList
        
set value of i to aVal
        
set aCount to aCount + 1
      end repeat
      
    end tell
  end tell
end setValueByRange

on getValueByRange(curTable, s1Column, s1Row, e1Row)
  tell application "Numbers"
    tell curTable
      tell column s1Column
        set vList to value of cells s1Row thru e1Row
        
return vList
      end tell
    end tell
  end tell
end getValueByRange

on getCurTable()
  tell application "Numbers"
    tell front document
      tell active sheet
        try
          set theTable to first table whose class of selection range is range
        on error
          return "" –何も選択されてなかった場合
        end try
        
        
return theTable
      end tell
    end tell
  end tell
end getCurTable

on getSelectionRange(theTable)
  tell application "Numbers"
    tell theTable
      set aSel to properties of selection range
      
set selName to name of aSel
      
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 e1Row to (address of row of range s2) as integer
      
set e1Column to (address of column of range s2) as integer
      
      
return {s1Row, s1Column, e1Row, e1Column}
    end tell
  end tell
end getSelectionRange

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 sweepList(aList, sweepItem)
  set bList to {}
  
repeat with i in aList
    if contents of i is not equal to sweepItem then
      set the end of bList to contents of i
    end if
  end repeat
  
return bList
end sweepList

–リストの差分を取得_v2
on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

–1D List(数値)をsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DNumList(theList as list, aBool as boolean)
  tell current application’s NSSet to set theSet to setWithArray_(theList)
  
tell current application’s NSSortDescriptor to set theDescriptor to sortDescriptorWithKey_ascending_(missing value, aBool)
  
set sortedList to theSet’s sortedArrayUsingDescriptors:{theDescriptor}
  
return (sortedList) as list
end sort1DNumList

★Click Here to Open This Script 

Posted in diff list | Tagged 13.0savvy 14.0savvy 15.0savvy Numbers | Leave a comment

Numbersで選択範囲のセルの前後の空白を削除

Posted on 10月 14, 2024 by Takaaki Naganoya

コピペで作ったNumbersの表に空白文字(ゴミ)が入っている場合のクリーニング用AppleScriptです。Numbers v14.2用に作成しましたが、バージョンが異なっても動作に変化はないでしょう。

ExcelやNumbersなどの表計算アプリでは、前のセルに入力されたフォーマットを維持する機能がついているため、前のセルが空白文字ではじまる(=ゴミが入っている)と、次のセルにも同様にゴミが入ることになります。

そこで、クリーニング用に本Scriptを作成しました。


▲こんな風に、セルの先頭にスペースが入ってしまっている場合のクリーニング用Script。対象セルを選択して本Scriptを実行


▲本Script実行後の様子。各セルの冒頭に入っていたスペースが削除される

ただ、大量のセルを処理するような配慮は一切行っていないので、広範囲のセルを処理する場合には、もっと真剣に高速化を行う必要があることでしょう。

macOS標準装備のスクリプトメニューに入れて呼び出すことを想定しています。

AppleScript名:選択範囲のセルの前後の空白を削除して書き戻す
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/14
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

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

set curTable to getCurTable() of me
if curTable = "" then return

tell application "Numbers"
  tell curTable
    set cList to every cell of selection range
    
repeat with i in cList
      set j to contents of i
      
set tmpVal to value of j
      
if tmpVal is not equal to missing value then
        set tmpVal to trimWhiteSpaceFromHeadAndTail(tmpVal) of me
        
ignoring application responses
          set value of j to tmpVal
        end ignoring
      end if
    end repeat
  end tell
end tell

on getCurTable()
  tell application "Numbers"
    tell front document
      tell active sheet
        try
          set theTable to first table whose class of selection range is range
        on error
          return "" –何も選択されてなかった場合
        end try
        
        
return theTable
      end tell
    end tell
  end tell
end getCurTable

on trimWhiteSpaceFromHeadAndTail(aStr as string)
  set aString to NSString’s stringWithString:aStr
  
set bString to aString’s stringByTrimmingCharactersInSet:(NSCharacterSet’s whitespaceAndNewlineCharacterSet)
  
return bString as anything –as anything
end trimWhiteSpaceFromHeadAndTail

★Click Here to Open This Script 

Posted in Text | Tagged 13.0savvy 14.0savvy 15.0savvy Numbers | Leave a comment

EnhancedやPremiumなどの高音質TTS音声を取得

Posted on 10月 13, 2024 by Takaaki Naganoya

macOS上のTTS Voiceから高音質のものだけを抽出するAppleScriptです。

macOS上のTTS環境が変化しており、「VoiceIdentifierが『premium』で終了しているもの」といったルールでは抽出できなくなりました。

そこで、実際にTTS Voiceを調査してmacOS 15時代の実態に合っている抽出を行なってみました(コロコロ変わるので次のOSで変わっているかも?)。

IDに「premium」が含まれるもののほか、「enhanced」が含まれているものが高音質音声であるもようです。

なお、実行結果はTTS Voiceのインストール状況に応じて変わる可能性が高く、実行環境ごとに異なるものとなるはずです。

AppleScript名:EnhancedやPremiumなどの高音質音声を取得.scptd
— Created 2018-02-15 by Takaaki Naganoya
— Modified 2024-10-13 by Takaaki Naganoya
— 2018-2024 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"

property NSColor : a reference to current application’s NSColor
property NSArray : a reference to current application’s NSArray
property NSSortDescriptor : a reference to current application’s NSSortDescriptor

set vList to getTTSPremiumVoiceName() of me
–> {"Allison(拡張)", "Ava(拡張)", "Chantal(拡張)", "Daniel(拡張)", "Evan(拡張)", "Joelle(拡張)", "Kate(拡張)", "Kyoko(拡張)", "Moira(拡張)", "Nathan(拡張)", "Noelle(拡張)", "Otoya(拡張)", "Samantha(拡張)", "Susan(拡張)", "Tom(拡張)", "Zoe(拡張)", "Amélie(プレミアム)", "Ava(プレミアム)", "Jamie(プレミアム)", "Zoe(プレミアム)"}

set vIDList to getTTSPremiumVoiceID() of me
–> {"com.apple.voice.enhanced.en-US.Allison", "com.apple.voice.enhanced.en-US.Ava", "com.apple.voice.enhanced.fr-CA.Chantal", "com.apple.voice.enhanced.en-GB.Daniel", "com.apple.voice.enhanced.en-US.Evan", "com.apple.voice.enhanced.en-US.Joelle", "com.apple.voice.enhanced.en-GB.Kate", "com.apple.voice.enhanced.ja-JP.Kyoko", "com.apple.voice.enhanced.en-IE.Moira", "com.apple.voice.enhanced.en-US.Nathan", "com.apple.voice.enhanced.en-US.Noelle", "com.apple.voice.enhanced.ja-JP.Otoya", "com.apple.voice.enhanced.en-US.Samantha", "com.apple.voice.enhanced.en-US.Susan", "com.apple.voice.enhanced.en-US.Tom", "com.apple.voice.enhanced.en-US.Zoe", "com.apple.voice.premium.fr-CA.Amelie", "com.apple.voice.premium.en-US.Ava", "com.apple.voice.premium.en-GB.Malcolm", "com.apple.voice.premium.en-US.Zoe"}

on getTTSPremiumVoiceName()
  set outArray to current application’s NSMutableArray’s new()
  
  
–Make Installed Voice List
  
set aList to current application’s NSSpeechSynthesizer’s availableVoices()
  
set bList to aList as list
  
  
repeat with i in bList
    set j to contents of i
    
set aDIc to (current application’s NSSpeechSynthesizer’s attributesForVoice:j)
    (
outArray’s addObject:aDIc)
  end repeat
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_("VoiceIdentifier contains[cd] %@ ", "enhanced")
  
set afilteredArray to outArray’s filteredArrayUsingPredicate:aPredicate
  
set aResList to (afilteredArray’s valueForKey:"VoiceName") as list
  
  
set bPredicate to current application’s NSPredicate’s predicateWithFormat_("VoiceIdentifier contains[cd] %@ ", "premium")
  
set afilteredArray to outArray’s filteredArrayUsingPredicate:bPredicate
  
set bResList to (afilteredArray’s valueForKey:"VoiceName") as list
  
  
  
return (aResList & bResList)
end getTTSPremiumVoiceName

on getTTSPremiumVoiceID()
  set outArray to current application’s NSMutableArray’s new()
  
  
–Make Installed Voice List
  
set aList to current application’s NSSpeechSynthesizer’s availableVoices()
  
set bList to aList as list
  
  
repeat with i in bList
    set j to contents of i
    
set aDIc to (current application’s NSSpeechSynthesizer’s attributesForVoice:j)
    (
outArray’s addObject:aDIc)
  end repeat
  
  
  
set aPredicate to current application’s NSPredicate’s predicateWithFormat_("VoiceIdentifier contains[cd] %@ ", "enhanced")
  
set afilteredArray to outArray’s filteredArrayUsingPredicate:aPredicate
  
set aResList to (afilteredArray’s valueForKey:"VoiceIdentifier") as list
  
  
set bPredicate to current application’s NSPredicate’s predicateWithFormat_("VoiceIdentifier contains[cd] %@ ", "premium")
  
set afilteredArray to outArray’s filteredArrayUsingPredicate:bPredicate
  
set bResList to (afilteredArray’s valueForKey:"VoiceIdentifier") as list
  
  
  
return (aResList & bResList)
end getTTSPremiumVoiceID

★Click Here to Open This Script 

Posted in Text to Speech | Tagged 15.0savvy | Leave a comment

AVSpeechSynthesizerで読み上げテスト

Posted on 10月 13, 2024 by Takaaki Naganoya

AppleScriptのビルトインコマンド「say」が日本語環境で一部のTTSボイスを正しく指定できなくなっている今日このごろ。

macOSのTTS環境がアップデートされ続けている中で、これに「say」コマンドが追いつけるのかどうか、非常に怪しい雰囲気になってきました。

そこで、AVSpeechSynthesizerを呼び出してsayコマンドを使わずにテキスト音声読み上げする方法を調べてみました。そんなに難しくはありません。

注意点は、TTS Voiceキャラクタのうち、com.apple.voiceのMac OS X系TSSキャラクタは使える。com.apple.speechのClassic MacOS系のTTSキャラクタも使える。com.apple.eloquenceのEloquence系TTSキャラクタも使える。Siri系のTTSのみ使えないということです。

これで、読み上げ内容のファイルへの保存さえできれば、sayコマンドはAppleScript自体でコマンドをのっとって、sayコマンド側ではなくAppleScript側で処理を肩代わりすることが可能になるでしょう。

AppleScript名:AVSpeechSynthesizerで読み上げテスト(言語とテキストを指定).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/12
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

set aSynth to current application’s AVSpeechSynthesizer’s alloc()’s init()

set aText to "昔、昔、ある所に、おじいさんとおばあさんが住んでいました。"
set aUttr to current application’s AVSpeechUtterance’s speechUtteranceWithString:(aText)

set aVoice to current application’s AVSpeechSynthesisVoice’s voiceWithLanguage:"ja-JP" –日本語のデフォルトボイスで読み上げ
aUttr’s setVoice:aVoice
aUttr’s setRate:0.6

aSynth’s speakUtterance:aUttr

★Click Here to Open This Script 

AppleScript名:AVSpeechSynthesizerで読み上げテスト(Voice IDとテキストを指定).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/12
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

set aSynth to current application’s AVSpeechSynthesizer’s alloc()’s init()

set aText to "むかーし、むかし、ある所に、おじいさんとおばあさんが住んでいました。"
set aUttr to current application’s AVSpeechUtterance’s speechUtteranceWithString:(aText)

set aVoice to current application’s AVSpeechSynthesisVoice’s voiceWithIdentifier:"com.apple.voice.enhanced.ja-JP.Kyoko" –voice系、eloquence系はOK。Siri系は指定できない(はず)
aUttr’s setVoice:aVoice
aUttr’s setRate:0.6 –0.0から1.0まで。1.0が高速

aSynth’s speakUtterance:aUttr

★Click Here to Open This Script 

Posted in Text to Speech | Tagged 15.0savvy AVSpeechSynthesizer | Leave a comment

macOS 15でDictionary.appに追加された11の辞書

Posted on 10月 11, 2024 by Takaaki Naganoya

辞書(Dictionary).appはmacOS上の非常に有用性の高いアプリです。さまざまな国・言語の辞書をメジャーアップデートのたびに追加しています。これは、iPhoneのインストールベース数の多さを背景に、macOS側にも共有している好例でしょう。


▲macOS 13上の辞書(Dictionary).appの辞書一覧


▲macOS 15上の辞書(Dictionary).appの辞書一覧

macOS 15では辞書数は78にのぼり、(macOS 14にくらべて)11の辞書が追加され、これまで「Apple用語辞典」と呼ばれていたものが「Apple Dictionary」と変更されました。

AppleScriptからも、オープンソースのDictionaryKitを呼び出すことで、この辞書.appの辞書を串刺し検索できるため、ものすごく有用性の高いものです。

■追加された辞書名一覧

Оксфорд Қазақ Cөздігі オックスフォード・カザフのリスク
Praktický Anglicko-Chorvatský Slovník 実用的な英語 – クロアチア語辞書
Praktisk Engelsk-Dansk Ordbog 実用的な英語式辞書
牛津粵英雙語詞典 オックスフォード広東語のバイリンガル辞書
Oxford Malayalam Dictionaries – മലയാളം-ഇംഗ്ലീഷ് • ഇംഗ്ലീഷ്-മലയാളം オックスフォードマラヤーラム語辞書 – 英語 – 英語 – 英語
Oxford Kannada Dictionaries – ಇಂಗ್ಲಿಷ್-ಕನ್ನಡ • ಕನ್ನಡ-ಇಂಗ್ಲಿಷ್ オックスフォードカンナダ辞書-English-Kannada•Kannada-English
Veľký Anglicko-Slovenský Slovník 偉大な英語スロバック辞書
Українсько-Aнглійський Cловник ウクライナ・アンジェリ
Oxford Urdu Dictionaries – اردو۔انگریزی • انگریزی-اردو オックスフォードウルドゥー語辞書-Urdu -English•English -urdu
Hrvatski Enciklopedijski Rječnik クロアチア百科事典辞書
Engelsk Ordbok 英語辞書(ノルウェー語)

Posted in System | Tagged 15.0savvy | Leave a comment

NSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの違いを計算する

Posted on 10月 11, 2024 by Takaaki Naganoya

macOS 15上でNSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの数が違う、

NSSpeechSynthesizer :205
AVSpeechSynthesisVoice:222

ことが気になりました。NSSpeechSynthesizerについては、あまり真面目にメンテナンスされていないからAVSpeechSynthesisVoiceを使えといった声も聞こえてきますが、具体的にどのあたりに「差」があるのかが気になります。

そこで、実際にAppleScriptで差分を計算して確認してみました。

–>{addItems:{“com.apple.ttsbundle.siri_Nicky_en-US_premium”, “com.apple.ttsbundle.siri_Hattori_ja-JP_premium”, “com.apple.ttsbundle.siri_Helena_de-DE_compact”, “com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact”, “com.apple.ttsbundle.siri_Gordon_en-AU_compact”, “com.apple.ttsbundle.siri_Martha_en-GB_compact”, “com.apple.ttsbundle.siri_O-Ren_ja-JP_premium”, “com.apple.ttsbundle.siri_Hattori_ja-JP_compact”, “com.apple.ttsbundle.siri_Nicky_en-US_compact”, “com.apple.ttsbundle.siri_Martin_de-DE_compact”, “com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact”, “com.apple.ttsbundle.siri_Dan_fr-FR_compact”, “com.apple.ttsbundle.siri_Aaron_en-US_compact”, “com.apple.ttsbundle.siri_Catherine_en-AU_compact”, “com.apple.ttsbundle.siri_Marie_fr-FR_compact”, “com.apple.ttsbundle.siri_O-Ren_ja-JP_compact”, “com.apple.ttsbundle.siri_Arthur_en-GB_compact”}, minusItems:{}}

17個のTTS Voice IDが追加されたことを確認できました。AVSpeechSynthesisVoice側で検出されていないTTS Voiceはないことも確認。

TTS Voice IDの個人的な理解は上記の表のとおりです。NSSpeechSynthesizerで検出できなかったのは、「com.apple.ttsbundle」ではじまるSiri系の(おそらく他のメーカーからのOEM)Voice Character 17個です。

AppleScript名:NSSpeechSynthesizerとAVSpeechSynthesisVoiceで返ってくるTTS Voice IDの違いを計算する
— Created 2024-10-11 by Takaaki Naganoya
— 2019-2024 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AppKit"
use framework "AVFoundation"

set aList to current application’s NSSpeechSynthesizer’s availableVoices() as list
set bList to (current application’s AVSpeechSynthesisVoice’s speechVoices()’s valueForKey:"identifier") as list
set a1Res to checkAllItemsAreSame(aList, bList) of me
–>{addItems:{"com.apple.ttsbundle.siri_Nicky_en-US_premium", "com.apple.ttsbundle.siri_Hattori_ja-JP_premium", "com.apple.ttsbundle.siri_Helena_de-DE_compact", "com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact", "com.apple.ttsbundle.siri_Gordon_en-AU_compact", "com.apple.ttsbundle.siri_Martha_en-GB_compact", "com.apple.ttsbundle.siri_O-Ren_ja-JP_premium", "com.apple.ttsbundle.siri_Hattori_ja-JP_compact", "com.apple.ttsbundle.siri_Nicky_en-US_compact", "com.apple.ttsbundle.siri_Martin_de-DE_compact", "com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact", "com.apple.ttsbundle.siri_Dan_fr-FR_compact", "com.apple.ttsbundle.siri_Aaron_en-US_compact", "com.apple.ttsbundle.siri_Catherine_en-AU_compact", "com.apple.ttsbundle.siri_Marie_fr-FR_compact", "com.apple.ttsbundle.siri_O-Ren_ja-JP_compact", "com.apple.ttsbundle.siri_Arthur_en-GB_compact"}, minusItems:{}}

–1D List同士の全要素が(登場順序が変更になっていても)同じかどうかをチェック
on checkAllItemsAreSame(aList, bList)
  set dRes to getDiffBetweenLists(aList, bList) of me
  
set ddRes to (dRes is equal to {addItems:{}, minusItems:{}}) as boolean
  
if ddRes = true then
    return true
  else
    return dRes
  end if
end checkAllItemsAreSame

–1D List同士のdiffを検出
on getDiffBetweenLists(aArray as list, bArray as list)
  set allSet to current application’s NSMutableSet’s setWithArray:aArray
  
allSet’s addObjectsFromArray:bArray
  
  
–重複する要素のみ抜き出す
  
set duplicateSet to current application’s NSMutableSet’s setWithArray:aArray
  
duplicateSet’s intersectSet:(current application’s NSSet’s setWithArray:bArray)
  
  
–重複部分を削除する
  
allSet’s minusSet:duplicateSet
  
set resArray to (allSet’s allObjects()) as list
  
  
set aSet to current application’s NSMutableSet’s setWithArray:aArray
  
set bSet to current application’s NSMutableSet’s setWithArray:resArray
  
aSet’s intersectSet:bSet –積集合
  
set addRes to aSet’s allObjects() as list
  
  
set cSet to current application’s NSMutableSet’s setWithArray:bArray
  
cSet’s intersectSet:bSet –積集合
  
set minusRes to cSet’s allObjects() as list
  
  
return {addItems:minusRes, minusItems:addRes}
end getDiffBetweenLists

★Click Here to Open This Script 

Posted in list Text to Speech | Tagged 15.0savvy | Leave a comment

macOS 15でも変化したText to Speech環境

Posted on 10月 9, 2024 by Takaaki Naganoya

macOS 15では、大幅にText To Speech環境が変わりました。従来のTTS音声キャラクタにくわえて、Speechify社の「Eloquence Text to Speech」のOEM供給を受けた(?)TTS音声が多数追加されているようです。

# Eloquenceという名前のTTSが、オープンソース系とか複数存在しているのでOEMというわけでもなさそう?

# よく見たら、macOS 13でもEloquenceのTTS Voiceが存在していることを確認。気づいただけだったのか。

EloquenceによるTTS音声は、何かの言語専用というわけでなく複数言語に対応しているようです(1つで複数言語対応というわけではなく、複数言語バージョンが提供されている模様)。com.apple.eloquenceではじまるIDのTTSキャラクタがOEM供給を受けているものだと見ています。

# オープンソース系の(for Android)Eloquenceだとサポートする言語が少なかったりして(日本語はなかった)、このいろんな言語をサポートしているEloquence TTSはいったい何なんだろうかと、、、、

これらをAppleScriptのsayコマンドで指定することはできませんが、システム設定で読み上げキャラクタに指定しておけば、デフォルト音声を用いての読み上げで利用できそうです(Siri系のTTSキャラクタはこうして利用できていました)。

TTSキャラクタについては、macOSのメジャーアップデートごとに増加しており、macOS 15では209に達しています(macOS 11では50、macOS 13では174)。

AppleScript名:現在利用可能なTTSボイスIDの一覧(macOS 15)..scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2020/06/09
—
–  Copyright © 2020 Piyomaru Software, All Rights Reserved
—

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

set aSynth to current application’s NSSpeechSynthesizer’s availableVoices() as list
–> macOS 15 (209)
— {"com.apple.speech.synthesis.voice.Agnes", "com.apple.speech.synthesis.voice.Albert", "com.apple.speech.synthesis.voice.Alex", "com.apple.voice.compact.it-IT.Alice", "com.apple.voice.compact.en-US.Allison", "com.apple.voice.enhanced.en-US.Allison", "com.apple.voice.compact.sv-SE.Alva", "com.apple.voice.compact.fr-CA.Amelie", "com.apple.voice.premium.fr-CA.Amelie", "com.apple.voice.compact.ms-MY.Amira", "com.apple.voice.compact.de-DE.Anna", "com.apple.voice.compact.en-US.Ava", "com.apple.voice.enhanced.en-US.Ava", "com.apple.voice.premium.en-US.Ava", "com.apple.speech.synthesis.voice.BadNews", "com.apple.speech.synthesis.voice.Bahh", "com.apple.speech.synthesis.voice.Bells", "com.apple.speech.synthesis.voice.Boing", "com.apple.speech.synthesis.voice.Bruce", "com.apple.speech.synthesis.voice.Bubbles", "com.apple.voice.compact.he-IL.Carmit", "com.apple.speech.synthesis.voice.Cellos", "com.apple.voice.enhanced.fr-CA.Chantal", "com.apple.voice.compact.id-ID.Damayanti", "com.apple.voice.compact.en-GB.Daniel", "com.apple.voice.enhanced.en-GB.Daniel", "com.apple.voice.compact.bg-BG.Daria", "com.apple.speech.synthesis.voice.Deranged", "com.apple.eloquence.de-DE.Eddy", "com.apple.eloquence.en-GB.Eddy", "com.apple.eloquence.en-US.Eddy", "com.apple.eloquence.es-ES.Eddy", "com.apple.eloquence.es-MX.Eddy", "com.apple.eloquence.fi-FI.Eddy", "com.apple.eloquence.fr-CA.Eddy", "com.apple.eloquence.fr-FR.Eddy", "com.apple.eloquence.it-IT.Eddy", "com.apple.eloquence.ja-JP.Eddy", "com.apple.eloquence.ko-KR.Eddy", "com.apple.eloquence.pt-BR.Eddy", "com.apple.eloquence.zh-CN.Eddy", "com.apple.eloquence.zh-TW.Eddy", "com.apple.voice.compact.nl-BE.Ellen", "com.apple.voice.compact.en-US.Evan", "com.apple.voice.enhanced.en-US.Evan", "com.apple.eloquence.de-DE.Flo", "com.apple.eloquence.en-GB.Flo", "com.apple.eloquence.en-US.Flo", "com.apple.eloquence.es-ES.Flo", "com.apple.eloquence.es-MX.Flo", "com.apple.eloquence.fi-FI.Flo", "com.apple.eloquence.fr-CA.Flo", "com.apple.eloquence.fr-FR.Flo", "com.apple.eloquence.it-IT.Flo", "com.apple.eloquence.ja-JP.Flo", "com.apple.eloquence.ko-KR.Flo", "com.apple.eloquence.pt-BR.Flo", "com.apple.eloquence.zh-CN.Flo", "com.apple.eloquence.zh-TW.Flo", "com.apple.speech.synthesis.voice.Fred", "com.apple.speech.synthesis.voice.GoodNews", "com.apple.eloquence.de-DE.Grandma", "com.apple.eloquence.en-GB.Grandma", "com.apple.eloquence.en-US.Grandma", "com.apple.eloquence.es-ES.Grandma", "com.apple.eloquence.es-MX.Grandma", "com.apple.eloquence.fi-FI.Grandma", "com.apple.eloquence.fr-CA.Grandma", "com.apple.eloquence.fr-FR.Grandma", "com.apple.eloquence.it-IT.Grandma", "com.apple.eloquence.ja-JP.Grandma", "com.apple.eloquence.ko-KR.Grandma", "com.apple.eloquence.pt-BR.Grandma", "com.apple.eloquence.zh-CN.Grandma", "com.apple.eloquence.zh-TW.Grandma", "com.apple.eloquence.de-DE.Grandpa", "com.apple.eloquence.en-GB.Grandpa", "com.apple.eloquence.en-US.Grandpa", "com.apple.eloquence.es-ES.Grandpa", "com.apple.eloquence.es-MX.Grandpa", "com.apple.eloquence.fi-FI.Grandpa", "com.apple.eloquence.fr-CA.Grandpa", "com.apple.eloquence.fr-FR.Grandpa", "com.apple.eloquence.it-IT.Grandpa", "com.apple.eloquence.ja-JP.Grandpa", "com.apple.eloquence.ko-KR.Grandpa", "com.apple.eloquence.pt-BR.Grandpa", "com.apple.eloquence.zh-CN.Grandpa", "com.apple.eloquence.zh-TW.Grandpa", "com.apple.speech.synthesis.voice.Hysterical", "com.apple.voice.compact.ro-RO.Ioana", "com.apple.eloquence.fr-FR.Jacques", "com.apple.voice.compact.pt-PT.Joana", "com.apple.voice.enhanced.en-US.Joelle", "com.apple.speech.synthesis.voice.Junior", "com.apple.voice.compact.th-TH.Kanya", "com.apple.voice.compact.en-AU.Karen", "com.apple.voice.enhanced.en-GB.Kate", "com.apple.speech.synthesis.voice.Kathy", "com.apple.voice.compact.ja-JP.Kyoko", "com.apple.voice.enhanced.ja-JP.Kyoko", "com.apple.voice.compact.hr-HR.Lana", "com.apple.voice.compact.sk-SK.Laura", "com.apple.voice.compact.hi-IN.Lekha", "com.apple.voice.compact.uk-UA.Lesya", "com.apple.voice.compact.vi-VN.Linh", "com.apple.voice.compact.pt-BR.Luciana", "com.apple.voice.compact.ar-001.Maged", "com.apple.voice.premium.en-GB.Malcolm", "com.apple.voice.compact.hu-HU.Mariska", "com.apple.voice.compact.zh-TW.Meijia", "com.apple.voice.compact.el-GR.Melina", "com.apple.voice.compact.ru-RU.Milena", "com.apple.voice.compact.en-IE.Moira", "com.apple.voice.enhanced.en-IE.Moira", "com.apple.voice.compact.es-ES.Monica", "com.apple.voice.compact.ca-ES.Montserrat", "com.apple.voice.enhanced.en-US.Nathan", "com.apple.voice.enhanced.en-US.Noelle", "com.apple.voice.compact.nb-NO.Nora", "com.apple.speech.synthesis.voice.Organ", "com.apple.voice.compact.ja-JP.Otoya", "com.apple.voice.enhanced.ja-JP.Otoya", "com.apple.voice.compact.es-MX.Paulina", "com.apple.speech.synthesis.voice.Princess", "com.apple.speech.synthesis.voice.Ralph", "com.apple.eloquence.de-DE.Reed", "com.apple.eloquence.en-GB.Reed", "com.apple.eloquence.en-US.Reed", "com.apple.eloquence.es-ES.Reed", "com.apple.eloquence.es-MX.Reed", "com.apple.eloquence.fi-FI.Reed", "com.apple.eloquence.fr-CA.Reed", "com.apple.eloquence.it-IT.Reed", "com.apple.eloquence.ja-JP.Reed", "com.apple.eloquence.ko-KR.Reed", "com.apple.eloquence.pt-BR.Reed", "com.apple.eloquence.zh-CN.Reed", "com.apple.eloquence.zh-TW.Reed", "com.apple.voice.compact.en-IN.Rishi", "com.apple.eloquence.de-DE.Rocko", "com.apple.eloquence.en-GB.Rocko", "com.apple.eloquence.en-US.Rocko", "com.apple.eloquence.es-ES.Rocko", "com.apple.eloquence.es-MX.Rocko", "com.apple.eloquence.fi-FI.Rocko", "com.apple.eloquence.fr-CA.Rocko", "com.apple.eloquence.fr-FR.Rocko", "com.apple.eloquence.it-IT.Rocko", "com.apple.eloquence.ja-JP.Rocko", "com.apple.eloquence.ko-KR.Rocko", "com.apple.eloquence.pt-BR.Rocko", "com.apple.eloquence.zh-CN.Rocko", "com.apple.eloquence.zh-TW.Rocko", "com.apple.voice.compact.en-US.Samantha", "com.apple.voice.enhanced.en-US.Samantha", "com.apple.eloquence.de-DE.Sandy", "com.apple.eloquence.en-GB.Sandy", "com.apple.eloquence.en-US.Sandy", "com.apple.eloquence.es-ES.Sandy", "com.apple.eloquence.es-MX.Sandy", "com.apple.eloquence.fi-FI.Sandy", "com.apple.eloquence.fr-CA.Sandy", "com.apple.eloquence.fr-FR.Sandy", "com.apple.eloquence.it-IT.Sandy", "com.apple.eloquence.ja-JP.Sandy", "com.apple.eloquence.ko-KR.Sandy", "com.apple.eloquence.pt-BR.Sandy", "com.apple.eloquence.zh-CN.Sandy", "com.apple.eloquence.zh-TW.Sandy", "com.apple.voice.compact.da-DK.Sara", "com.apple.voice.compact.fi-FI.Satu", "com.apple.eloquence.de-DE.Shelley", "com.apple.eloquence.en-GB.Shelley", "com.apple.eloquence.en-US.Shelley", "com.apple.eloquence.es-ES.Shelley", "com.apple.eloquence.es-MX.Shelley", "com.apple.eloquence.fi-FI.Shelley", "com.apple.eloquence.fr-CA.Shelley", "com.apple.eloquence.fr-FR.Shelley", "com.apple.eloquence.it-IT.Shelley", "com.apple.eloquence.ja-JP.Shelley", "com.apple.eloquence.ko-KR.Shelley", "com.apple.eloquence.pt-BR.Shelley", "com.apple.eloquence.zh-CN.Shelley", "com.apple.eloquence.zh-TW.Shelley", "com.apple.voice.compact.zh-HK.Sinji", "com.apple.voice.compact.en-US.Susan", "com.apple.voice.enhanced.en-US.Susan", "com.apple.voice.compact.en-ZA.Tessa", "com.apple.voice.compact.fr-FR.Thomas", "com.apple.voice.compact.sl-SI.Tina", "com.apple.voice.compact.zh-CN.Tingting", "com.apple.voice.compact.en-US.Tom", "com.apple.voice.enhanced.en-US.Tom", "com.apple.speech.synthesis.voice.Trinoids", "com.apple.speech.synthesis.voice.Whisper", "com.apple.voice.compact.nl-NL.Xander", "com.apple.voice.compact.tr-TR.Yelda", "com.apple.voice.compact.ko-KR.Yuna", "com.apple.speech.synthesis.voice.Zarvox", "com.apple.voice.enhanced.en-US.Zoe", "com.apple.voice.premium.en-US.Zoe", "com.apple.voice.compact.pl-PL.Zosia", "com.apple.voice.compact.cs-CZ.Zuzana"}

★Click Here to Open This Script 

AppleScript名:AVSpeechSynthesisVoiceのIDを取得_macOS15.0.scpt
— Created 2018-02-15 by Takaaki Naganoya
— 2018 Piyomaru Software
use AppleScript version "2.8"
use scripting additions
use framework "Foundation"
use framework "AVFoundation"

set aList to (current application’s AVSpeechSynthesisVoice’s speechVoices()’s valueForKey:"identifier") as list
–macOS 13 (190)
–> {"com.apple.voice.compact.ar-001.Maged", "com.apple.voice.compact.bg-BG.Daria", "com.apple.voice.compact.ca-ES.Montserrat", "com.apple.voice.compact.cs-CZ.Zuzana", "com.apple.voice.compact.da-DK.Sara", "com.apple.eloquence.de-DE.Sandy", "com.apple.eloquence.de-DE.Shelley", "com.apple.ttsbundle.siri_Helena_de-DE_compact", "com.apple.eloquence.de-DE.Grandma", "com.apple.eloquence.de-DE.Grandpa", "com.apple.eloquence.de-DE.Eddy", "com.apple.eloquence.de-DE.Reed", "com.apple.voice.compact.de-DE.Anna", "com.apple.ttsbundle.siri_Martin_de-DE_compact", "com.apple.eloquence.de-DE.Rocko", "com.apple.eloquence.de-DE.Flo", "com.apple.voice.compact.el-GR.Melina", "com.apple.ttsbundle.siri_Gordon_en-AU_compact", "com.apple.voice.compact.en-AU.Karen", "com.apple.ttsbundle.siri_Catherine_en-AU_compact", "com.apple.voice.premium.en-GB.Malcolm", "com.apple.voice.enhanced.en-GB.Daniel", "com.apple.ttsbundle.Oliver-premium", "com.apple.voice.enhanced.en-GB.Kate", "com.apple.eloquence.en-GB.Rocko", "com.apple.eloquence.en-GB.Shelley", "com.apple.ttsbundle.Oliver-compact", "com.apple.voice.compact.en-GB.Daniel", "com.apple.ttsbundle.siri_Martha_en-GB_compact", "com.apple.eloquence.en-GB.Grandma", "com.apple.eloquence.en-GB.Grandpa", "com.apple.eloquence.en-GB.Flo", "com.apple.eloquence.en-GB.Eddy", "com.apple.eloquence.en-GB.Reed", "com.apple.eloquence.en-GB.Sandy", "com.apple.ttsbundle.siri_Arthur_en-GB_compact", "com.apple.voice.enhanced.en-IE.Moira", "com.apple.voice.compact.en-IE.Moira", "com.apple.voice.compact.en-IN.Rishi", "com.apple.voice.premium.en-US.Zoe", "com.apple.voice.premium.en-US.Ava", "com.apple.voice.enhanced.en-US.Samantha", "com.apple.voice.enhanced.en-US.Evan", "com.apple.voice.enhanced.en-US.Zoe", "com.apple.voice.enhanced.en-US.Joelle", "com.apple.voice.enhanced.en-US.Susan", "com.apple.voice.enhanced.en-US.Nathan", "com.apple.voice.enhanced.en-US.Tom", "com.apple.voice.enhanced.en-US.Noelle", "com.apple.eloquence.en-US.Flo", "com.apple.speech.synthesis.voice.Albert", "com.apple.speech.synthesis.voice.Bahh", "com.apple.speech.synthesis.voice.Fred", "com.apple.speech.synthesis.voice.Hysterical", "com.apple.voice.compact.en-US.Allison", "com.apple.speech.synthesis.voice.Organ", "com.apple.speech.synthesis.voice.Cellos", "com.apple.voice.compact.en-US.Evan", "com.apple.speech.synthesis.voice.Zarvox", "com.apple.eloquence.en-US.Rocko", "com.apple.eloquence.en-US.Shelley", "com.apple.speech.synthesis.voice.Princess", "com.apple.eloquence.en-US.Grandma", "com.apple.eloquence.en-US.Eddy", "com.apple.speech.synthesis.voice.Bells", "com.apple.eloquence.en-US.Grandpa", "com.apple.speech.synthesis.voice.Trinoids", "com.apple.speech.synthesis.voice.Kathy", "com.apple.eloquence.en-US.Reed", "com.apple.speech.synthesis.voice.Boing", "com.apple.speech.synthesis.voice.GoodNews", "com.apple.speech.synthesis.voice.Whisper", "com.apple.speech.synthesis.voice.Bruce", "com.apple.speech.synthesis.voice.Deranged", "com.apple.ttsbundle.siri_Nicky_en-US_compact", "com.apple.speech.synthesis.voice.BadNews", "com.apple.ttsbundle.siri_Aaron_en-US_compact", "com.apple.speech.synthesis.voice.Bubbles", "com.apple.voice.compact.en-US.Susan", "com.apple.voice.compact.en-US.Tom", "com.apple.speech.synthesis.voice.Agnes", "com.apple.voice.compact.en-US.Samantha", "com.apple.eloquence.en-US.Sandy", "com.apple.speech.synthesis.voice.Junior", "com.apple.voice.compact.en-US.Ava", "com.apple.speech.synthesis.voice.Ralph", "com.apple.voice.compact.en-ZA.Tessa", "com.apple.eloquence.es-ES.Shelley", "com.apple.eloquence.es-ES.Grandma", "com.apple.eloquence.es-ES.Rocko", "com.apple.eloquence.es-ES.Grandpa", "com.apple.eloquence.es-ES.Flo", "com.apple.eloquence.es-ES.Sandy", "com.apple.voice.compact.es-ES.Monica", "com.apple.eloquence.es-ES.Eddy", "com.apple.eloquence.es-ES.Reed", "com.apple.eloquence.es-MX.Rocko", "com.apple.voice.compact.es-MX.Paulina", "com.apple.eloquence.es-MX.Flo", "com.apple.eloquence.es-MX.Sandy", "com.apple.eloquence.es-MX.Eddy", "com.apple.eloquence.es-MX.Shelley", "com.apple.eloquence.es-MX.Reed", "com.apple.eloquence.es-MX.Grandma", "com.apple.eloquence.es-MX.Grandpa", "com.apple.eloquence.fi-FI.Shelley", "com.apple.eloquence.fi-FI.Grandma", "com.apple.eloquence.fi-FI.Grandpa", "com.apple.eloquence.fi-FI.Sandy", "com.apple.voice.compact.fi-FI.Satu", "com.apple.eloquence.fi-FI.Eddy", "com.apple.eloquence.fi-FI.Rocko", "com.apple.eloquence.fi-FI.Reed", "com.apple.eloquence.fi-FI.Flo", "com.apple.voice.premium.fr-CA.Amelie", "com.apple.voice.enhanced.fr-CA.Chantal", "com.apple.eloquence.fr-CA.Shelley", "com.apple.eloquence.fr-CA.Grandma", "com.apple.eloquence.fr-CA.Grandpa", "com.apple.eloquence.fr-CA.Rocko", "com.apple.eloquence.fr-CA.Eddy", "com.apple.eloquence.fr-CA.Reed", "com.apple.voice.compact.fr-CA.Amelie", "com.apple.eloquence.fr-CA.Flo", "com.apple.eloquence.fr-CA.Sandy", "com.apple.eloquence.fr-FR.Grandma", "com.apple.eloquence.fr-FR.Flo", "com.apple.eloquence.fr-FR.Rocko", "com.apple.eloquence.fr-FR.Grandpa", "com.apple.eloquence.fr-FR.Sandy", "com.apple.eloquence.fr-FR.Eddy", "com.apple.voice.compact.fr-FR.Thomas", "com.apple.ttsbundle.siri_Dan_fr-FR_compact", "com.apple.eloquence.fr-FR.Jacques", "com.apple.ttsbundle.siri_Marie_fr-FR_compact", "com.apple.eloquence.fr-FR.Shelley", "com.apple.voice.compact.he-IL.Carmit", "com.apple.voice.compact.hi-IN.Lekha", "com.apple.voice.compact.hr-HR.Lana", "com.apple.voice.compact.hu-HU.Mariska", "com.apple.voice.compact.id-ID.Damayanti", "com.apple.eloquence.it-IT.Eddy", "com.apple.eloquence.it-IT.Sandy", "com.apple.eloquence.it-IT.Reed", "com.apple.eloquence.it-IT.Shelley", "com.apple.eloquence.it-IT.Grandma", "com.apple.eloquence.it-IT.Grandpa", "com.apple.eloquence.it-IT.Flo", "com.apple.eloquence.it-IT.Rocko", "com.apple.voice.compact.it-IT.Alice", "com.apple.ttsbundle.siri_Hattori_ja-JP_premium", "com.apple.ttsbundle.siri_O-Ren_ja-JP_premium", "com.apple.voice.enhanced.ja-JP.Kyoko", "com.apple.voice.enhanced.ja-JP.Otoya", "com.apple.voice.compact.ja-JP.Kyoko", "com.apple.ttsbundle.siri_Hattori_ja-JP_compact", "com.apple.voice.compact.ja-JP.Otoya", "com.apple.ttsbundle.siri_O-Ren_ja-JP_compact", "com.apple.voice.compact.ko-KR.Yuna", "com.apple.voice.compact.ms-MY.Amira", "com.apple.voice.compact.nb-NO.Nora", "com.apple.voice.compact.nl-BE.Ellen", "com.apple.voice.compact.nl-NL.Xander", "com.apple.voice.compact.pl-PL.Zosia", "com.apple.eloquence.pt-BR.Reed", "com.apple.voice.compact.pt-BR.Luciana", "com.apple.eloquence.pt-BR.Shelley", "com.apple.eloquence.pt-BR.Grandma", "com.apple.eloquence.pt-BR.Grandpa", "com.apple.eloquence.pt-BR.Rocko", "com.apple.eloquence.pt-BR.Flo", "com.apple.eloquence.pt-BR.Sandy", "com.apple.eloquence.pt-BR.Eddy", "com.apple.voice.compact.pt-PT.Joana", "com.apple.voice.compact.ro-RO.Ioana", "com.apple.voice.compact.ru-RU.Milena", "com.apple.voice.compact.sk-SK.Laura", "com.apple.voice.compact.sv-SE.Alva", "com.apple.voice.compact.th-TH.Kanya", "com.apple.voice.compact.tr-TR.Yelda", "com.apple.voice.compact.uk-UA.Lesya", "com.apple.voice.compact.vi-VN.Linh", "com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact", "com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact", "com.apple.voice.compact.zh-CN.Tingting", "com.apple.ttsbundle.Sin-ji-premium", "com.apple.voice.compact.zh-HK.Sinji", "com.apple.ttsbundle.Mei-Jia-premium", "com.apple.voice.compact.zh-TW.Meijia", "com.apple.speech.synthesis.voice.Alex"}

–macOS 15 (222)
–> {"com.apple.voice.compact.ar-001.Maged", "com.apple.voice.compact.bg-BG.Daria", "com.apple.voice.compact.ca-ES.Montserrat", "com.apple.voice.compact.cs-CZ.Zuzana", "com.apple.voice.compact.da-DK.Sara", "com.apple.eloquence.de-DE.Sandy", "com.apple.eloquence.de-DE.Shelley", "com.apple.ttsbundle.siri_Helena_de-DE_compact", "com.apple.eloquence.de-DE.Grandma", "com.apple.eloquence.de-DE.Grandpa", "com.apple.eloquence.de-DE.Eddy", "com.apple.eloquence.de-DE.Reed", "com.apple.voice.compact.de-DE.Anna", "com.apple.ttsbundle.siri_Martin_de-DE_compact", "com.apple.eloquence.de-DE.Rocko", "com.apple.eloquence.de-DE.Flo", "com.apple.voice.compact.el-GR.Melina", "com.apple.ttsbundle.siri_Gordon_en-AU_compact", "com.apple.voice.compact.en-AU.Karen", "com.apple.ttsbundle.siri_Catherine_en-AU_compact", "com.apple.voice.premium.en-GB.Malcolm", "com.apple.voice.enhanced.en-GB.Daniel", "com.apple.voice.enhanced.en-GB.Kate", "com.apple.eloquence.en-GB.Rocko", "com.apple.eloquence.en-GB.Shelley", "com.apple.voice.compact.en-GB.Daniel", "com.apple.ttsbundle.siri_Martha_en-GB_compact", "com.apple.eloquence.en-GB.Grandma", "com.apple.eloquence.en-GB.Grandpa", "com.apple.eloquence.en-GB.Flo", "com.apple.eloquence.en-GB.Eddy", "com.apple.eloquence.en-GB.Reed", "com.apple.eloquence.en-GB.Sandy", "com.apple.ttsbundle.siri_Arthur_en-GB_compact", "com.apple.voice.enhanced.en-IE.Moira", "com.apple.voice.compact.en-IE.Moira", "com.apple.voice.compact.en-IN.Rishi", "com.apple.voice.premium.en-US.Zoe", "com.apple.voice.premium.en-US.Ava", "com.apple.voice.enhanced.en-US.Samantha", "com.apple.voice.enhanced.en-US.Evan", "com.apple.ttsbundle.siri_Nicky_en-US_premium", "com.apple.voice.enhanced.en-US.Ava", "com.apple.voice.enhanced.en-US.Zoe", "com.apple.voice.enhanced.en-US.Joelle", "com.apple.voice.enhanced.en-US.Susan", "com.apple.voice.enhanced.en-US.Allison", "com.apple.speech.synthesis.voice.Bruce", "com.apple.voice.enhanced.en-US.Nathan", "com.apple.voice.enhanced.en-US.Tom", "com.apple.speech.synthesis.voice.Agnes", "com.apple.voice.enhanced.en-US.Noelle", "com.apple.eloquence.en-US.Flo", "com.apple.speech.synthesis.voice.Bahh", "com.apple.speech.synthesis.voice.Fred", "com.apple.speech.synthesis.voice.Albert", "com.apple.speech.synthesis.voice.Hysterical", "com.apple.voice.compact.en-US.Allison", "com.apple.speech.synthesis.voice.Organ", "com.apple.speech.synthesis.voice.Cellos", "com.apple.voice.compact.en-US.Evan", "com.apple.speech.synthesis.voice.Zarvox", "com.apple.eloquence.en-US.Rocko", "com.apple.eloquence.en-US.Shelley", "com.apple.speech.synthesis.voice.Princess", "com.apple.eloquence.en-US.Grandma", "com.apple.eloquence.en-US.Eddy", "com.apple.speech.synthesis.voice.Bells", "com.apple.eloquence.en-US.Grandpa", "com.apple.speech.synthesis.voice.Kathy", "com.apple.speech.synthesis.voice.Trinoids", "com.apple.eloquence.en-US.Reed", "com.apple.speech.synthesis.voice.Boing", "com.apple.speech.synthesis.voice.Whisper", "com.apple.speech.synthesis.voice.GoodNews", "com.apple.speech.synthesis.voice.Deranged", "com.apple.ttsbundle.siri_Nicky_en-US_compact", "com.apple.speech.synthesis.voice.BadNews", "com.apple.ttsbundle.siri_Aaron_en-US_compact", "com.apple.speech.synthesis.voice.Bubbles", "com.apple.voice.compact.en-US.Susan", "com.apple.voice.compact.en-US.Tom", "com.apple.voice.compact.en-US.Samantha", "com.apple.eloquence.en-US.Sandy", "com.apple.speech.synthesis.voice.Junior", "com.apple.voice.compact.en-US.Ava", "com.apple.speech.synthesis.voice.Ralph", "com.apple.voice.compact.en-ZA.Tessa", "com.apple.eloquence.es-ES.Shelley", "com.apple.eloquence.es-ES.Grandma", "com.apple.eloquence.es-ES.Rocko", "com.apple.eloquence.es-ES.Grandpa", "com.apple.eloquence.es-ES.Flo", "com.apple.eloquence.es-ES.Sandy", "com.apple.voice.compact.es-ES.Monica", "com.apple.eloquence.es-ES.Eddy", "com.apple.eloquence.es-ES.Reed", "com.apple.eloquence.es-MX.Rocko", "com.apple.voice.compact.es-MX.Paulina", "com.apple.eloquence.es-MX.Flo", "com.apple.eloquence.es-MX.Sandy", "com.apple.eloquence.es-MX.Eddy", "com.apple.eloquence.es-MX.Shelley", "com.apple.eloquence.es-MX.Grandma", "com.apple.eloquence.es-MX.Reed", "com.apple.eloquence.es-MX.Grandpa", "com.apple.eloquence.fi-FI.Shelley", "com.apple.eloquence.fi-FI.Grandma", "com.apple.eloquence.fi-FI.Grandpa", "com.apple.eloquence.fi-FI.Sandy", "com.apple.voice.compact.fi-FI.Satu", "com.apple.eloquence.fi-FI.Eddy", "com.apple.eloquence.fi-FI.Rocko", "com.apple.eloquence.fi-FI.Reed", "com.apple.eloquence.fi-FI.Flo", "com.apple.voice.premium.fr-CA.Amelie", "com.apple.voice.enhanced.fr-CA.Chantal", "com.apple.eloquence.fr-CA.Shelley", "com.apple.eloquence.fr-CA.Grandma", "com.apple.eloquence.fr-CA.Grandpa", "com.apple.eloquence.fr-CA.Rocko", "com.apple.eloquence.fr-CA.Eddy", "com.apple.eloquence.fr-CA.Reed", "com.apple.voice.compact.fr-CA.Amelie", "com.apple.eloquence.fr-CA.Flo", "com.apple.eloquence.fr-CA.Sandy", "com.apple.eloquence.fr-FR.Grandma", "com.apple.eloquence.fr-FR.Flo", "com.apple.eloquence.fr-FR.Rocko", "com.apple.eloquence.fr-FR.Grandpa", "com.apple.eloquence.fr-FR.Sandy", "com.apple.eloquence.fr-FR.Eddy", "com.apple.voice.compact.fr-FR.Thomas", "com.apple.ttsbundle.siri_Dan_fr-FR_compact", "com.apple.eloquence.fr-FR.Jacques", "com.apple.ttsbundle.siri_Marie_fr-FR_compact", "com.apple.eloquence.fr-FR.Shelley", "com.apple.voice.compact.he-IL.Carmit", "com.apple.voice.compact.hi-IN.Lekha", "com.apple.voice.compact.hr-HR.Lana", "com.apple.voice.compact.hu-HU.Mariska", "com.apple.voice.compact.id-ID.Damayanti", "com.apple.eloquence.it-IT.Eddy", "com.apple.eloquence.it-IT.Sandy", "com.apple.eloquence.it-IT.Reed", "com.apple.eloquence.it-IT.Shelley", "com.apple.eloquence.it-IT.Grandma", "com.apple.eloquence.it-IT.Grandpa", "com.apple.eloquence.it-IT.Flo", "com.apple.eloquence.it-IT.Rocko", "com.apple.voice.compact.it-IT.Alice", "com.apple.ttsbundle.siri_Hattori_ja-JP_premium", "com.apple.ttsbundle.siri_O-Ren_ja-JP_premium", "com.apple.voice.enhanced.ja-JP.Kyoko", "com.apple.voice.enhanced.ja-JP.Otoya", "com.apple.eloquence.ja-JP.Eddy", "com.apple.eloquence.ja-JP.Reed", "com.apple.eloquence.ja-JP.Shelley", "com.apple.voice.compact.ja-JP.Kyoko", "com.apple.eloquence.ja-JP.Grandma", "com.apple.eloquence.ja-JP.Rocko", "com.apple.eloquence.ja-JP.Grandpa", "com.apple.ttsbundle.siri_Hattori_ja-JP_compact", "com.apple.voice.compact.ja-JP.Otoya", "com.apple.eloquence.ja-JP.Sandy", "com.apple.ttsbundle.siri_O-Ren_ja-JP_compact", "com.apple.eloquence.ja-JP.Flo", "com.apple.eloquence.ko-KR.Rocko", "com.apple.eloquence.ko-KR.Grandma", "com.apple.eloquence.ko-KR.Grandpa", "com.apple.eloquence.ko-KR.Eddy", "com.apple.eloquence.ko-KR.Sandy", "com.apple.voice.compact.ko-KR.Yuna", "com.apple.eloquence.ko-KR.Reed", "com.apple.eloquence.ko-KR.Flo", "com.apple.eloquence.ko-KR.Shelley", "com.apple.voice.compact.ms-MY.Amira", "com.apple.voice.compact.nb-NO.Nora", "com.apple.voice.compact.nl-BE.Ellen", "com.apple.voice.compact.nl-NL.Xander", "com.apple.voice.compact.pl-PL.Zosia", "com.apple.eloquence.pt-BR.Reed", "com.apple.voice.compact.pt-BR.Luciana", "com.apple.eloquence.pt-BR.Shelley", "com.apple.eloquence.pt-BR.Grandma", "com.apple.eloquence.pt-BR.Grandpa", "com.apple.eloquence.pt-BR.Rocko", "com.apple.eloquence.pt-BR.Flo", "com.apple.eloquence.pt-BR.Sandy", "com.apple.eloquence.pt-BR.Eddy", "com.apple.voice.compact.pt-PT.Joana", "com.apple.voice.compact.ro-RO.Ioana", "com.apple.voice.compact.ru-RU.Milena", "com.apple.voice.compact.sk-SK.Laura", "com.apple.voice.compact.sl-SI.Tina", "com.apple.voice.compact.sv-SE.Alva", "com.apple.voice.compact.th-TH.Kanya", "com.apple.voice.compact.tr-TR.Yelda", "com.apple.voice.compact.uk-UA.Lesya", "com.apple.voice.compact.vi-VN.Linh", "com.apple.eloquence.zh-CN.Eddy", "com.apple.eloquence.zh-CN.Shelley", "com.apple.ttsbundle.siri_Yu-Shu_zh-CN_compact", "com.apple.eloquence.zh-CN.Grandma", "com.apple.eloquence.zh-CN.Reed", "com.apple.eloquence.zh-CN.Grandpa", "com.apple.eloquence.zh-CN.Rocko", "com.apple.ttsbundle.siri_Li-Mu_zh-CN_compact", "com.apple.eloquence.zh-CN.Flo", "com.apple.voice.compact.zh-CN.Tingting", "com.apple.eloquence.zh-CN.Sandy", "com.apple.voice.compact.zh-HK.Sinji", "com.apple.eloquence.zh-TW.Shelley", "com.apple.eloquence.zh-TW.Grandma", "com.apple.eloquence.zh-TW.Grandpa", "com.apple.eloquence.zh-TW.Sandy", "com.apple.eloquence.zh-TW.Flo", "com.apple.eloquence.zh-TW.Eddy", "com.apple.eloquence.zh-TW.Reed", "com.apple.voice.compact.zh-TW.Meijia", "com.apple.eloquence.zh-TW.Rocko", "com.apple.speech.synthesis.voice.Alex"}

★Click Here to Open This Script 

Posted in Text to Speech | Tagged 15.0savvy | Leave a comment

Pages書類の内容を伏せ字に v2

Posted on 10月 5, 2024 by Takaaki Naganoya

現在オープン中の最前面のPages書類の内容を伏せ字に置き換えるAppleScriptの改良版です。電子書籍「Pages+AppleScriptで本をつくろう!」のために作成したScriptの改良版です。

–> Download Script Bundle With library

実行にはライブラリ「dynamicClicker」が必要なため、上記リンクからAppleScriptバンドル書類をダウンロードして実行してください。

Pagesの書類上のオブジェクトは、

のようになっており(iWork Scripting Book with AppleScriptより引用)、shapeとtext itemの区別ができないという「頭のおかしな仕様」になっていますが、オブジェクトのclassを求めれば、だいたいは区別できる状況です。

group itemについてはメニューを強制操作して(なくなるまで永久ループで)グループ解除を行い、そののちにshapeとtableについては伏せ字処理を行います。

image、chart、movieなどのオブジェクトについては伏せ字処理を行いませんが、そのあたりは処理したいユーザーの趣味次第でしょう。

AppleScript名:全ページを伏せ字に v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/02
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

tell application "Pages"
  tell front document
    set pCount to count every page
    
repeat with p from 1 to pCount
      tell page p
        –ひたすらグループ化されたアイテムを解除する。多重にグループ化が可能なので、ひたすら繰り返す
        
repeat
          set gList to every group
          
if gList = {} then exit repeat
          
set gRes to ungroupPagesItems(gList) of me
        end repeat
        
        
–通常処理
        
set aList to every iWork item
        
        
repeat with i in aList
          set j to contents of i
          
set tmpClass to class of j
          
          
if tmpClass = shape then
            set aText to object text of j
            
set mText to maskStrings(aText) of me
            
set object text of j to mText
            
          else if tmpClass = table then
            tell j
              set tmpW to width
              
set tmpH to height
              
set tumeF to false
              
set cColumn to count every column
              
              
if tmpW = 0 or tmpH = 0 then
                —
              else
                set aRatio to tmpW / tmpH
                
                
if aRatio < 0.125 then set tumeF to true
                
if cColumn = 1 then set tumeF to true
              end if
            end tell
            
            
–表がツメでない場合にのみ処理
            
if tumeF = false then
              tell j
                set aTitle to ""
                
try
                  set aTitle to name of it
                  
set mText to maskStrings(aTitle) of me
                  
set name of it to mText
                end try
                
                
set cellList to every cell
                
repeat with ii in cellList
                  set jj to contents of ii
                  
set aValue to (value of jj) as string
                  
set mText to maskStrings(aValue) of me
                  
set value of jj to mText
                end repeat
                
              end tell
              
            end if
          end if
          
        end repeat
        
      end tell
    end repeat
  end tell
end tell

–Pagesで選択中のアイテムをグループ解除する
on ungroupPagesItems(gList as list)
  set appName to "Pages" –Application Name
  
set aList to {"配置", "グループ解除"} –Localized Menu Titles (menu title structure to "Ungroup")
  
  
tell application "Pages"
    tell front document
      set selection to gList
    end tell
  end tell
  
  
set aRes to clickSpecifiedMenuElement(appName, aList) of dLib
  
return aRes
end ungroupPagesItems

–指定したルールのとおりの文字種の並びになっているか?
on maskStrings(aStr)
  set aList to characters of aStr
  
  
set chkList to {}
  
repeat with i from 1 to (length of aList)
    set j1 to contents of item i of aList
    
    
set tmpStr to j1
    
    
set j2 to (my chkNumeric:j1)
    
set j3 to (my chkAlphabetCapt:j1)
    
set j4 to (my chkAlphabetSmall:j1)
    
    
if j2 = true then
      set tmpStr to "9"
    else if j3 = true then
      set tmpStr to "Z"
    else if j4 = true then
      set tmpStr to "z"
    else
      set tmpStr to "あ"
    end if
    
    
set the end of chkList to tmpStr
  end repeat
  
return chkList as string
end maskStrings

— アルファベット大文字か
on chkAlphabetCapt:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set allCharSet to current application’s NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabetCapt:

— アルファベット小文字か
on chkAlphabetSmall:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set allCharSet to current application’s NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabetSmall:

–数字のみか
on chkNumeric:checkString
  set digitCharSet to current application’s NSCharacterSet’s characterSetWithCharactersInString:"0123456789"
  
set ret to my chkCompareString:checkString baseString:digitCharSet
  
return ret as boolean
end chkNumeric:

–アルファベットと数字のみか
on chkAlphaNumeric:checkString
  set alnumCharSet to current application’s NSCharacterSet’s alphanumericCharacterSet()
  
set ret to my chkCompareString:checkString baseString:alnumCharSet
  
return ret as boolean
end chkAlphaNumeric:

–アルファベットと数字と記号のみか
on chkAlphaNumericSymbol:checkString
  set muCharSet to current application’s NSCharacterSet’s alphanumericCharacterSet()’s mutableCopy()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkAlphaNumericSymbol:

–記号のみか
on chkSymbol:checkString
  set muCharSet to current application’s NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSymbol:

–全角文字が存在するか
on chkMultiByteChar:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set aRes to aStr’s canBeConvertedToEncoding:(current application’s NSASCIIStringEncoding)
  
return (aRes as boolean)
end chkMultiByteChar:

on chkCompareString:checkString baseString:baseString
  set aScanner to current application’s NSScanner’s localizedScannerWithString:checkString
  
aScanner’s setCharactersToBeSkipped:(missing value)
  
aScanner’s scanCharactersFromSet:baseString intoString:(missing value)
  
return (aScanner’s isAtEnd()) as boolean
end chkCompareString:baseString:

on chkCompareString:checkString characterSet:baseSet
  set anNSString to current application’s NSString’s stringWithString:checkString
  
set theRange to anNSString’s rangeOfCharacterFromSet:baseSet
  
return (|length| of theRange = 0) as boolean
end chkCompareString:characterSet:

★Click Here to Open This Script 

Posted in Object control | Tagged 13.0savvy 14.0savvy 15.0savvy Pages | Leave a comment

Pages書類の内容を伏せ字に

Posted on 10月 3, 2024 by Takaaki Naganoya

現在オープン中の最前面のPages書類の内容を伏せ字に置き換えるAppleScriptです。

新刊「Pages+AppleScriptで本をつくろう!」の作成のために書いたものです。Pages書類を付録として電子書籍に添付する場合に、あくまでデザインテンプレートとしての利用を見込んでいるため、本文がそのまま入っていると困るわけです、私が。

そんなわけで、せっかく作ったPages書類の内容を伏せ字にして、ダミー書類化するためのAppleScriptが必要になったわけです。

一応、テキストを伏せ字にするAppleScriptは作ってあったので、これをPages書類相手に処理するよう書き換えたものがこれです。


▲処理前


▲処理後

ただし、すべてのPages書類内のオブジェクトに対応していません。groupオブジェクトについては、メニュー操作を行えばグループ解除を行えなくもないですが、未着手です。

ちょっと気をつけて処理したのが「表」の内部セルに入っている値です。空欄だと値(value)がmissing valueになるので、そこは触らないほうがよかったかもしれません。

自分だけの事情になりますが、ページ左右端に「ツメ」と呼ばれるマークを「表」オブジェクトを用いて記入しているため、この「ツメ」に相当する「表」については無視するようにしています。

AppleScript名:全ページを伏せ字に.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/10/02
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

tell application "Pages"
  tell front document
    set pCount to count every page
    
repeat with p from 1 to pCount
      tell page p
        set aList to every iWork item
        
        
repeat with i in aList
          set j to contents of i
          
set tmpClass to class of j
          
          
if tmpClass = shape then
            set aText to object text of j
            
set mText to maskStrings(aText) of me
            
set object text of j to mText
            
          else if tmpClass = group then
            
            
            
          else if tmpClass = table then
            tell j
              set tmpW to width
              
set tmpH to height
              
set tumeF to false
              
set cColumn to count every column
              
              
if tmpW = 0 or tmpH = 0 then
                —
              else
                set aRatio to tmpW / tmpH
                
                
if aRatio < 0.125 then set tumeF to true
                
if cColumn = 1 then set tumeF to true
              end if
            end tell
            
            
–表がツメでない場合にのみ処理
            
if tumeF = false then
              tell j
                set aTitle to ""
                
try
                  set aTitle to name of it
                  
set mText to maskStrings(aTitle) of me
                  
set name of it to mText
                end try
                
                
set cellList to every cell
                
repeat with ii in cellList
                  set jj to contents of ii
                  
set aValue to (value of jj) as string
                  
set mText to maskStrings(aValue) of me
                  
set value of jj to mText
                end repeat
                
              end tell
              
            end if
          end if
          
        end repeat
        
      end tell
    end repeat
  end tell
end tell

–指定したルールのとおりの文字種の並びになっているか?
on maskStrings(aStr)
  set aList to characters of aStr
  
  
set chkList to {}
  
repeat with i from 1 to (length of aList)
    set j1 to contents of item i of aList
    
    
set tmpStr to j1
    
    
set j2 to (my chkNumeric:j1)
    
set j3 to (my chkAlphabetCapt:j1)
    
set j4 to (my chkAlphabetSmall:j1)
    
    
if j2 = true then
      set tmpStr to "9"
    else if j3 = true then
      set tmpStr to "Z"
    else if j4 = true then
      set tmpStr to "z"
    else
      set tmpStr to "あ"
    end if
    
    
set the end of chkList to tmpStr
  end repeat
  
return chkList as string
end maskStrings

— アルファベット大文字か
on chkAlphabetCapt:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set allCharSet to current application’s NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "A", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabetCapt:

— アルファベット小文字か
on chkAlphabetSmall:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set allCharSet to current application’s NSMutableCharacterSet’s alloc()’s init()
  
allCharSet’s addCharactersInRange:(current application’s NSMakeRange(ASCII number of "a", 26))
  
set aBool to my chkCompareString:aStr baseString:allCharSet
  
return aBool as boolean
end chkAlphabetSmall:

–数字のみか
on chkNumeric:checkString
  set digitCharSet to current application’s NSCharacterSet’s characterSetWithCharactersInString:"0123456789"
  
set ret to my chkCompareString:checkString baseString:digitCharSet
  
return ret as boolean
end chkNumeric:

–アルファベットと数字のみか
on chkAlphaNumeric:checkString
  set alnumCharSet to current application’s NSCharacterSet’s alphanumericCharacterSet()
  
set ret to my chkCompareString:checkString baseString:alnumCharSet
  
return ret as boolean
end chkAlphaNumeric:

–アルファベットと数字と記号のみか
on chkAlphaNumericSymbol:checkString
  set muCharSet to current application’s NSCharacterSet’s alphanumericCharacterSet()’s mutableCopy()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkAlphaNumericSymbol:

–記号のみか
on chkSymbol:checkString
  set muCharSet to current application’s NSCharacterSet’s alloc()’s init()
  
muCharSet’s addCharactersInString:"$\"!~&=#[]._-+`|{}?%^*/’@-/:;(),"
  
set ret to my chkCompareString:checkString baseString:muCharSet
  
return ret as boolean
end chkSymbol:

–全角文字が存在するか
on chkMultiByteChar:checkString
  set aStr to current application’s NSString’s stringWithString:checkString
  
set aRes to aStr’s canBeConvertedToEncoding:(current application’s NSASCIIStringEncoding)
  
return (aRes as boolean)
end chkMultiByteChar:

on chkCompareString:checkString baseString:baseString
  set aScanner to current application’s NSScanner’s localizedScannerWithString:checkString
  
aScanner’s setCharactersToBeSkipped:(missing value)
  
aScanner’s scanCharactersFromSet:baseString intoString:(missing value)
  
return (aScanner’s isAtEnd()) as boolean
end chkCompareString:baseString:

on chkCompareString:checkString characterSet:baseSet
  set anNSString to current application’s NSString’s stringWithString:checkString
  
set theRange to anNSString’s rangeOfCharacterFromSet:baseSet
  
return (|length| of theRange = 0) as boolean
end chkCompareString:characterSet:

★Click Here to Open This Script 

Posted in Object control Text | Tagged 13.0savvy 14.0savvy 15.0savvy Pages | Leave a comment

新刊電子書籍「Pages+AppleScriptで本をつくろう!」を刊行

Posted on 10月 3, 2024 by Takaaki Naganoya

電子書籍新刊「Pages+AppleScriptで本をつくろう!」を刊行しました。全370ページ、サンプルAppleScriptアーカイブつき。
→ 販売ページ

本書は、Appleのかんたんワープロ「Pages」の使い方を「本づくり」という観点からわかりやすくまとめたものです。

本という「お約束の塊」について、それぞれの部品をどのように作っているか、実例にもとづいてご紹介しています。本書を作ったときのPages書類を含め、用例をオマケとして添付しています。

Pagesはシンプルで強力な機能を備えていますが、シンプルであるがゆえに手間が増えてしまうケースがままあります。

これに対して、macOSのスクリプト言語である「AppleScript」を利用することで、手間のかかる作業を省ける構造になっています。

本書では、筆者がPagesを使って本を作るなかで、「どうしてもこれが必要」と感じた内容をまとめたAppleScriptを付録としてご提供しています。

本書をお買い求めいただくことで、どなたも同じ道具を使って手軽に電子書籍コンテンツを作る環境とノウハウを得られる、と自負するものです。

目次

準備編

1章

電子書籍の筆者になろう!

2章

本を作るために、Pagesになれよう!
Pagesで作る「本」とは?
Pagesのツールバー設定
Pagesの参考書
AppleScriptでパワーアップ

3章

Pagesの基本操作
テキスト
表
写真
図形
欄外の表記

実践編

4章

「本」を作る作業に慣れよう!
本を作る「作業」の流れ
Pages、4つのオキテ
PDF書き出し
Skim PDF Viewerの使い方

5章

本の部品を作る作業に慣れよう!
表紙
記事一覧でもある「目次」
読者へのあいさつ「まえがき」
仁義のための登録商標表記
記事本文ページ
記事を区切る「章トビラ」
本の名刺「奥付」
本の余韻を生む「裏表紙」
ページの左右を調整する「空白」

6章

Pagesのレイアウトに翻訳

7章

本は「顔」(表紙)が命
応用編

8章

頒布/配布方法を選ぼう

9章

作成した電子書籍を各種Book Storeへ
電子書籍をクリエーター天国のBOOTHで販売
電子書籍をAmazon Kindleで販売!
各電子書籍ストアの「検閲」

10章

Mac App Storeから取得
ユーザー辞書の作り方
表情豊かな、フォントをそろえよう!
フリーで利用できるイラスト/画像素材を活用しよう!
本の構造を知ろう!
プリンタで両面印刷してホチキス製本
コンビニのコピー機で出力してホチキス製本
付録AppleScriptについて
①PDF書き出し+結合
②ツメ操作
③パーソナル面付け
④PDFへのTOC追加
⑤テキストボックス操作
⑥表の列幅、行高さ調整
⑦フォント情報収集
⑧ファイル名(章)修正
⑨ファイル名(仮想ノンブル)修正
⑩PDF操作
筆者が刊行した電子書籍の仕様
Pagesのバージョン履歴

Posted in Books news | Tagged 13.0savvy 14.0savvy 15.0savvy Pages | Leave a comment

有害ではなくなっていたSpaces

Posted on 9月 30, 2024 by Takaaki Naganoya

Spacesは、macOS標準搭載の仮想デスクトップ機能であり、最大16個の仮想デスクトップを作れるようになっているほか、F3キーを押すと縮小表示を行うようになっているなど、ハード/ソフトともによく統合された機能です。

ただし、AppleScriptユーザー側からすると

「他の仮想デスクトップにアプリのウィンドウを置くとAppleScriptからアクセスできないカス機能」
「開発チームが他の機能のことを考慮していないクズ機能」

といった感想になります。

このため、さまざまな書籍で「AppleScriptとの互換性のない機能」のひとつとしてリストアップされ、AppleScript系の開発/運用現場では「安全のためにSpacesを使わないように」と注意するのが真っ先に行う恒例行事になっていました。

内蔵HDD/SSDの暗号化機能なみに、登場時にAppleScriptとの互換性検証が不十分なものについては「信用できない」として、以来、安全のために暗号化機能は極力使わないようにしてきました。

# HDDの暗号化機能が登場したときに、暗号化したHDDにAppleScriptからアクセスできないというバカみたいな不具合が発生。その後も、有効にするとeGPUが使えなくなるなど、この機能を作っている担当者だかチームのことが信じられません。

そして話はSpacesに戻ります。執筆中の電子書籍「Pages+AppleScriptで本をつくろう!」の注意点でSpacesについて言及し、確認のために「やっぱり今でも動かないのか?」と、試してみたら……他の仮想デスクトップ上に配置したPagesの書類の情報を取得できます。

「…………。」

何度試してみても、他の仮想デスクトップに配置したPages書類の情報を取得できます。

macOS 13.7.1と、macOS 10.13.7で試してみたところ、両方で動作しました。

このぐらいの範囲のmacOSで動くのであれば、さまざまな本でSpacesに関する「危険なので使用を推奨しない」という評価は取り下げる必要があることでしょう。

ただ、Pagesについては表示中のページから+6ページぐらいを超えるとオブジェクトのposition属性を取得できないといった不具合があり、これはmacOS 15で再テストしても発生が確認されています。

Posted in Bug news | Tagged 10.13savvy 15.0savvy Spaces | Leave a comment

Safari v18のtabのpidを取得

Posted on 9月 21, 2024 by Takaaki Naganoya

新たにリリースされたSafari v18(macOS 13/14/15用)で、各Tabに「pid」属性が新設されました。

各Webコンテンツのブラウズを行う処理プロセスを、独立したプロセスで行うことで、メモリの食いすぎでプロセスが止まったような場合にでも他のWebブラウジングに影響を与えない、というあたりにメリットがあったとか。


▲Safari v17とv18のAppleScript用語辞書(sdef)を比較したところ


▲SafariでYouTube上のムービーを再生しているところ


▲アクティビティモニタ上で該当するpidのプロセスを確認

pidがわかると、どういう「いいこと」があるのかが問題です。メモリの使用状況などを確認することはできますし、個別にプロセスをkillすることもできるわけですが、そこまでやるんだろうかと。そういうニーズがあって新設したのか、ちょっとわからないところです。

それはともかく、Safari(≒WebKit)系はゴミプロセスがメモリ上に残りまくるので(Mail.appもメッセージを表示するだけでゴミプロセスが残るし)、その点がちょっとどうなのかという点と、Webコンテンツ上の画像ボタンを文字認識しておかしな動作をしまくるので、そのあたりは勘弁してほしいところです。

AppleScript名:Safariのtabのpidを取得.scpt
tell application "Safari"
  tell window 1
    set aList to pid of every tab
    
–> {33892}
  end tell
end tell

★Click Here to Open This Script 

Posted in news Object control | Tagged 13.0savvy 14.0savvy 15.0savvy Safari | Leave a comment

iWork Appsがv14.2にアップデート

Posted on 9月 20, 2024 by Takaaki Naganoya

iWork Apps(Keynote、Pages、Numbers)がバージョン14.2にアップデートしました。

すべてのアプリでAppleScript用語辞書への変更はありません。

Keynote 14.2では、macOS 15, Sequoia上でHDRコンテンツの表示をサポートしています。

バグの修正がうたわれていますが、Pagesのページ上のオブジェクトの情報を取得できる範囲が現在表示中の見開き+6ページに制限されるというアホな仕様は変わっていないことを確認しています。

Posted in news | Tagged Keynote Numbers Pages | Leave a comment

Post navigation

  • Older posts
  • Newer posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AppleScriptによる並列処理
  • macOS 15でも変化したText to Speech環境
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • 【続報】macOS 15.5で特定ファイル名パターンのfileをaliasにcastすると100%クラッシュするバグ
  • Script Debuggerの開発と販売が2025年に終了
  • macOS 15 リモートApple Eventsにバグ?
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • NSObjectのクラス名を取得 v2.1
  • macOS 15:スクリプトエディタのAppleScript用語辞書を確認できない
  • 有害ではなくなっていたSpaces
  • AVSpeechSynthesizerで読み上げテスト

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (197) 14.0savvy (150) 15.0savvy (139) CotEditor (66) Finder (51) Keynote (119) 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 (76) Pages (55) Pixelmator Pro (20) 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
  • date
  • 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
  • process
  • 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年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 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