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

カテゴリー: System

Frameworkを任意のパスからloadして実行するじっけん

Posted on 1月 29 by Takaaki Naganoya

オープンソースのCocoa Frameworkをgithubなどからダウンロードしてビルドし、AppleScriptから実行することは日常的に行なっています。

ただし、これはmacOS 10.14で~/Library/Frameworksから読み込んで実行することが、スクリプトエディタ上では禁止、Script Debuggerでのみ可能という状況です。

macOS標準添付のFrameworkの多くは、/System/Library/Frameworks以下に(若干の例外はあれど)配置されていることが期待されます。

スクリプトエディタ上で実行するScriptについては、macOSデフォルトインストールされているAppleのFrameworkしか呼び出せない状況です。

そこで、/Library/Frameworksあたりに入れたFrameworkを強制的に呼び出せないかと実験してみたものが、これです。

choose fileで指定したFrameworkを強制的に読み込んで実行するテストを行なってみました。結果からいえば、Script Debugger上では実行できるのですが、スクリプトエディタではloadが行えず、エラーになりました。

結論:残念!

もともと、ホームディレクトリ以下のバイナリを呼び出すことをSIPで禁止したいというセキュリティ上のポリシーによって、macOS 10.14以降ではmacOS標準装備のスクリプトエディタが影響を受けました。

Script Debuggerでこの点は補われていたわけですが、AppleScriptから/Library/FrameworkにインストールしたFrameworkを呼び出すことを許可していただきたいところです。/Library/Frameworkなら、ホームディレクトリ以下ではないし、管理者権限がないとFrameworkのインストールもできないため、サードパーティのFrameworkのインストール先としては妥当です。何らかの悪意をもったソフトウェアがFrameworkを勝手にインストールする危険性も低いことでしょう。

AppleScript名:Framerokを任意のパスからloadして実行するじっけん.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2025/01/29
—
–  Copyright © 2025 Piyomaru Software, All Rights Reserved
—

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

set fPath to POSIX path of (choose file)

loadAndExecuteFramework(fPath, "SFPSDWriter") of me

on loadAndExecuteFramework(frameworkPath, functionName)
  — Frameworkのパスをチェック
  
(*
  if frameworkPath does not start with "/Library/" then
    display dialog "Error: Framework path must be inside /Library/"
    return
  end if
  *)

  
  
— Frameworkをロード
  
set frameworkNSURL to current application’s NSURL’s fileURLWithPath:frameworkPath
  
set bundle to current application’s NSBundle’s bundleWithURL:frameworkNSURL
  
  
if bundle is missing value then
    display dialog "Error: Failed to load framework at " & frameworkPath
    
return
  end if
  
  
— Frameworkのクラスをロード
  
set isLoaded to bundle’s load()
  
if isLoaded is false then
    display dialog "Error: Failed to load framework"
    
return
  end if
  
  
— クラスを取得
  
set className to current application’s NSClassFromString(functionName)
  
if className is missing value then
    display dialog "Error: Function ’" & functionName & "’ not found"
    
return
  end if
  
  
log className
  
  
— メソッドを実行(クラスメソッドとして想定)
  
try
    className’s performSelector:"execute"
    
display dialog "Function ’" & functionName & "’ executed successfully."
  on error errMsg
    display dialog "Error executing function: " & errMsg
  end try
end loadAndExecuteFramework

★Click Here to Open This Script 

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

Bluetoothに接続中のデバイス名を取得するv6

Posted on 12月 13, 2024 by Takaaki Naganoya

3年ぐらい前に書いてあった、Mac本体にペアリングして接続しているBluetoothのデバイス名を取得するAppleScriptです。

AppleScript名:Bluetoothに接続中のデバイス名を取得するv6.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/12/13
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

set pRes to getBluetoothPowerState() of me
if pRes = false then return

set dArray to current application’s IOBluetoothDevice’s pairedDevices()
set dRes to my filterRecListByLabel1(dArray, "isConnected != 0")
set dNameList to (dRes’s valueForKeyPath:"name") as list
–> {"Logicool Z600", "Takaaki Naganoya のキーボード #1", "Takaaki Naganoya のマウス"}
–> {"Logicool Z600", "AirPods Pro", "DUALSHOCK 4 Wireless Controller"}

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

–Mac本体のBluetoothのパワー状態を取得
on getBluetoothPowerState()
  set aCon to current application’s IOBluetoothHostController’s alloc()’s init()
  
set pRes to (aCon’s powerState()) as boolean
end getBluetoothPowerState

★Click Here to Open This Script 

Posted in Bluetooth System | Tagged 13.0savvy 14.0savvy 15.0savvy | Leave a comment

各Framework内のbridgesupportファイル情報の収集

Posted on 11月 29, 2024 by Takaaki Naganoya

macOS内の標準装備のFrameworkの情報を収集するAppleScriptです。AppleScriptからmacOS内のFrameworkを呼ぶには、Framework内にbridgesupportファイルが存在している必要があります。

これまで、さまざまな資料を作成するさいに、Frameworkの有無だけをまとめてきましたが……結局のところ、bridgesupportファイルの有無を調査しないと意味がないのでは? ということで書いてみたものです。

結果は、Framework名、x86版の有無、ARM64E版の有無がCSVファイルで出力されます。

AppleScript名:各Framework内のbridgesupportファイル情報の収集_v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/11/29
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

use AppleScript
use framework "Foundation"
use scripting additions

script spd
  property a1Res : {}
  
property a2Res : {}
  
property a3Res : {}
  
property allList : {}
  
property fNames : {}
end script

set outPath to POSIX path of (choose file name with prompt "Input file name (with \".csv\")")

–Frameworkフォルダ1から取得
set frPath to "/System/Library/Frameworks/"
set s1Text to "find " & frPath & " -name *.framework"
set (a1Res of spd) to paragraphs of (do shell script s1Text)

set osV to my numToHex((system attribute "sysv"), 4)

if osV ≥ "1200" then
  –Frameworkフォルダ2から取得
  
set frPath to "/System/DriverKit/System/Library/Frameworks"
  
set s1Text to "find " & frPath & " -name *.framework"
  
set (a2Res of spd) to paragraphs of (do shell script s1Text)
  
  
–合成
  
set (a3Res of spd) to (a1Res of spd) & (a2Res of spd)
else
  copy (a1Res of spd) to (a3Res of spd)
end if

–合成して重複を除去
set aRes to uniquify1DList((a3Res of spd)) of me

–フレームワークでループして、bridgesupportファイルをx64とApple Silicon版を検索
set (fNames of spd) to {}
repeat with i in aRes
  set t1Path to (current application’s NSString’s stringWithString:(i))
  
set t2Path to t1Path’s stringByResolvingSymlinksInPath() –リンクを解消
  
set tName to t2Path’s lastPathComponent()’s stringByDeletingPathExtension() as string
  
  
–Find x64 bridgesupport
  
set s1Text to "find " & t2Path & " -name " & tName & ".bridgesupport"
  
try
    set a1Res to do shell script s1Text
  on error
    set a1Res to ""
  end try
  
  
–Find Apple Silicon (ARM64E) bridgesupport
  
set s2Text to "find " & t2Path & " -name " & tName & ".arm64e.bridgesupport"
  
try
    set a2Res to do shell script s2Text
  on error
    set a2Res to ""
  end try
  
  
–Check result of x64 bridgesupport  
  
set ttList to {tName}
  
if a1Res is not equal to "" then
    set the end of ttList to "●"
  else
    set the end of ttList to ""
  end if
  
  
–Check result of Apple Silicon (ARM64E) bridgesupport   
  
if a2Res is not equal to "" then
    set the end of ttList to "●"
  else
    set the end of ttList to ""
  end if
  
  
–Store Results
  
if tName is not in (fNames of spd) then –重複出力を防ぐ
    set the end of (allList of spd) to ttList
    
set the end of (fNames of spd) to tName
  end if
end repeat

–結果のCSV書き出し
set sRes to saveAsCSV((allList of spd), outPath) of me

on numToHex(theNumber, stringLength)
  set hexString to {}
  
repeat with i from stringLength to 1 by -1
    set hexString to ((theNumber mod 16) as string) & hexString
    
set theNumber to theNumber div 16
  end repeat
  
return (hexString as string)
end numToHex

on getFileSizeFromPath(aPath)
  set aaPath to current application’s NSString’s stringWithString:(aPath)
  
set aaaPath to aaPath’s stringByResolvingSymlinksInPath() –リンクを解消
  
set aFM to current application’s NSFileManager’s defaultManager()
  
set anAttr to aFM’s attributesOfItemAtPath:(aaaPath) |error|:(missing value)
  
set sRes to anAttr’s fileSize()
  
return sRes as string
end getFileSizeFromPath

–文字置換
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

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

on writeToFileAsUTF8(aStr, aPath)
  set cStr to current application’s NSString’s stringWithString:aStr
  
set thePath to POSIX path of aPath
  
set aRes to cStr’s writeToFile:thePath atomically:false encoding:(current application’s NSUTF8StringEncoding) |error|:(missing value)
  
return aRes as boolean
end writeToFileAsUTF8

on uniquify1DList(theList as list)
  set theSet to current application’s NSOrderedSet’s orderedSetWithArray:theList
  
return (theSet’s array()) as list
end uniquify1DList

★Click Here to Open This Script 

Posted in System | Tagged 12.0savvy 13.0savvy 14.0savvy 15.0savvy | Leave a comment

ステージマネージャのON_OFF

Posted on 11月 15, 2024 by Takaaki Naganoya

macOS 13で搭載された「ステージマネージャ」機能のオン/オフを行うAppleScriptです。

ステージマネージャは、最前面のアプリのウィンドウだけを表示するようにする仕組みで、iPadOSに搭載されたものがそのままmacOSにも搭載されました。ドラッグ&ドロップをこのステージマネージャに対して行えるのと、表示ウィンドウを最前面のものだけに切り替えるものです。

つまり、マルチウィンドウのGUIに不慣れなユーザーのために用意された機能です。Windowsユーザー向けに用意した、ともいえるでしょう。

このステージマネージャのOn/Offを行います。動作内容はご覧のとおり、単にshellコマンドを呼び出しているだけです。現在オンになっているかどうかも、defaults readコマンドで同様に実行できることでしょう。


▲真っ先にオフにして、二度とオンにすることはなかったステージマネージャ(画面左端)


▲元に戻ると安心します

AppleScript名:ステージマネージャのON_OFF
—
–  Created by: Takaaki Naganoya
–  Created on: 2024/11/15
—
–  Copyright © 2024 Piyomaru Software, All Rights Reserved
—

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

set aBool to true
stageManagerControl(aBool) of me

delay 5

set aBool to false
stageManagerControl(aBool) of me

on stageManagerControl(aBool as boolean)
  set sText to "defaults write com.apple.WindowManager GloballyEnabled -bool " & (aBool as string)
  
do shell script sText
end stageManagerControl

★Click Here to Open This Script 

Posted in shell script System | Tagged 13.0savvy 14.0savvy 15.0savvy | 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

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

macOS 14で変更になったOSバージョン取得APIの返り値

Posted on 8月 24, 2024 by Takaaki Naganoya

macOSのバージョンを求める機能については、かならず複数の方法で取得できるように調査しています。

それは、Appleがバグを作る可能性が一番高い機能だからです(なんで懲りないんだろ?)。

OSバージョンを求めるのに、

・AppleScriptの標準装備コマンド「system info」で求める
–> {AppleScript version:”2.8″, AppleScript Studio version:”1.5.3″, system version:”13.6.9″, short user name:”XXXX”, long user name:”XXXXX XXXXX”, user ID:504, user locale:”ja_JP”, home directory:alias “Macintosh HD:Users:XXXX:”, boot volume:”Macintosh HD:”, computer name:”M1 mini”, host name:”m1mini.local”, IPv4 address:”192.168.0.99″, primary Ethernet address:”99:99:99:99:ZZ:99″, CPU type:”ARM64E”, CPU speed:missing value, physical memory:16384}

・AppleScriptの環境プロパティ「system attribute」を求める
set v1 to system attribute “sys1” –> 10
set v2 to system attribute “sys2” –> 4
set v3 to system attribute “sys3” –> 11

・shell commandで求める
–> sw_vers
–> sw_vers -productVersion

などに加えて、NSProcessInfos processInfo()’s operatingSystemVersion() を呼び出すという方法も加わりました。

ただ、これが最近おかしな挙動をするようになったのに気づいていろいろ調査してみたら、macOS 14になって返り値のフォーマットを変えたことが判明しました。ラベルつきの値(NSDictionary)で返してきたのが、ラベルなしの配列(NSArray)で返すように変わっています。macOS 10.13で座標系のデータをラベルなしで返すように変更してきたのと同様の変更が加えられています。

macOS 14.xの初期バージョンでは従来タイプの値を返してきたように記憶していますが、いつ変更したのやら。

AppleScript名:OSバージョンを求める.scpt
use AppleScript
use framework "Foundation"
use scripting additions

set pInfo to (current application’s NSProcessInfo’s processInfo()’s operatingSystemVersion())
–> {majorVersion:10, minorVersion:14, patchVersion:6}–10.14
–> {majorVersion:13, minorVersion:6, patchVersion:9}–13.6.9
–> {14, 6, 1}–14.6.1
–> {15, 1, 0}–15.0.1

★Click Here to Open This Script 

こういう基本的な情報を提供するAPIの仕様を変更することに、どういうインセンティブがあるのか不明です。変える価値があると判断したから変えたんでしょう。自分にはどういう理由なのか、さっぱり分かりません。

安全のためには、AppleScriptのビルトイン機能を使うか、OS内のplistを読み取って自分で処理するとかいった「対策」が必要なのでしょう。

Posted in System | Tagged 14.0savvy 15.0savvy | Leave a comment

ディスプレイをスリープ状態にして処理続行

Posted on 12月 3, 2023 by Takaaki Naganoya

特定のディスプレイのみ消灯して処理続行、という処理を行なってみたかったのですが、いろいろ調べた結果、すべてのディスプレイを消灯する方法しか見つかりませんでした。

それでも、寝る前に電子書籍1冊分のデータをPDFにすべて書き出して連結する、といったAppleScriptを実行するのに、ディスプレイをあらかじめスリープ状態にしたあとで、処理終了後にコンピュータごとsleepにしてもよさそうです。

1000ページ分の電子書籍のPages書類をすべてPDFに書き出して、ファイル名順に連結してもM1 Mac miniで7分ぐらいで処理できるので、この程度の処理だとディスプレイを消して処理する意義はそれほどないのかもしれませんけれども。

AppleScript名:ディスプレイをスリープ状態にして処理続行.scpt
do shell script "pmset displaysleepnow"
beep 10

★Click Here to Open This Script 

Posted in shell script System | Leave a comment

macOS 13 TTS環境の変化について

Posted on 11月 22, 2023 by Takaaki Naganoya

正確にいえばmacOS 12あたりから大幅に変わっていて、忙しさにかまけて詳細な調査は行なってこなかったのですが……必要に迫られていろいろ調べてみました(Piyomaru Context Menu Assistant関連で)。

変更点1:TTS Voiceから年齢(Age)という属性値が削除された

変更点2:TTS Voiceの名前(Name)という属性値がローカライズされて返るようになった

変更点3:AppleScriptのsayコマンドにTTS Voiceの名前(Name)を設定するとエラーになるものが多数出てきた

変更点4:TTS Voice低音質キャラクタと高音質キャラクタ(Premium、Enhanced)があった場合に、AppleScriptのsayコマンドで低音質キャラクタが指定されるようになった。高音質キャラクタ(Premium、Enhanced)を明示的に指定する方法はない(sayコマンドでは不可能。AVSpeechSynthesizerを呼び出して読み上げるのは可能)

変更点5:AppleScriptのsayコマンドでSiriボイスを指定できないが、システムのデフォルト読み上げ設定にSiri音声を指定していると、sayコマンドでTTSボイス無指定(システムのデフォルト設定ボイスを使用)でSiri音声で読み上げられる

変更点1は、ポリコレの一環なんでしょうか。別に機械音声なので「年齢を基準に処理するな」とかいう不満は誰も抱かないと思います。これを決定した責任者は、頭がおかしいです。

変更点2は、NameのほかにLocalizedNameとかいった属性値を持たせるべきだったんじゃないでしょうか。経験の足りないエンジニアがとりあえずやっつけで仕事をしてしまったように見えます。これを決めた責任者は頭がおかしいです。バカと言って差し支えないでしょう。

変更点3は、けっこう困ります。AppleScriptのデフォルトコマンドには、TTS Voiceキャラクタ名の一覧を取得する、といった命令が存在せず、なんとなく「システム環境設定に出てくる名前を指定して使ってね」といった無責任な状況になっていました。昔からあるTTS VoiceのうちBells、Hysterical、Organ、Princess、Trinoids、Whisperを指定してもエラーになります(OS内に存在しているのに)。これは、OSの内部が壊れているものと判断しています。いい加減にしてほしいです。

変更点4は、Apple社内がえらく混乱しているように見えます。ちゃんと状況を整理していないような、開発現場のカオスな状況しか感じません。エンジニアの人数はさほど増やしていないのに、OSの数を野放図に増やしすぎです。これは、そういう管理をしている管理職の頭がおかしいです。

変更点5は、おそらくApple側が意図していない動作だと思われますが、「いまだとsayコマンドでAppleScriptからSiriの音声が指定し放題」であるということです。sayコマンドでは音声の指定を行わないと、OSデフォルトの音声キャラクタが指定されます。このデフォルト音声をSiriの音声にしておいて、キャラクタ無指定でsayコマンドを実行すると、Siriの音声キャラクタで発声が行われます。

sayコマンドで指定できるということは、音声ファイルにレンダリング可能だということで、Appleがキャラクタ提供元とそういうライセンス契約をしているのであればよいのですが、バグによって意図しない使われ方をしてしまう可能性があるわけです。ただ、このような状況を作った責任はAppleにあるものであって、ユーザーにはありません。

–> Play TTS by Siri demo

追跡調査を行なってみたところ、shell commandの/usr/bin/sayは、これらの、AppleScriptのsayコマンドではエラーになるText To Speechキャラクタ「Bells」も問題なく指定できました。

Posted in Bug Text to Speech | Tagged 13.0savvy | Leave a comment

macOS 14の変更がmacOS 13にも反映

Posted on 9月 21, 2023 by Takaaki Naganoya

macOS 14RCをさわって「システム設定」をAppleScriptから操作し、目的のPaneをIDで指定して表示できることを確認しました。

macOS 13に戻ってきて資料を作成(macOS 14を信用していないので)。「macOS 13でも動いてみたりして?」と、冗談半分にmacOS 14用のScriptを走らせたら……動いてしまいました。

各PaneのIDやnameを取得でき、指定IDのPaneを表示でき、現在表示中のPaneの情報を取得できます。

厳密に「いつから」この状態になっていたのかは不明ですが、macOS 13.5あたりでしょうか? 自分の環境はmacOS 13.6betaなので、13.5/13.5.1の状況は確認のしようがありませんが、OSのマイナーバージョンアップ時にこうしたまともな改修を行うなんて、前代未聞です。よほど、全世界的に文句を言われたのでしょう。

name ID
(ユーザーの名前) com.apple.systempreferences.AppleIDSettings*AppleIDSettings
ファミリー com.apple.Family-Settings.extension*Family
Wi‑Fi com.apple.wifi-settings-extension
Bluetooth com.apple.BluetoothSettings
ネットワーク com.apple.Network-Settings.extension
VPN com.apple.NetworkExtensionSettingsUI.NESettingsUIExtension
通知 com.apple.Notifications-Settings.extension
サウンド com.apple.Sound-Settings.extension
集中モード com.apple.Focus-Settings.extension
スクリーンタイム com.apple.Screen-Time-Settings.extension
一般 com.apple.systempreferences.GeneralSettings
外観 com.apple.Appearance-Settings.extension
アクセシビリティ com.apple.Accessibility-Settings.extension
コントロールセンター com.apple.ControlCenter-Settings.extension
SiriとSpotlight com.apple.Siri-Settings.extension
プライバシーとセキュリティ com.apple.settings.PrivacySecurity.extension
デスクトップとDock com.apple.Desktop-Settings.extension
ディスプレイ com.apple.Displays-Settings.extension
壁紙 com.apple.Wallpaper-Settings.extension
スクリーンセーバ com.apple.ScreenSaver-Settings.extension
省エネルギー com.apple.Battery-Settings.extension*EnergySaverPreferences
ロック画面 com.apple.Lock-Screen-Settings.extension
ログインパスワード com.apple.Touch-ID-Settings.extension*TouchIDPasswordPrefs
ユーザとグループ com.apple.Users-Groups-Settings.extension
パスワード com.apple.Passwords-Settings.extension
インターネットアカウント com.apple.Internet-Accounts-Settings.extension
Game Center com.apple.Game-Center-Settings.extension
キーボード com.apple.Keyboard-Settings.extension
マウス com.apple.Mouse-Settings.extension
ゲームコントローラ com.apple.Game-Controller-Settings.extension
プリンタとスキャナ com.apple.Print-Scan-Settings.extension
AppleScript名:すべてのPaneの情報を取得.scpt
tell application "System Settings"
  set aList to properties of every pane
  
–> {{class:pane, name:"外観", id:"com.apple.Appearance-Settings.extension"}, {class:pane, name:"ロック画面", id:"com.apple.Lock-Screen-Settings.extension"}, {class:pane, name:"キーボード", id:"com.apple.Keyboard-Settings.extension"}, {class:pane, name:"ファミリー", id:"com.apple.Family-Settings.extension*Family"}, {class:pane, name:"Wi‑Fi", id:"com.apple.wifi-settings-extension"}, {class:pane, name:"デスクトップとDock", id:"com.apple.Desktop-Settings.extension"}, {class:pane, name:"Bluetooth", id:"com.apple.BluetoothSettings"}, {class:pane, name:"壁紙", id:"com.apple.Wallpaper-Settings.extension"}, {class:pane, name:"SiriとSpotlight", id:"com.apple.Siri-Settings.extension"}, {class:pane, name:"マウス", id:"com.apple.Mouse-Settings.extension"}, {class:pane, name:"プライバシーとセキュリティ", id:"com.apple.settings.PrivacySecurity.extension"}, {class:pane, name:"機能拡張", id:"com.apple.ExtensionsPreferences"}, {class:pane, name:"プロファイル", id:"com.apple.Profiles-Settings.extension"}, {class:pane, name:"省エネルギー", id:"com.apple.Battery-Settings.extension*EnergySaverPreferences"}, {class:pane, name:"一般", id:"com.apple.systempreferences.GeneralSettings"}, {class:pane, name:"情報", id:"com.apple.SystemProfiler.AboutExtension"}, {class:pane, name:"ソフトウェアアップデート", id:"com.apple.Software-Update-Settings.extension"}, {class:pane, name:"ストレージ", id:"com.apple.settings.Storage"}, {class:pane, name:"AirDropとHandoff", id:"com.apple.AirDrop-Handoff-Settings.extension"}, {class:pane, name:"ログイン項目", id:"com.apple.LoginItems-Settings.extension"}, {class:pane, name:"言語と地域", id:"com.apple.Localization-Settings.extension"}, {class:pane, name:"日付と時刻", id:"com.apple.Date-Time-Settings.extension"}, {class:pane, name:"共有", id:"com.apple.Sharing-Settings.extension"}, {class:pane, name:"Time Machine", id:"com.apple.Time-Machine-Settings.extension"}, {class:pane, name:"転送またはリセット", id:"com.apple.Transfer-Reset-Settings.extension"}, {class:pane, name:"起動ディスク", id:"com.apple.Startup-Disk-Settings.extension"}, {class:pane, name:"集中モード", id:"com.apple.Focus-Settings.extension"}, {class:pane, name:"ゲームコントローラ", id:"com.apple.Game-Controller-Settings.extension"}, {class:pane, name:"スクリーンタイム", id:"com.apple.Screen-Time-Settings.extension"}, {class:pane, name:"長野谷隆昌", id:"com.apple.systempreferences.AppleIDSettings*AppleIDSettings"}, {class:pane, name:"VPN", id:"com.apple.NetworkExtensionSettingsUI.NESettingsUIExtension"}, {class:pane, name:"ディスプレイ", id:"com.apple.Displays-Settings.extension"}, {class:pane, name:"プリンタとスキャナ", id:"com.apple.Print-Scan-Settings.extension"}, {class:pane, name:"Game Center", id:"com.apple.Game-Center-Settings.extension"}, {class:pane, name:"インターネットアカウント", id:"com.apple.Internet-Accounts-Settings.extension"}, {class:pane, name:"コントロールセンター", id:"com.apple.ControlCenter-Settings.extension"}, {class:pane, name:"ネットワーク", id:"com.apple.Network-Settings.extension"}, {class:pane, name:"スクリーンセーバ", id:"com.apple.ScreenSaver-Settings.extension"}, {class:pane, name:"アクセシビリティ", id:"com.apple.Accessibility-Settings.extension"}, {class:pane, name:"サウンド", id:"com.apple.Sound-Settings.extension"}, {class:pane, name:"ユーザとグループ", id:"com.apple.Users-Groups-Settings.extension"}, {class:pane, name:"パスワード", id:"com.apple.Passwords-Settings.extension"}, {class:pane, name:"通知", id:"com.apple.Notifications-Settings.extension"}, {class:pane, name:"ログインパスワード", id:"com.apple.Touch-ID-Settings.extension*TouchIDPasswordPrefs"}, {class:pane, name:"SwiftDefaultApps", id:"cl.fail.lordkamina.SwiftDefaultApps"}, {class:pane, name:"SwitchResX", id:"fr.madrau.switchresx.prefpane"}}
end tell

★Click Here to Open This Script 

AppleScript名:現在表示中のPaneの情報を取得.scpt
tell application "System Settings"
  set aList to properties of current pane
  
–> {class:pane, name:"外観", id:"com.apple.Appearance-Settings.extension"}
end tell

★Click Here to Open This Script 

AppleScript名:WiFiのPaneを表示.scpt
tell application "System Settings"
  reveal pane id "com.apple.wifi-settings-extension"
end tell

★Click Here to Open This Script 

Posted in news System | Tagged 13.0savvy 14.0 System Settings | 1 Comment

指定のアプリケーションの実行アーキテクチャを変更

Posted on 5月 3, 2023 by Takaaki Naganoya

指定のアプリケーションの実行アーキテクチャを変更するAppleScriptです。

–> Download setArchLib.scptd

Apple Silicon Mac上でアプリケーションをRosetta 2によってIntel 64バイナリのARMエミュレーション動作を行うかどうかは、Finder上の「Rosettaを利用して開く」のチェックボックスによって制御されています。

これを、外側(FinderのGUI)から操作するか、内側(何らかのOS内のサービスやメタデータ)から操作するかによって、その「やりかた」は大きく異なります。

自分は、できることなら極力GUI Scriptingを使いたくない派なので、「そういえばASからこのあたりの設定をいじくった記憶がない」と思いつつ、「内側から操作する方法はないものか」と考えていました。

さっそくGithub上でいろいろ調査してみたところ、LaunchServiceのプライベートAPIに「_LSSetArchitecturePreferenceForApplicationURL」というものがあって、これを呼ぶことで処理を実現できそうだということが判明。

処理内容は、アゴが外れそうなほど簡単なので、AppleScript(AppleScriptObjC)でも普通に書けそうな勢いでしたが、アンダースコアで始まるAPIはAppleScriptにBridgeしにくく、もともとのプロジェクトのもの(UNIXのコマンドラインから呼び出す「SetArchPrefForURL」プロジェクト)をビルドしたバイナリをScriptバンドル内に入れて、呼び出すようにしてみました。

Cocoa Frameworkのプロジェクトを作成して、AppleScriptから普通にPOSIX pathとCPUアーキテクチャを渡せば結果をbooleanで返してくるようなスタイルに書き換えようとして、途中で頓挫してしまいました。そんなに気合いを入れる内容でもないので、こんなものでいいんでしょう。

AppleScript名:setArchLib.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2023/05/03
—
–  Copyright © 2023 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4" — Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set appPath to choose file of type {"com.apple.application-bundle"}
–set archStr to "x86_64"
set archStr to "arm64"

set archRes to setArchForApp(appPath, archStr as string) of me

on setArchForApp(appPath, archStr as string)
  if archStr is not in {"x86_64", "arm64"} then error "Invalid architecture"
  
  
set exePath to POSIX path of (path to resource "SetArchPrefForURL")
  
set sRes to do shell script (quoted form of exePath) & " " & (quoted form of POSIX path of appPath) & " " & archStr
  
return (sRes = "") as boolean
end setArchForApp

★Click Here to Open This Script 

Posted in file System | Tagged 11.0savvy 12.0savvy 13.0savvy | Leave a comment

macOS 13 TTS Voice環境に変更

Posted on 11月 12, 2022 by Takaaki Naganoya

macOS 13でTTS(Text To Speech)キャラクタが追加され、日本語環境では各種読み上げ機能で「O-Ren」(女性)と「Hattori」(男性)というSiriの音声が使えるようになりました。

macOS 13の「システム設定」(System Settings.app)の「アクセシビリティ」>「読み上げコンテンツ」で、「システムの声」(TTS読み上げキャラクタ)を選択、追加できるわけですが……

ただし、AppleScriptのsayコマンド(音声読み上げ、音声ファイルへのレンダリング)で、「Hattori」「O-Ren」が使えるというわけではありません。逆に、OSのサービス経由で音声名称を取得すると、

{"Kyoko", "Kyoko(拡張)", "Otoya", "Otoya(拡張)"}

などと結果が返ってくるものの、”Kyoko(拡張)”, “Otoya(拡張)”をsayコマンドで指定するとエラーになります。

say "こんにちは" using "Kyoko(拡張)"
--> AppleScript Execution Error
AppleScript名:TTS Voiceを言語で抽出.scpt
— Created 2017-03-28 by Takaaki Naganoya
— 2017 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set aLoc to (current application’s NSLocale’s currentLocale()’s identifier()) as string
–>  "ja_JP"

set vList to getTTSVoiceNameWithLanguage(aLoc) of me
–>  {"Kyoko", "Otoya"}–macOS 12まで
–>  {"Kyoko", "Kyoko(拡張)", "Otoya", "Otoya(拡張)"}–macOS 13

on getTTSVoiceNameWithLanguage(voiceLang)
  set outArray to current application’s NSMutableArray’s new()
  
  
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_("VoiceLocaleIdentifier == %@", voiceLang)
  
set filteredArray to outArray’s filteredArrayUsingPredicate:aPredicate
  
set aResList to (filteredArray’s valueForKey:"VoiceName") as list
  
  
return aResList
end getTTSVoiceNameWithLanguage

★Click Here to Open This Script 

TTS Voiceの環境に合わせて何かこれらのTTS Voiceのファミリー名称などを返すようにしないとダメなのかも???

AppleScript名:TTS Voiceを言語で抽出 v2.scpt
— Created 2017-03-28 by Takaaki Naganoya
— Modified 2022-11-12 by Takaaki Naganoya
— 2022 Piyomaru Software
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

set aLoc to (current application’s NSLocale’s currentLocale()’s identifier()) as string
–>  "ja_JP"

set vList to getTTSVoiceNameWithLanguage(aLoc) of me
–>  {"Kyoko", "Otoya"}–macOS 12まで
–>  {"Kyoko", "Otoya"}–macOS 13

on getTTSVoiceNameWithLanguage(voiceLang)
  set outArray to current application’s NSMutableArray’s new()
  
  
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_("VoiceLocaleIdentifier == %@", voiceLang)
  
set filteredArray to outArray’s filteredArrayUsingPredicate:aPredicate
  
set aResList to (filteredArray’s valueForKey:"VoiceNameRoot") –Voice Rootを取得
  
  
–要素をユニーク化
  
set theSet to current application’s NSOrderedSet’s orderedSetWithArray:aResList
  
return (theSet’s array()) as list
end getTTSVoiceNameWithLanguage

★Click Here to Open This Script 

Posted in System Text to Speech | Tagged 13.0savvy | 3 Comments

Bundle IDで指定したアプリケーションのSDEFからコマンドを抽出テスト(指定コマンドのコマンド属性取り出し)

Posted on 8月 13, 2022 by Takaaki Naganoya

アプリケーションのSDEF(AppleScript用語辞書)を解析して情報を取り出すシリーズの本命。指定コマンドの属性値を取り出すテスト用のAppleScriptです。

–> Download script with library

まだ、明確な成果が出ているわけではありませんが、こうしてアクセスして問題がないか、多くのアプリケーションの各コマンドで問題がないかを調査しているところです。

AppleScript名:Bundle IDで指定したアプリケーションのSDEFからコマンドを抽出テスト(指定コマンドのコマンド属性取り出し).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/08/2
—
–  Copyright © 2022 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 (sdefDict of myDict) to {}
set aRes to parseSdefAndRetCommandStructure("com.apple.iWork.Keynote", "export") of me

on parseSdefAndRetCommandStructure(targAppBundleID, aTargCom)
  if (sdefDict of myDict) = {} then
    set aRes to parseSDEFandRetXMLStr(targAppBundleID) of me
    
set (sdefDict of myDict) to (xmlLib’s makeRecordWithXML:aRes)
  end if
  
  
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
      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
    on error
      return false
    end try
    
  end repeat
  
return false
end parseSdefAndRetCommandStructure

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

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

–SDEFをXincludeを考慮しつつ展開
on parseSDEFandRetXMLStr(targAppBundleID)
  set thePath to POSIX path of (path to application id targAppBundleID)
  
  
set aSDEFname to retAppSdefNameFromBundleIPath(thePath, "OSAScriptingDefinition") of me
  
if aSDEFname = false then return
  
  
if aSDEFname does not end with ".sdef" then set aSDEFname to aSDEFname & ".sdef"
  
set sdefFullPath to thePath & "Contents/Resources/" & aSDEFname
  
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 parseSDEFandRetXMLStr

–指定パスからアプリケーションのInfo.plist中の属性値を返す
on retAppSdefNameFromBundleIPath(appPath as string, aKey as string)
  set aDict to (current application’s NSBundle’s bundleWithPath:appPath)’s infoDictionary()
  
set aRes to aDict’s valueForKey:(aKey)
  
if aRes = missing value then return false
  
set asRes to aRes as string
  
  
return asRes as string
end retAppSdefNameFromBundleIPath

★Click Here to Open This Script 

Posted in sdef System XML | Tagged 10.14savvy 10.15savvy 11.0savvy 12.0savvy | Leave a comment

Bundle IDで指定したアプリケーションのSDEFからXPathで指定したClassにアクセス v2

Posted on 8月 2, 2022 by Takaaki Naganoya

Bundle IDで指定したアプリケーションのSDEF(AppleScript定義辞書)を、Xincludeを考慮しつつparseして、XPathで指定したクラスにアクセスするAppleScriptです。

KeynoteのAppleScript用語辞書の「open」コマンド、

を指定して本Scriptでデータを取り出すと、

のような出力が得られます。まだちょっと、属性値を取り出すところまで行っていませんが、つまり…指定コマンドのパラメータや、指定クラスがどのようなコマンドに応答するかなど、プログラム側からわかるようになることでしょう(多分)。

AppleScript名:Bundle IDで指定したアプリケーションのSDEFからXPathで指定したClassにアクセス v2.scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/08/2
—
–  Copyright © 2022 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 targAppBundleID to "com.apple.iWork.Keynote" –SDEFを取り出すターゲットのアプリケーションのBundle ID
–set commandXPath to "//class[@name=’application’]/property"
–set commandXPath to "//command[@name=’open’]/direct-parameter"
–set commandXPath to "//class[@name=’document’]/property"
–set commandXPath to "//class[@name=’document’]/responds-to"
–set commandXPath to "//command[@name=’open’]" –Open Command–Open コマンド
set commandXPath to "//command[@name=’open’]/direct-parameter/type" –Open Command–Open コマンド

set aRes to parseSDEFandRetXPathData(targAppBundleID, commandXPath) of me
return aRes

–SDEFをXincludeを考慮しつつ展開
on parseSDEFandRetXPathData(targAppBundleID, commandXPath)
  set thePath to POSIX path of (path to application id targAppBundleID)
  
  
set aSDEFname to retAppSdefNameFromBundleIPath(thePath, "OSAScriptingDefinition") of me
  
if aSDEFname = false then return
  
  
if aSDEFname does not end with ".sdef" then set aSDEFname to aSDEFname & ".sdef"
  
set sdefFullPath to thePath & "Contents/Resources/" & aSDEFname
  
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
  
  
set dRes to my extractFrom:theXMLDoc matchingXPath:commandXPath
  
return dRes
end parseSDEFandRetXPathData

–指定のNSXMLDocumentから、指定のXPathでアクセスして内容を返す
on extractFrom:theNSXMLDocument matchingXPath:theQuery
  set attStrings to {} — where attributes will be stored
  
set theXMLOutput to current application’s NSXMLElement’s alloc()’s initWithName:"output" — found nodes added to this
  
  
set {theResults, theNSError} to (theNSXMLDocument’s nodesForXPath:theQuery |error|:(reference)) — query
  
  
if theResults is not missing value then
    repeat with anNSXMLNode in (theResults as list)
      anNSXMLNode’s detach() — need to detach first
      
if anNSXMLNode’s |kind|() as integer = current application’s NSXMLAttributeKind then — see if it’s an attribute or node
        set end of attStrings to (anNSXMLNode’s stringValue()) as {text, list, record}
      else
        (theXMLOutput’s addChild:anNSXMLNode) — add node
      end if
    end repeat
    
    
return (theXMLOutput’s XMLStringWithOptions:(current application’s NSXMLNodePrettyPrint)) as {text, list, record}
  else
    return missing value
  end if
end extractFrom:matchingXPath:

–指定パスからアプリケーションのInfo.plist中の属性値を返す
on retAppSdefNameFromBundleIPath(appPath as string, aKey as string)
  set aDict to (current application’s NSBundle’s bundleWithPath:appPath)’s infoDictionary()
  
set aRes to aDict’s valueForKey:(aKey)
  
if aRes = missing value then return false
  
set asRes to aRes as string
  
  
return asRes as string
end retAppSdefNameFromBundleIPath

★Click Here to Open This Script 

Posted in sdef System XML | Tagged 10.15savvy 11.0savvy 12.0savvy Keynote | 1 Comment

Dockに登録されている項目の情報を取得する

Posted on 7月 28, 2022 by Takaaki Naganoya

Dockの情報が取得できることは、はるかかなた昔から知っていましたが、実際に使える用途がなかったのでScriptを組んで放置状態になっていました(本Scriptのオリジナルは2008年に書いてありました)。存在を思い出したので、動作を再確認してみました。

–> {{minimum value:missing value, orientation:missing value, position:{1878, 40}, class:UI element, accessibility description:missing value, role description:”アプリケーションDock項目”, focused:missing value, title:”Finder”, size:{30, 22}, help:missing value, entire contents:{}, enabled:missing value, maximum value:missing value, role:”AXDockItem”, value:missing value, subrole:”AXApplicationDockItem”, selected:false, name:”Finder”, description:”アプリケーションDock項目”}, {minimum value:missing value, orientation:missing value, position:{1878, 62}, class:UI element, accessibility description:missing value, role description:”アプリケーションDock項目”, focused:missing value, title:”Safari”, size:{30, 22}, help:missing value, entire contents:{}, enabled:missing value, maximum value:missing value, role:”AXDockItem”, value:missing value, subrole:”AXApplicationDockItem”, selected:false, name:”Safari”, description:”アプリケーションDock項目”},…}

実行のためには、AppleScript実行プログラム(スクリプトエディタなど)に対してシステム環境設定>セキュリティとプライバシー>プライバシー>アクセシビリティでGUI Scriptingの実行を許可しておく必要があります。

AppleScript名:Dockに登録されている項目の情報を取得する.scpt
tell application "System Events"
  tell application process "Dock"
    tell list 1
      –アプリケーションのDock項目
      
set apList to every UI element whose subrole is "AXApplicationDockItem"
      
      
set nURLlist to {}
      
repeat with i in apList
        set anURL to properties of i
        
set the end of nURLlist to anURL
      end repeat
    end tell
  end tell
end tell

return nURLlist

★Click Here to Open This Script 

Posted in GUI Scripting System | Tagged 12.0savvy | Leave a comment

与えられた自然言語テキストから言語を推測して、指定の性別で、TTSキャラクタを自動選択して読み上げ

Posted on 2月 5, 2022 by Takaaki Naganoya

自然言語テキストを与えると、記述言語を推測して、その言語コード(jaとか)、性別、Premium(高音質)音声かどうか(true/false)をもとにText to Speechの読み上げ音声キャラクタをしぼりこんで、sayコマンドで音声読み上げするAppleScriptです。

# ScriptのリストについているURL Linkを書き換えました

自然言語から推測される言語コードと、TTS音声キャラクタに振られている言語コードの間に仕様的な食い違いがあるので、中国語の自動判定を行うためには、(若干の)処理を追加する必要があります。

自然言語テキストから取得できるのは「簡体字」「繁体字」のコードである一方で、TTS読み上げキャラクタが持っているのは、China、HongKong、Taiwanと国コードなので、対照表でもつけるか、いっそ全部「zh」でくくってランダム選択するか、、、はたまた、実行マシンの緯度・経度情報から判定するか、テーブルを編集可能なようにしておいて、テーブルのルールを決め打ちで反映するとか、、、、


▲システム環境設定>アクセシビリティ>読み上げコンテンツ>システムの声 のポップアップメニューで、一番下に「カスタマイズ」の項目があり、Text To Speech読み上げキャラクタの追加が行える


▲追加したTTSキャラクタの音声データは自動でダウンロードが行われる。TTS用にSiri音声は指定できないが、「ショートカット」の音声読み上げでは指定できる。このあたり、外部のTTS音声データ提供会社との契約によるものなのか、あるいは管理プログラムが異なるのか?

AppleScript名:与えられた自然言語テキストから言語を推測して、指定の性別で、TTSキャラクタを自動選択して読み上げ v1(簡体字、繁体字 未サポート).scptd
—
–  Created by: Takaaki Naganoya
–  Created on: 2022/02/05
—
–  Copyright © 2022 Piyomaru Software, All Rights Reserved
—
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSSpeechSynthesizer : a reference to current application’s NSSpeechSynthesizer

set str1 to "こんにちは"

–指定文字列が何語かを推測して、言語コード(Short)を取得
set a1Res to guessLanguageCodeOf(str1) of me

–指定の言語コード(Short)をキーにしてTTS属性情報を取得
set vList to retAvailableTTSbyShortLangCodeAndSexAndPremium(a1Res, "Female", true) of me
if vList = {} then return

–取得したTTS情報リストから、てきとーに項目を取得
set fV to contents of first item of vList

set vName to VoiceName of fV
say str1 using vName

—
on retAvailableTTSbyShortLangCodeAndSexAndPremium(aLangShortCode as string, aSex as string, premiumFlag as boolean)
  set outList to {}
  
  
if aSex is not in {"Male", "Female"} then error "Sex code is wrong"
  
  
set aList to NSSpeechSynthesizer’s availableVoices()
  
set bList to aList as list
  
  
repeat with i in bList
    set j to contents of i
    
set aInfo to (NSSpeechSynthesizer’s attributesForVoice:j)
    
set aInfoRec to aInfo as record
    
    
–読み上げ対象文字データは多すぎるので削除しておく
    
set VoiceIndividuallySpokenCharacters of aInfoRec to {}
    
set VoiceSupportedCharacters of aInfoRec to {}
    
    
set aName to VoiceName of aInfoRec
    
set aLangCode to VoiceLocaleIdentifier of aInfoRec
    
    
set aGender to VoiceGender of aInfoRec
    
set aVID to VoiceIdentifier of aInfoRec
    
    
if (aLangCode starts with aLangShortCode) and (aGender = "VoiceGender" & aSex) then
      if premiumFlag = true then
        if aVID ends with "premium" then
          set the end of outList to aInfoRec
        end if
      else
        set the end of outList to aInfoRec
      end if
    end if
  end repeat
  
  
return outList
end retAvailableTTSbyShortLangCodeAndSexAndPremium

–文字列から言語を推測して言語名を返す
on guessLanguageOf(theString)
  set theTagger to current application’s NSLinguisticTagger’s alloc()’s initWithTagSchemes:{current application’s NSLinguisticTagSchemeLanguage} options:0
  
theTagger’s setString:theString
  
set languageID to theTagger’s tagAtIndex:0 |scheme|:(current application’s NSLinguisticTagSchemeLanguage) tokenRange:(missing value) sentenceRange:(missing value)
  
return ((current application’s NSLocale’s localeWithLocaleIdentifier:"en")’s localizedStringForLanguageCode:languageID) as text
end guessLanguageOf

–文字列から言語を推測して言語コードを返す
on guessLanguageCodeOf(theString)
  set theTagger to current application’s NSLinguisticTagger’s alloc()’s initWithTagSchemes:{current application’s NSLinguisticTagSchemeLanguage} options:0
  
theTagger’s setString:theString
  
set languageID to theTagger’s tagAtIndex:0 |scheme|:(current application’s NSLinguisticTagSchemeLanguage) tokenRange:(missing value) sentenceRange:(missing value)
  
return languageID as text
end guessLanguageCodeOf

★Click Here to Open This Script 

Posted in Language Text Text to Speech | Tagged 10.15savvy 11.0savvy 12.0savvy NSLinguisticTagger NSLocale NSSpeechSynthesizer | Leave a comment

Post navigation

  • Older posts

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

Google Search

Popular posts

  • 開発機としてM2 Mac miniが来たのでガチレビュー
  • macOS 15, Sequoia
  • 指定のWordファイルをPDFに書き出す
  • Pages本執筆中に、2つの書類モード切り替えに気がついた
  • Numbersで選択範囲のセルの前後の空白を削除
  • メキシカンハットの描画
  • Pixelmator Pro v3.6.4でAppleScriptからの操作時の挙動に違和感が
  • AdobeがInDesign v19.4からPOSIX pathを採用
  • Safariで「プロファイル」機能を使うとAppleScriptの処理に影響
  • AppleScriptによる並列処理
  • Cocoa Scripting Course 続刊計画
  • macOS 14.xでScript Menuの実行速度が大幅に下がるバグ
  • AppleScript入門③AppleScriptを使った「自動化」とは?
  • Keynote/Pagesで選択中の表カラムの幅を均等割
  • Keynote、Pages、Numbers Ver.14.0が登場
  • macOS 15 リモートApple Eventsにバグ?
  • デフォルトインストールされたフォント名を取得するAppleScript
  • AppleScript入門① AppleScriptってなんだろう?
  • macOS 14で変更になったOSバージョン取得APIの返り値
  • macOS 15でも変化したText to Speech環境

Tags

10.11savvy (1101) 10.12savvy (1242) 10.13savvy (1391) 10.14savvy (587) 10.15savvy (438) 11.0savvy (283) 12.0savvy (212) 13.0savvy (194) 14.0savvy (147) 15.0savvy (129) CotEditor (66) Finder (51) iTunes (19) Keynote (116) 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) 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
  • 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年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