-- Dialog:Title:LineFeed:Tab set mTitle to me's name set mLF to linefeed set mTB to tab -- Playlist Selection Dialog when Text Search:Display Switch set mSearchPlaylist to true -- Item Selection Dialog:Display Switch set mOneItem to true -- Shuffle Selection Dialog:Display Switch:Shuffle Pattern:Minimum Number of Songs set mShuffle to true set mShuffleList to {"Songs", "Albums"} set mShuffleMinimum to 2 -- Timer Selection Dialog:Display Switch:Timer Pattern:Monitoring Interval by Seconds set mTimer to true set mTimerList to {"00:05:00", "00:15:00", "00:30:00", "01:00:00", "01:30:00", "02:00:00"} set mTimerDelay to 5 try tell application "Music" delay 0.5 -- Window Name set mMusicWindow to name of browser window 1 -- Playlist Name set mLibraryPlaylist to name of library playlist 1 set mMusicPlaylist to name of user playlist 1 set mMyPlaylist to "Music Player" set mSearchResult to "Search Result" set mSearchResult1 to "Search Result1" set mSearchResult2 to "Search Result2" set mExcludePlaylist to {mMusicPlaylist, "Alfred Playlist"} -- Launch Application:Hide Main Window activate --set (window mMusicWindow)'s collapsed to true -- Input Search Text:Stop Process by Cancel display dialog "Input Search Text: (*:AND , +:OR)" default answer "" with title mTitle buttons {"Cancel", "OK"} default button 2 set mSearchText to result's text returned set mSearchText to my RepAndTrim(mSearchText) -- Select Playlist:Unselected is Entire Library:Stop Process by Cancel if ((count mSearchText) is 0) or mSearchPlaylist then set mList to {} repeat with i in ((every playlist's name) as list) if ((count playlist (i)'s tracks) > 0) and (not (mExcludePlaylist contains playlist (i)'s name)) then set mList's end to i end repeat set mChoose to choose from list mList with title mTitle with prompt "Select playlist to search:" cancel button name "Cancel" with multiple selections allowed if mChoose is false then error number -128 if (count mChoose) is 0 then set mChoose to {mLibraryPlaylist} else set mChoose to {mLibraryPlaylist} end if -- Perform Text Search if (count mSearchText) is not 0 then if mSearchResult is not in ((every playlist's name) as list) then set mSearchTrack to make new playlist with properties {name:mSearchResult} set mSearchTrack to playlist (mSearchResult) delete mSearchTrack's every track set mSearchTrack1 to make new playlist with properties {name:mSearchResult1} set mSearchTrack2 to make new playlist with properties {name:mSearchResult2} set mList to my devText(mSearchText, "+") repeat with h in mChoose repeat with i in mList set mList1 to my devText(i, "*") set mPlaylist to h set mText to (mList1's item 1) as string set mTracks to my TextSearch(mPlaylist, mText) repeat with j in mTracks duplicate j to mSearchTrack1 end repeat if (count mList1) > 1 then set mList1 to mList1's rest repeat with j in mList1 set mPlaylist to mSearchResult1 set mText to j as string set mTracks to my TextSearch(mPlaylist, mText) repeat with k in mTracks duplicate k to mSearchTrack2 end repeat delete mSearchTrack1's tracks duplicate mSearchTrack2's tracks to mSearchTrack1 delete mSearchTrack2's tracks end repeat end if duplicate mSearchTrack1's tracks to mSearchTrack end repeat end repeat delete playlist (mSearchResult1) delete playlist (mSearchResult2) set mChoose to {mSearchResult} end if -- Exclude Duplicate Tracks:Get Track Information:Exit without Tracks set mID to {} set mList to {} set mListGenre to {} set mListArtist to {} set mListAlbum to {} repeat with i in mChoose repeat with j in playlist (i)'s tracks tell j if database ID is not in mID then set mID's end to database ID if genre is not in mListGenre then set mListGenre's end to genre as string if artist is not in mListArtist then set mListArtist's end to artist as string if album is not in mListAlbum then set mListAlbum's end to album as string end if end tell end repeat end repeat if mSearchResult is in ((every playlist's name) as list) then delete playlist (mSearchResult) if (count mID) is 0 then error number -129 set mPrompt to "Search Text : " & mSearchText & mLF & mLF & "Found Item : " & mLF & (count mListGenre) & mTB & "Genres" & mLF & (count mListArtist) & mTB & "Artists" & mLF & (count mListAlbum) & mTB & "Albums" & mLF & (count mID) & mTB & "Songs" & mLF set mList to mListGenre -- Select Genres:Get Track Information:Stop Process by Cancel if ((count mList) ⠥ 2) or mOneItem then set mDefault to "" if (count mList) = 1 then set mDefault to mList's item 1 set mList to my SortOfList(the mList) set mChoose to choose from list mList with title mTitle with prompt (mPrompt & mLF & "Select Genres: (Select All with Unselected)") as string default items mDefault cancel button name "Cancel" with multiple selections allowed and empty selection allowed else set mChoose to {} end if if mChoose is false then error number -128 set mID1 to {} set mList to {} set mListGenre to {} set mListArtist to {} set mListAlbum to {} repeat with i in mID tell (tracks whose database ID is i) if ((count mChoose) is 0) or (genre is in mChoose) then set mID1's end to i if genre is not in mListGenre then set mListGenre's end to genre as string if artist is not in mListArtist then set mListArtist's end to artist as string if album is not in mListAlbum then set mListAlbum's end to album as string end if end tell end repeat set mID to mID1 set mPrompt to "Search Text : " & mSearchText & mLF & mLF & "Found Item : " & mLF & (count mListGenre) & mTB & "Genres" & mLF & (count mListArtist) & mTB & "Artists" & mLF & (count mListAlbum) & mTB & "Albums" & mLF & (count mID) & mTB & "Songs" & mLF set mList to mListArtist -- Select Artists:Get Track Information:Stop Process by Cancel if ((count mList) ⠥ 2) or mOneItem then set mDefault to "" if (count mList) = 1 then set mDefault to mList's item 1 set mList to my SortOfList(the mList) set mChoose to choose from list mList with title mTitle with prompt (mPrompt & mLF & "Select Artists: (Select All with Unselected)") as string default items mDefault cancel button name "Cancel" with multiple selections allowed and empty selection allowed else set mChoose to {} end if if mChoose is false then error number -128 set mID1 to {} set mList to {} set mListGenre to {} set mListArtist to {} set mListAlbum to {} repeat with i in mID tell (tracks whose database ID is i) if ((count mChoose) is 0) or (artist is in mChoose) then set mID1's end to i if genre is not in mListGenre then set mListGenre's end to genre as string if artist is not in mListArtist then set mListArtist's end to artist as string if album is not in mListAlbum then set mListAlbum's end to album as string end if end tell end repeat set mID to mID1 set mPrompt to "Search Text : " & mSearchText & mLF & mLF & "Found Item : " & mLF & (count mListGenre) & mTB & "Genres" & mLF & (count mListArtist) & mTB & "Artists" & mLF & (count mListAlbum) & mTB & "Albums" & mLF & (count mID) & mTB & "Songs" & mLF set mList to mListAlbum -- Select Albums:Get Track Information:Stop Process by Cancel if ((count mList) ⠥ 2) or mOneItem then set mDefault to "" if (count mList) = 1 then set mDefault to mList's item 1 set mList to my SortOfList(the mList) set mChoose to choose from list mList with title mTitle with prompt (mPrompt & mLF & "Select Albums: (Select All with Unselected)") as string default items mDefault cancel button name "Cancel" with multiple selections allowed and empty selection allowed else set mChoose to {} end if if mChoose is false then error number -128 set mID1 to {} set mList to {} set mListGenre to {} set mListArtist to {} set mListAlbum to {} set mListName to {} repeat with i in mID tell (tracks whose database ID is i) if ((count mChoose) is 0) or (album is in mChoose) then set mID1's end to i if genre is not in mListGenre then set mListGenre's end to genre as string if artist is not in mListArtist then set mListArtist's end to artist as string if album is not in mListAlbum then set mListAlbum's end to album as string if name is not in mListName then set mListName's end to name as string end if end tell end repeat set mID to mID1 set mPrompt to "Search Text : " & mSearchText & mLF & mLF & "Found Item : " & mLF & (count mListGenre) & mTB & "Genres" & mLF & (count mListArtist) & mTB & "Artists" & mLF & (count mListAlbum) & mTB & "Albums" & mLF & (count mID) & mTB & "Songs" & mLF set mList to mListName -- Select Tracks:Stop Process by Cancel --if ((count mList) ⠥ 2) or mOneItem then if (count mList) ⠥ 1 then set mDefault to "" if (count mList) = 1 then set mDefault to mList's item 1 set mChoose to choose from list mList with title mTitle with prompt (mPrompt & mLF & "Select Tracks: (Select All with Unselected)") as string default items mDefault cancel button name "Cancel" with multiple selections allowed and empty selection allowed else set mChoose to {} end if if mChoose is false then error number -128 -- Create Playlist:Ignore Broken Link Errors:Exit without Tracks try if mMyPlaylist is not in ((every playlist's name) as list) then set mPlayTrack to make new playlist with properties {name:mMyPlaylist} set mPlayTrack to playlist (mMyPlaylist) delete mPlayTrack's every track repeat with i in mID tell (tracks whose database ID is i) if ((count mChoose) is 0) or (name is in mChoose) then duplicate tracks to mPlayTrack end if end tell end repeat end try set mCount to (count mPlayTrack's tracks) if mCount is 0 then error number -129 -- Shuffle Selection set shuffle enabled to false if mShuffle then if (mCount ⠥ mShuffleMinimum) then set mChoose to choose from list mShuffleList with title mTitle with prompt ("Select Shuffle: (All " & mCount & " Songs)") as string cancel button name "Cancel" with empty selection allowed if (mChoose is not false) and ((count mChoose) is not 0) then if mChoose is {"Songs"} then set shuffle mode to songs if mChoose is {"Albums"} then set shuffle mode to albums set shuffle enabled to true end if end if end if -- Playback Time set mSeconds to mPlayTrack's duration -- Timer Selection:Repeat Setting:Stop Process by Cancel set song repeat to off if mSeconds is 0 then -- For URL Tracks set mChoose to choose from list mTimerList with title mTitle with prompt ("Select Timer: (Required)") as string cancel button name "Cancel" if mChoose is false then error number -128 set mSeconds to my TimeToSeconds(mChoose as string) else if mTimer then set mDuration to mSeconds set mMyTime to my SecondsToTime(mDuration) set mTimerList's end to mMyTime set mTimerList to my SortOfList(the mTimerList) set mChoose to choose from list mTimerList with title mTitle with prompt ("Select Timer: (All " & mCount & " Songs)") as string default items mMyTime cancel button name "Cancel" if mChoose is false then error number -128 if (count mChoose) is not 0 then set mSeconds to my TimeToSeconds(mChoose as string) if mSeconds > mDuration then set song repeat to all end if end if end if -- Start Playing play playlist mMyPlaylist set mOldTrack to current track if front window's name is mMusicWindow then reveal current track -- Playtime Monitoring Loop set mStartTime to my (current date) set mEndTime to mStartTime + mSeconds set mNowTime to mStartTime repeat while mNowTime < mEndTime if application "Music" is not running then error number -128 if player state is stopped then exit repeat if player state is paused then set mEndTime to mEndTime + mTimerDelay set mNewTrack to current track if mNewTrack is not mOldTrack then if song repeat is off then delete mOldTrack if front window's name is mMusicWindow then reveal current track set mOldTrack to mNewTrack end if delay mTimerDelay set mNowTime to my (current date) end repeat set mNowTime to my (current date) -- Fade-out:Stop Playback set mVolume to sound volume if player state is playing then repeat with i from mVolume to 0 by -1 set sound volume to i delay 0.1 end repeat end if stop if not (mNowTime < mEndTime) then delete mPlayTrack's every track -- Restore Playback Mode set sound volume to mVolume set shuffle enabled to false set song repeat to off -- Restore Main Window set mWindows to every window repeat with i in mWindows if i's name is not mMusicWindow then close i end repeat -- Quit Application quit end tell -- Error Exit on error mCaption number mErrorNumber tell me to activate if mErrorNumber = -129 then -- No playback data display dialog "There is no data to play." buttons {"OK"} default button 1 with icon 2 giving up after 5 tell application "Music" to quit else if mErrorNumber = -128 then -- Cancellation of processing display dialog "The process has been discontinued." buttons {"OK"} default button 1 with icon 0 giving up after 5 tell application "Music" to quit else -- Other Errors display dialog mCaption & return & "Error Number:" & mErrorNumber buttons {"OK"} default button 1 with icon 0 end if end try -- List Sorting on SortOfList(my_list) set index_list to {} set sorted_list to {} repeat (my_list's length) times set low_item to "*" repeat with i from 1 to (my_list's length) if i is not in index_list then set this_item to (my_list's item i) as string if low_item is "*" then set low_item to this_item set low_item_index to i else if this_item comes before low_item then set low_item to this_item set low_item_index to i end if end if end repeat set end of sorted_list to low_item set end of index_list to low_item_index end repeat return the sorted_list end SortOfList -- HH:MM:SS to Seconds on TimeToSeconds(hhmmss) set hh to (hhmmss's text from character 1 to character 2) as integer set mm to (hhmmss's text from character 4 to character 5) as integer set ss to (hhmmss's text from character 7 to character 8) as integer return (hh * hours + mm * minutes + ss) end TimeToSeconds -- Seconds to HH:MM:SS on SecondsToTime(ssNum) set hhStr to my ZeroPadding((ssNum div hours) as string, 2) set mmStr to my ZeroPadding((ssNum mod hours div minutes) as string, 2) set ssStr to my ZeroPadding((ssNum mod hours mod minutes) as string, 2) return hhStr & ":" & mmStr & ":" & ssStr end SecondsToTime -- Zero padding on ZeroPadding(aNum, aLen) do shell script "printf '%0" & aLen & "d' " & aNum end ZeroPadding -- String splitting on devText(theText, aDelimiter) set tmp to AppleScript's text item delimiters set AppleScript's text item delimiters to aDelimiter set theList to theText's every text item set AppleScript's text item delimiters to tmp return theList end devText -- Full-width and half-width conversion : Delete the first and last spaces on RepAndTrim(str) do shell script "osascript -l JavaScript <<'EOF' - " & str's quoted form & " 'use strict'; function run(argv) { return argv[0].replace(/\\uFF0A/g, '*').replace(/\\uFF0B/g, '+').replace(/\\u3000/g, ' ').trim(); } EOF" end RepAndTrim -- Custom Text search on TextSearch(mPlaylist, mText) tell application "Music" set mTracks to playlist (mPlaylist)'s every file track whose ¬ name contains mText or ¬ artist contains mText or ¬ album contains mText or ¬ album artist contains mText or ¬ genre contains mText or ¬ sort name contains mText or ¬ sort artist contains mText or ¬ sort album contains mText or ¬ sort album artist contains mText --composer contains mText or ¬ --sort composer contains mText or ¬ --lyrics contains mText or ¬ --comment contains mText or ¬ return mTracks end tell end TextSearch