AppleScriptによるiTunesのスリープタイマー

AppleScriptの勉強をかねて、iTunes11でのスリープタイマーアプリケーションを作成してみました。

おヒマな方、AppleScriptに詳しい方には、ぜひお試しいただいて改善点などアドバイスをいただけたら幸いです。

当方、プログラム経験(COBOL,Visual Basic等)はあるものの、AppleScriptは全くの素人です。どんな事でも結構ですので何とぞご指導ください。




なお、iTunes11には「AppleScriptでシャッフルとリピートの情報を取得、設定できない」というバグがあるそうです。こちらにその報告があります。

iTunes 11 AppleScript bug « Doug's AppleScripts for iTunes

iTunes10.7では問題なく、iTunes11にて発生したバグであることは当方でも確認いたしました。


また、その対応策を考えられた方がいらっしゃいましたので、そちらからサンプルサブルーチンを拝借いたしました。それがこちらに公開されています。

How to set iTunes 11 in shuffle or repeat mode via applescript ...

このサブルーチンはiTunes11専用です。また、下記ソースコードでは日本語環境用に少々カスタマイズしています。




以下がソースコードです。(先頭のデフォルト値は、各々の好みで変更してください)

set myShuffleList to {"曲別", "アルバム別", "グループ別"}

set myTimerList to {"00:05:00", "00:15:00", "00:30:00", "01:00:00", "01:30:00", "02:00:00"}

set myDelayTime to 10


set myDefaultShuffle to "アルバム別"

set myDefaultPlayList to "お気に入りのラジオ番組"

set myDefaultTrack to "Jazz Wyoming"

set myDefaultTimer to "01:00:00"


try



-- iTunesが起動されているか?

if application "iTunes" is not running then

display alert "iTunesが起動されていません:" message "起動しますか?" as warning buttons {"No", "Yes"} default button "No" cancel button "No"

if result is {"No"} then

error number -128

else

tell application "iTunes" to run

end if

end if


tell application "iTunes"



-- Windowを表示


activate

set visible of front window to true



-- プレイリストを選択

set mySelectPlaylist to (choose from list (name of every playlist as list) with prompt "プレイリストを選択して下さい:" & return & "[キャンセル]で、再生を中止します。" default items myDefaultPlayList)

if mySelectPlaylist is false then

error number -128

else

set myPlaylist to playlist (mySelectPlaylist as string)


revealmyPlaylist

end if



-- トラックを選択

set mySelectTrack to (choose from list (name of every track of myPlaylist as list) with prompt "トラックを選択して下さい:" & return & "[キャンセル]で、全曲を再生します。" default items myDefaultTrack)

if mySelectTrack is false then


-- プレイリストを再生

set myTrack to myPlaylist

set myKind to ""


-- シャッフル再生?

set mySelectShuffle to (choose from list myShuffleList with prompt "シャッフル再生をしますか:" & return & "[キャンセル]で、先頭から再生します。" default items myDefaultShuffle)

if mySelectShuffle is false then

set myShuffle to "オフ"

else

set myShuffle to (mySelectShuffle as string)

end if

my setShuffleType(myShuffle)

else


-- トラックを再生

set myTrack to track (mySelectTrack as string) of myPlaylist

set myKind to kind of myTrack


revealmyTrack

end if



-- タイマーを選択:プレイリスト再生 or ラジオ再生

if (myKind is "") or (myKind is "インターネットオーディオストリーム") then

set myTimer to (choose from list myTimerList with prompt "再生時間を選択して下さい:" & return & "[キャンセル]で、再生を中止します。" default items myDefaultTimer)

if myTimer is false then error number -128

else

set myTimer to my retSecondsToTimer(((duration of myTrack) as integer) + 1)

end if



-- 再生開始

play myTrack with once


revealcurrent track



-- 再生時間の監視

set mySeconds to my retTimerToSeconds(myTimer as string)

repeat (mySeconds div myDelayTime + 1) times

if player state is not playing then exit repeat


delaymyDelayTime

end repeat


repeat with myVolume from 100 to 0 by -10

set sound volume to myVolume

delay 1

end repeat


stop

my setShuffleType("オフ")

set sound volume to 100

set visible of front window to false


end tell



-- エラー出口

on error wCaptionnumberwErrNum

if wErrNum = -128 then


-- "Cancelled!!"

else

error wCaptionnumberwErrNum

end if


end try


-- HH:MM:SSを秒に変換

on retTimerToSeconds(hhmmss)

set hh to (text from character 1 to character 2 of hhmmss) as integer

set mm to (text from character 4 to character 5 of hhmmss) as integer

set ss to (text from character 7 to character 8 of hhmmss) as integer

return (hh * hours + mm * minutes + ss)

end retTimerToSeconds


-- シャッフル状態の取得

on getShuffleType() -- the return value is a string: Off/By Songs/By Albums/By Groupings

tell application "System Events"

tell process "iTunes"

set menuItems to menu items of menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1

set onOffItemName to name of item 1 of menuItems

end tell

end tell



-- is shuffle off

ignoring case

if onOffItemName contains "シャッフルをオン" then return "オフ"

end ignoring



-- shuffle is on so find how we are shuffling

set currentChoice to "Unknown"

tell application "System Events"

tell process "iTunes"

repeat with i from 2 to count of menuItems

set anItem to item i of menuItems

try

set theResult to value of attribute "AXMenuItemMarkChar" of anItem

if theResult is not "" then

set currentChoice to name of anItem

exit repeat

end if

end try

end repeat

end tell

end tell

return currentChoice

end getShuffleType


-- シャッフルの設定

on setShuffleType(shuffleType) -- shuffleType is a string: Off/By Songs/By Albums/By Groupings

set currentValue to my getShuffleType()


script subs

on toggleShuffleOnOff(OnOff)

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name ends with "シャッフルを" & OnOff)

end toggleShuffleOnOff


on pressBySongs()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name ends with "曲別")

end pressBySongs


on pressByAlbums()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name ends with "アルバム別")

end pressByAlbums


on pressByGroupings()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name ends with "グループ別")

end pressByGroupings

end script


ignoring case

if shuffleType contains "オフ" then -- we have to make sure it's off

if currentValue does not contain "オフ" then subs's toggleShuffleOnOff("オフ")

else


-- make sure it's on

if currentValue contains "オフ" then subs's toggleShuffleOnOff("オン")



-- select the shuffle menu item for the type

if shuffleType contains "曲別" and currentValue does not contain "曲別" then


subs's pressBySongs()

else if shuffleType contains "アルバム別" and currentValue does not contain "アルバム別" then


subs's pressByAlbums()

else if shuffleType contains "グループ別" and currentValue does not contain "グループ別" then


subs's pressByGroupings()

end if

end if

end ignoring

end setShuffleType


なお、リピート再生については、実用的でないことから対応しておりません。

MacBook Pro (15-inch Early 2008), OS X Mountain Lion, Core2Duo 2.4GHz , 4G RAM

投稿日 2013/05/02 19:47

返信
返信: 47

2013/05/09 03:45 Hiro__S への返信

あれ? myTrackCountLimit の値を大きくしたんですか?このままだと、私の環境ではハングします。AppleScript Editor 起動直後にこのスクリプトを実行すると 100% ハング...。

はい、どうしても1000曲を越えるプレイリストを読み込みたかったので...

私のところではハングはしません。

1,028曲のプレイリストの読み込みが約90秒でした。

アプリケーション形式だとちゃんと動きますが、プレイリストの作成が極端に遅くなります。リミットは 50 でも良いぐらいです。1 曲 4 分で計 200 分。曲数が多いと設定だけで 10 分ぐらいかかっちゃいます。(笑)

設定はお好みで(お持ちのプレイリストの大きさに合わせて)減らして下さい。

それと、ライブラリ選択 → 複数選択...とすると、myTrackCountLimit が決壊。曲数分のプレイリストを作ってしまいます。

えへへ、仕様です。(笑)

myTrackCountLimitは、入力するプレイリストひとつ当りのトラック数上限です。この値を大きくしすぎると、例えば「ミュージック(ライブラリ全体)」や「プレイリストフォルダ」の様なトラック数の大きなものがプレイリストの選択リストに表示されてしまうため、それを抑止するために設けた制限値です。


「最初に全体のプレイリストを作って、そこから不要なトラックを順次絞り込んで削除していく」という効率的でない作りなので、最初に大きなプレイリストを選択しちゃうと凄い時間がかかってしまいます。(汗)

2013/05/09 04:55 Hiro__S への返信

どうぞご自由に弄りたおしてください。m( _ _ )m


先ほど見つけた不具合というか面白くない仕様をひとつお知らせします。

「プレイリストを複数選択したとき、各プレイリストに同じ曲が存在すると出来上がったプレイリストにも同じ曲がダブってしまいます。」その点をご了承ください。


また後日、何らかの対策を考えます。

2013/05/09 05:12 Pajerow への返信

プレイリストを複数選択したとき、各プレイリストに同じ曲が存在すると出来上がったプレイリストにも同じ曲がダブってしまいます。


実は、週末の楽しみの一つにこれが入ってたりして。(笑)


例えば myTrackCountLimit を 500 にして、表示されたプレイリストを全部選択すると、私の場合プレイリストが 2000 曲を超えてしまいます。かなり重複してます。それも含めて「決壊」と書きました。対処いただけるなら是非ともお願いしたく。

2013/05/09 18:33 Pajerow への返信

Hiro.Sさん、こんにちは。

貴殿の「週末の楽しみ」を奪うつもりはありませんので見たくなかったらスルーして下さい。(笑)



Pajerow による書き込み:


「プレイリストを複数選択したとき、各プレイリストに同じ曲が存在すると出来上がったプレイリストにも同じ曲がダブってしまいます。」その点をご了承ください。


また後日、何らかの対策を考えます。

について、以下のとおり対策を施しました。(赤字部分を追加)

set myTrackCountLimit to 1500

set myDuplicateTrackNumberCheck to true

set myPlaylistName to "for Sleep Timer"

set myShuffleList to {"曲別", "アルバム別", "グループ別"}

set myTimerList to {"00:05:00", "00:15:00", "00:30:00", "01:00:00", "01:30:00", "02:00:00"}

set myDelayTime to 5




(省略)




-- アルバムを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to album of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "アルバムを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultAlbum with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose album is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



-- 重複トラックの削除

my delDuplicates(myPlayTrack, myDuplicateTrackNumberCheck)

set mytracks to every track of myPlayTrack



-- トラックを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to name of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "トラックを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultTrack with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose name is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



(省略)



-- 重複トラックの削除

on delDuplicates(plList, trkNum)

tell application "iTunes"

-- find all artists

set artistList to artist of every track of plList whose artist is not missing value

set actArtList to {}

repeat with a in artistList

if not (actArtList contains (a as string)) then copy (a as string) to end of actArtList

end repeat

-- find all albums for a given artist

repeat with a in actArtList

set albList to (album of every track of plList whose artist is a and album is not missing value)

set actAlbList to {}

repeat with al in albList

if not (actAlbList contains (al as string)) then copy (al as string) to end of actAlbList

end repeat

-- find all tracks with artist a and album al

repeat with al in actAlbList

set naList to (name of every track of plList whose artist is a and album is al and name is not missing value)

set actNaList to {}

repeat with na in naList

if not (actNaList contains (na as string)) then copy (na as string) to end of actNaList

end repeat

-- find all tracks with artist a and album al and name na

repeat with na in actNaList

-- Checking of track number ?

if trkNum is true then

set trList to (track number of every track of plList whose artist is a and album is al and name is na and track number is not missing value)

set actTrList to {}

repeat with tr in trList

if not (actTrList contains tr) then copy tr to end of actTrList

end repeat

-- find all tracks with artist a and album al and name na and track number tr

repeat with tr in actTrList

-- handle those tracks

set tracksWithThisComb to (every track of plList whose artist is a and album is al and name is na and track number is tr)

if length of tracksWithThisComb > 1 then

repeat with i from 2 to length of tracksWithThisComb

set t to item i of tracksWithThisComb

delete t

end repeat

end if

end repeat

else

set tracksWithThisComb to (every track of plList whose artist is a and album is al and name is na)

if length of tracksWithThisComb > 1 then

repeat with i from 2 to length of tracksWithThisComb

set t to item i of tracksWithThisComb

delete t

end repeat

end if

end if

end repeat

end repeat

end repeat

end tell

end delDuplicates


上記の「delDuplicates」サブルーチンは、Cleaning up your iTunes library (on a mac)のサイトを参考にさせていただきました。このサイトのスクリプトでは「アーティスト名、アルバム名、トラック名が同じもの」を重複として判定していましたが、それだと同一アルバム内にある同一トラック名の曲が重複と判断されて削除されてしまう事例があったため、判定条件にさらに「トラックNo.」を追加しました。(例えば、オフコースのOverに収録されている「心 はなれて」など...当方のライブラリ内に該当するアルバムが数枚ありました)

ただし、この判定条件を追加すると、プレイリストの曲数が増えた場合に大きなCPU負荷がかかり処理時間も極端に増大します。もしこの条件をはずしたい場合は、myDuplicateTrackNumberCheckの初期値をFalseにしてください。



また、「ブックを除外」するロジックに考慮不足がありましたので下記の通り変更しました。


-- ブックを除外

delete (every track of myPlayTrack whose kind ends with "ブック" or kind is "PDF 書類")

set mytracks to every track of myPlayTrack

従来は「名前」だけで判定していましたが、ブックと同一名の曲があると除外されてしまう事例があったため、「名前:name」でなく「種類:kind」で判定する様に変更しました。(例えば、夏目漱石の「こころ」と小田和正の自己ベスト2に収録されている「こころ」が同一名のため削除されていました)

2013/05/10 02:59 Pajerow への返信

重複回避はもっとシンプルにこんな感じでどうでしょうか?database ID がミソ。


オリジナル

-- 専用プレイリストにコピー:リンク切れがあるとここでエラーが発生する(無視)

try

repeat with myItem in mySelect

set mytracks to every track of playlist (myItem as string)

repeat with mytrack in mytracks

duplicate mytrack to myPlayTrack

end repeat

end repeat

set mytracks to every track of myPlayTrack

end try


重複を回避しながらプレイリストを作成

-- 専用プレイリストにコピー:リンク切れがあるとここでエラーが発生する(無視)

try

repeat with i in mySelect

repeat with j in tracks of playlist (i as string)

if exists tracks in myPlayTrack then

set id_list to database ID of tracks in myPlayTrack

else

set id_list to {}

end if

if database ID of j is not in id_list then

duplicate j to myPlayTrack

end if

end repeat

end repeat

set mytracks to tracks of myPlayTrack

end try


また、重複可/不可を切り替えるなら適当にフラグを立ててから if 文でこんな感じ。

set dedupe to yes as boolean

if dedupe is false then

-- 重複ありのプレイリスト作成

else

-- 重複なしのプレイリスト作成

end if

2013/05/10 03:38 Hiro__S への返信

すっ、すっごい!!! ナイスです!!

Hiro.S さんによる書き込み:


database ID がミソ。

なるほど、database IDとは... これだと一発で重複がわかりますね。

the common, unique ID for this track. If two tracks in different playlists have the same database ID, they are sharing the same data.」だそうですね。(用語説明より)


非常にシンプルでわかり易いです。

CPU負荷も60%程度ですし。(私のだと100%振り切れてました)



謹んで頂戴いたします。

どうもありがとうございました。m( _ _ )m

2013/05/18 20:57 Pajerow への返信

iTunes 11.0.3 では AppleScript 関連に大きく手が加えられたようです。


iTunes 11.0.2~11.0.3 AppleScript系変更点まとめ

http://piyocast.com/as/archives/2461


その他に気づいた点は、

  • shuffle と song repeat が操作できない問題は直っていない模様。残念...。
  • iTunes 10 から発生していた変なバグ (ある種の AppleScript を実行した後で iTunes のメニューバーがランダムでグレイアウトする) は修正されたようです。多分...。
  • UI の構成が一部変更になったので GUI スクリプティングは要注意。


このスクリプトには多分影響がないと思いますが一応ご報告まで。

2013/05/18 21:41 Hiro__S への返信

Hiro.Sさん、こんにちは。 ご報告ありがとうございます。


shuffle と song repeat が操作できない問題は直っていない模様。残念...。

この点は、アップデート後すぐに当方でも確認しておりました。残念です。


iTunes 10 から発生していた変なバグ (ある種の AppleScript を実行した後で iTunes のメニューバーがランダムでグレイアウトする) は修正されたようです。多分...。

先日、このスクリプトでのシャッフルのメニュー操作でエラーが発生したことがありました。これが原因だったのかも...。直ったのかもしれませんのでしばらく様子見です。


UI の構成が一部変更になったので GUI スクリプティングは要注意。

ですね。まぁ、これは使っていない(使い方がわからない)ので大丈夫かと。



あと、AirPlay関係の機能追加がありましたので早速こちらを試してみました。

Basic Airplay script

でも、あまり実用性がないので止めました。

2013/11/03 01:49 Pajerow への返信

Mac OS X 10.9 Maverics が発表されたので動作確認してみました。


基本的にそのままで動作しました。

ただし、以下の不思議な現象を確認できました。


(10.9 Mavericsで発生する固有の現象)

本プログラムをScriptとして動作させた場合は問題ないが、

Applicationとして保存し実行した場合に問題が発生する。

例えば、再生時間を5分として実行しても、実際には約8分間再生が続く。

(指定した時間で再生が終了しない)

Scriptの中で「Delay」命令でループさせているがその動作が関係しているのではないかと予想。



そもそも、Scriptのまま実行するのとApplicationとして保存して実行することでどうして動作が違ってくるのでしょうか???

お分かりの方、いらっしゃいませんか。

2013/11/03 08:00 Pajerow への返信

お手伝いしたい気持ちはあるのですが Snow Leopard な私には手も足も出ません。ギブアップ。


とりあえず現在知ってるのは、Mavericks の AppleScript は過去最大級の変革が行われたこと、OS の セキュリティがさらに強化されたこと、それに伴いユニバーサルアクセスへの一定の制限が加えられたこと。


この辺を頭の片隅に置きつつ、スクリプトの各部分を一つずつ確認していくしかないような気もします。


下記は Mavericks の AppleScript 情報です。本件とは関係ないかもしれませんが一応。


Piyomaru Software (ご存知かと思いますが、ここは AppleScript 全般)

http://piyocast.com/as/


New Automation Features in OS X Mavericks

http://macosxautomation.com/mavericks/index.html


OS X: GUI Scripting - Accessibility Access Controls

http://macosxautomation.com/mavericks/guiscripting/index.html

2013/11/03 13:25 Hiro__S への返信

Hiro.Sさん、コメントありがとうございます。


そうでしたね、まだSnow Leopardで頑張っておられるんですね。(^ ^)

ご提示いただいたリンク先については当方でも適時参照するようにしています。


今回報告の現象は、Mavericks Developper Previewのときからいろいろと検証していたのですが、正式リリース版でも動作が変わらなかったので投稿させていただきました。


また、何か思いつくことがありましたらコメントよろしくお願いいたします。

2013/11/03 18:14 Pajerow への返信

Pajerow による書き込み:


(10.9 Mavericsで発生する固有の現象)

本プログラムをScriptとして動作させた場合は問題ないが、

Applicationとして保存し実行した場合に問題が発生する。

例えば、再生時間を5分として実行しても、実際には約8分間再生が続く。

(指定した時間で再生が終了しない)

Scriptの中で「Delay」命令でループさせているがその動作が関係しているのではないかと予想。

上記の不可思議な現象を回避するため、一部Scriptを変更しました。



(変更前)


-- 再生時間の監視

set myRepeat to mySeconds div myDelayTime

if mySeconds mod myDelayTime > 0 then set myRepeat to myRepeat + 1

repeat myRepeat times

if player state is not playing then exit repeat

set myNewTrack to current track

if myNewTrack is not myOldTrack then

set myOldTrack to myNewTrack

revealmyNewTrack

end if

delaymyDelayTime

end repeat


(変更後)


-- 再生時間の監視

set sTime to my (current date)

set nTime to sTime

set eTime to sTime + mySeconds

repeat while nTime < eTime

if player state is not playing then exit repeat

set myNewTrack to current track

if myNewTrack is not myOldTrack then

set myOldTrack to myNewTrack

revealmyNewTrack

end if

delaymyDelayTime

set nTime to my (current date)

end repeat

※実時間による判定を行うようにしたため、Delay命令のループによる経過時間の遅延は発生しないようになりました。

2013/11/03 18:17 Pajerow への返信

大分手を加えましたので、再度全体を掲載しておきます。

set myTrackCountLimit to 1500

set myPlaylistName to "for Sleep Timer"

set myShuffleList to {"曲別", "アルバム別", "グループ別"}

set myTimerList to {"00:05:00", "00:15:00", "00:30:00", "01:00:00", "01:30:00", "02:00:00"}

set myDelayTime to 5


set myDefaultShuffle to "アルバム別"

set myDefaultPlayList to "インターネットラジオ"

set myDefaultGenre to "*"

set myDefaultArtist to "*"

set myDefaultAlbum to "*"

set myDefaultTrack to "Jazz Wyoming"

set myDefaultTimer to "01:00:00"


try



-- iTunesが起動されているか?

if application "iTunes" is not running then


--display alert "iTunesが起動されていません:" message "起動しますか?" as warning buttons {"No", "Yes"} default button "Yes" cancel button "No"


--if result is {"No"} then error number -128

tell application "iTunes" to run

end if


tell application "iTunes"



-- Windowを表示


activate

set visible of front window to true



-- 専用プレイリストを作成

set myAllPlaylist to name of every playlist as list

if myPlaylistName is in myAllPlaylist then

set myPlayTrack to playlist (myPlaylistName)

delete every track of myPlayTrack

else

set myPlayTrack to makenewplaylistwith properties {name:myPlaylistName}

end if


revealmyPlayTrack



-- プレイリストを選択:複数選択も可

set myList to {}

repeat with myItem in myAllPlaylist

set myStr to myItem as string

if ((counttracks of playlist (myStr)) > myTrackCountLimit) or (myStr is myPlaylistName) then

else

set myList to myList & {myStr}

end if

end repeat

set mySelect to choose from list myList with prompt "プレイリストを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]で再生を中止します。" & return & return & "(トラック数が" & myTrackCountLimit & "曲を越えるプレイリストは表示されません)" default items myDefaultPlayList with multiple selections allowed

if mySelect is false then error number -128



-- 専用プレイリストに重複を除外してコピー:リンク切れがあるとここでエラーが発生するが無視する

try

set id_list to {}

repeat with i in mySelect

repeat with j in tracks of playlist (i as string)

if database ID of j is not in id_list then

set id_list to id_list & (database ID of j)


duplicatejtomyPlayTrack

end if

end repeat

end repeat

end try



-- ブックを除外

delete (every track of myPlayTrack whose kind ends with "ブック" or kind is "PDF 書類")

set mytracks to every track of myPlayTrack



-- ジャンルを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to genre of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

set myList to my simple_sort(the myList)

set mySeconds to duration of myPlayTrack

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "ジャンルを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultGenre with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose genre is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



-- アーティストを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to artist of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

set myList to my simple_sort(the myList)

set mySeconds to duration of myPlayTrack

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "アーティストを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultArtist with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose artist is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



-- アルバムを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to album of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

set myList to my simple_sort(the myList)

set mySeconds to duration of myPlayTrack

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "アルバムを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultAlbum with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose album is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



-- トラックを選択:複数選択も可

set myList to {}

repeat with mytrack in mytracks

set myStr to name of mytrack

if myStr is not in myList then set myList to myList & {myStr}

end repeat

set myList to my simple_sort(the myList)

set mySeconds to duration of myPlayTrack

if myList is not {} and myList is not {""} and number of myList > 1 then

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "トラックを選択して下さい:" & return & "(複数選択も可)" & return & "[キャンセル(esc)]ですべてを選択します。" default items myDefaultTrack with multiple selections allowed

if mySelect is not false then

repeat with myItem in myList

if myItem is not in mySelect then

delete (every track of myPlayTrack whose name is myItem as string)

end if

end repeat

set mytracks to every track of myPlayTrack

end if

end if



-- 曲数の判定:複数曲の場合、シャッフル再生

my setShuffleType("オフ")

my setRepeatType("")

set myTrackCount to counttrack of myPlayTrack

if myTrackCount = 0 then error number -128

set mySeconds to duration of myPlayTrack

if myTrackCount > 1 then

set myList to myShuffleList

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "シャッフル再生をしますか:" & return & "[キャンセル(esc)]で先頭から再生します。" default items myDefaultShuffle

if mySelect is not false then my setShuffleType(mySelect as string)

end if



-- タイマー選択

set myList to myTimerList

if mySeconds is 0 then

set mySelect to choose from list myList with prompt "再生時間を選択して下さい:" & return & "[キャンセル(esc)]で再生を中止します。" default items myDefaultTimer

if mySelect is false then error number -128

set mySeconds to my retTimerToSeconds(mySelect as string)

else

set myDuration to mySeconds

set mySelect to choose from list myList with prompt "選択合計時間:" & my retSecondsToTimer(mySeconds) & return & return & "再生時間を選択して下さい:" & return & "指定時間リピート再生します。" & return & "[キャンセル(esc)]で全体を1回のみ再生します。" default items myDefaultTimer

if mySelect is not false then

set mySeconds to my retTimerToSeconds(mySelect as string)

if mySeconds > myDuration then my setRepeatType("すべて")

end if

end if



-- 再生開始


playmyPlayTrack with once

set myOldTrack to current track


revealmyOldTrack



-- 再生時間の監視


(*set myRepeat to mySeconds div myDelayTime

if mySeconds mod myDelayTime > 0 then set myRepeat to myRepeat + 1

repeat myRepeat times

if player state is not playing then exit repeat

set myNewTrack to current track

if myNewTrack is not myOldTrack then

set myOldTrack to myNewTrack

reveal myNewTrack

end if

delay myDelayTime

end repeat*)


set sTime to my (current date)

set nTime to sTime

set eTime to sTime + mySeconds

repeat while nTime < eTime

if player state is not playing then exit repeat

set myNewTrack to current track

if myNewTrack is not myOldTrack then

set myOldTrack to myNewTrack


revealmyNewTrack

end if


delaymyDelayTime

set nTime to my (current date)

end repeat



-- フェードアウトして停止

set myVolume to sound volume

if player state is playing then

repeat with v from myVolume to 0 by -1

set sound volume to v

delay 0.1

end repeat

end if


stop

my setShuffleType("オフ")

my setRepeatType("")

set sound volume to myVolume

set visible of front window to false


--quit


end tell



-- エラー出口

on error wCaptionnumberwErrNum

tell me to activate

if wErrNum = -128 then


-- "Cancelled !!"

display alert "処理は中止されました..." as warning

else


-- "Error Happend !!"

display alert wCaption & return & "Error No" & wErrNum as warning

end if

end try


-- HH:MM:SSを秒に変換

on retTimerToSeconds(hhmmss)

set hh to (text from character 1 to character 2 of hhmmss) as integer

set mm to (text from character 4 to character 5 of hhmmss) as integer

set ss to (text from character 7 to character 8 of hhmmss) as integer

return (hh * hours + mm * minutes + ss)

end retTimerToSeconds


-- 秒をHH:MM:SSに変換

on retSecondsToTimer(ssNum)

set hhStr to retZeroPaddingText((ssNum div hours) as string, 2)

set mmStr to retZeroPaddingText((ssNum mod hours div minutes) as string, 2)

set ssStr to retZeroPaddingText((ssNum mod hours mod minutes) as string, 2)

return hhStr & ":" & mmStr & ":" & ssStr

end retSecondsToTimer


-- ゼロパディング

on retZeroPaddingText(aNum, aLen)

do shell script "printf '%0" & aLen & "d' " & aNum

end retZeroPaddingText


-- シャッフル状態の取得

on getShuffleType() -- the return value is a string: Off/By Songs/By Albums/By Groupings


tell application "System Events"

tell process "iTunes"

set menuItems to menu items of menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1

set onOffItemName to name of item 1 of menuItems

end tell

end tell



-- is shuffle off

if onOffItemName contains "オン" then return "オフ"



-- shuffle is on so find how we are shuffling

set currentChoice to "Unknown"

tell application "System Events"

tell process "iTunes"

repeat with i from 2 to count of menuItems

set anItem to item i of menuItems

try

set theResult to value of attribute "AXMenuItemMarkChar" of anItem

if (theResult is not "") and (theResult is not missing value) then

set currentChoice to name of anItem

exit repeat

end if

end try

end repeat

end tell

end tell

return currentChoice


end getShuffleType


-- シャッフルの設定

on setShuffleType(shuffleType) -- shuffleType is a string: Off/By Songs/By Albums/By Groupings


set currentValue to my getShuffleType()


script subs

on toggleShuffleOnOff()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name contains "シャッフル")

end toggleShuffleOnOff


on pressBySongs()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name contains "")

end pressBySongs


on pressByAlbums()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name contains "アルバム")

end pressByAlbums


on pressByGroupings()

tell application "System Events" to perform action "AXPress" of (first menu item of process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "シャッフル"'s menu 1 whose name contains "グループ")

end pressByGroupings

end script


if shuffleType contains "オフ" then -- we have to make sure it's off

if currentValue does not contain "オフ" then subs's toggleShuffleOnOff()

else


-- make sure it's on

if currentValue contains "オフ" then subs'stoggleShuffleOnOff()



-- select the shuffle menu item for the type

if shuffleType contains "" and currentValue does not contain "" then


subs'spressBySongs()

else if shuffleType contains "アルバム" and currentValue does not contain "アルバム" then


subs'spressByAlbums()

else if shuffleType contains "グループ" and currentValue does not contain "グループ" then


subs'spressByGroupings()

end if

end if


end setShuffleType


-- リピート状態の取得

on getRepeatType() -- the return value is a string: Off/All/One

tell application "System Events"

tell process "iTunes"

set menuItems to menu items of menu bar 1's menu bar item "制御"'s menu 1's menu item "リピート"'s menu 1

set currentChoice to "unknown"

repeat with anItem in menuItems

try

set theResult to value of attribute "AXMenuItemMarkChar" of anItem

if (theResult is not "") and (theResult is not missing value) then

set currentChoice to name of anItem

exit repeat

end if

end try

end repeat

end tell

end tell

return currentChoice

end getRepeatType


-- リピートの設定

on setRepeatType(repeatType) -- repeatType is a string: Off/All/One

set currentValue to my getRepeatType()

if currentValue is not repeatType then

tell application "System Events" to tell process "iTunes"'s menu bar 1's menu bar item "制御"'s menu 1's menu item "リピート"'s menu 1

if repeatType is "すべて" then

perform action "AXPress" of menu item "すべて"

else if repeatType is "1 項目" then

perform action "AXPress" of menu item "1 項目"

else

perform action "AXPress" of menu item ""

end if

end tell

end if

end setRepeatType


-- リストの並べ替え

on simple_sort(my_list)

set the index_list to {}

set the sorted_list to {}

repeat (the number of items in my_list) times

set the low_item to "*"

repeat with i from 1 to (number of items in my_list)

if i is not in the index_list then

set this_item to item i of my_list as text

if the low_item is "*" then

set the low_item to this_item

set the low_item_index to i

else if this_item comes before the low_item then

set the low_item to this_item

set the low_item_index to i

end if

end if

end repeat

set the end of sorted_list to the low_item

set the end of the index_list to the low_item_index

end repeat

return the sorted_list

end simple_sort


2013/11/03 22:41 Pajerow への返信

当方の環境ではバッチリ動きました。お疲れさまです。


ーーーーー


皆さん


このスレッドの冒頭でも触れられている iTunes の AppleScript で「shuffle と song repeat が取得/設定できない問題」のフィードバックをしていただけませんか?既に報告済みの方は再度していただければと。私もフィードバックしましたが、後回しになってるみたいで...。


問題のコードはこんな感じです。


tell application "iTunes"     tell playlist "プレイリスト名" -- 「プレイリスト名」は適宜変更してください                 (* 取得の問題 *)         -- song repeat -- off/one/all が返されるはずも、常に off が返される         -- shuffle -- true/false が返されるはずも、常に false が返される                 (* 設定の問題 *)         -- set song repeat to one -- エラー         -- set shuffle to true -- エラー             end tell end tell

このスレッドはシステム、またはAppleコミュニティチームによってロックされました。 問題解決の参考になる情報であれば、どの投稿にでも投票いただけます。またコミュニティで他の回答を検索することもできます。

AppleScriptによるiTunesのスリープタイマー

Apple サポートコミュニティへようこそ
Apple ユーザ同士でお使いの製品について助け合うフォーラムです。Apple Account を使ってご参加ください。