1#!/usr/bin/env zsh 2 3function music itunes() { 4 local APP_NAME=Music sw_vers=$(sw_vers -productVersion 2>/dev/null) 5 6 autoload is-at-least 7 if [[ -z "$sw_vers" ]] || is-at-least 10.15 $sw_vers; then 8 if [[ $0 = itunes ]]; then 9 echo >&2 The itunes function name is deprecated. Use \'music\' instead. 10 return 1 11 fi 12 else 13 APP_NAME=iTunes 14 fi 15 16 local opt=$1 playlist=$2 17 (( $# > 0 )) && shift 18 case "$opt" in 19 launch|play|pause|stop|rewind|resume|quit) 20 ;; 21 mute) 22 opt="set mute to true" 23 ;; 24 unmute) 25 opt="set mute to false" 26 ;; 27 next|previous) 28 opt="$opt track" 29 ;; 30 vol) 31 local new_volume volume=$(osascript -e "tell application \"$APP_NAME\" to get sound volume") 32 if [[ $# -eq 0 ]]; then 33 echo "Current volume is ${volume}." 34 return 0 35 fi 36 case $1 in 37 up) new_volume=$((volume + 10 < 100 ? volume + 10 : 100)) ;; 38 down) new_volume=$((volume - 10 > 0 ? volume - 10 : 0)) ;; 39 <0-100>) new_volume=$1 ;; 40 *) echo "'$1' is not valid. Expected <0-100>, up or down." 41 return 1 ;; 42 esac 43 opt="set sound volume to ${new_volume}" 44 ;; 45 playlist) 46 # Inspired by: https://gist.github.com/nakajijapan/ac8b45371064ae98ea7f 47 if [[ -n "$playlist" ]]; then 48 osascript 2>/dev/null <<EOF 49 tell application "$APP_NAME" 50 set new_playlist to "$playlist" as string 51 play playlist new_playlist 52 end tell 53EOF 54 if [[ $? -eq 0 ]]; then 55 opt="play" 56 else 57 opt="stop" 58 fi 59 else 60 opt="set allPlaylists to (get name of every playlist)" 61 fi 62 ;; 63 playing|status) 64 local currenttrack currentartist state=$(osascript -e "tell application \"$APP_NAME\" to player state as string") 65 if [[ "$state" = "playing" ]]; then 66 currenttrack=$(osascript -e "tell application \"$APP_NAME\" to name of current track as string") 67 currentartist=$(osascript -e "tell application \"$APP_NAME\" to artist of current track as string") 68 echo -E "Listening to ${fg[yellow]}${currenttrack}${reset_color} by ${fg[yellow]}${currentartist}${reset_color}" 69 else 70 echo "$APP_NAME is $state" 71 fi 72 return 0 73 ;; 74 shuf|shuff|shuffle) 75 # The shuffle property of current playlist can't be changed in iTunes 12, 76 # so this workaround uses AppleScript to simulate user input instead. 77 # Defaults to toggling when no options are given. 78 # The toggle option depends on the shuffle button being visible in the Now playing area. 79 # On and off use the menu bar items. 80 local state=$1 81 82 if [[ -n "$state" && "$state" != (on|off|toggle) ]]; then 83 print "Usage: $0 shuffle [on|off|toggle]. Invalid option." 84 return 1 85 fi 86 87 case "$state" in 88 on|off) 89 # Inspired by: https://stackoverflow.com/a/14675583 90 osascript >/dev/null 2>&1 <<EOF 91 tell application "System Events" to perform action "AXPress" of (menu item "${state}" of menu "Shuffle" of menu item "Shuffle" of menu "Controls" of menu bar item "Controls" of menu bar 1 of application process "iTunes" ) 92EOF 93 return 0 94 ;; 95 toggle|*) 96 osascript >/dev/null 2>&1 <<EOF 97 tell application "System Events" to perform action "AXPress" of (button 2 of process "iTunes"'s window "iTunes"'s scroll area 1) 98EOF 99 return 0 100 ;; 101 esac 102 ;; 103 ""|-h|--help) 104 echo "Usage: $0 <option>" 105 echo "option:" 106 echo "\t-h|--help\tShow this message and exit" 107 echo "\tlaunch|play|pause|stop|rewind|resume|quit" 108 echo "\tmute|unmute\tMute or unmute $APP_NAME" 109 echo "\tnext|previous\tPlay next or previous track" 110 echo "\tshuf|shuffle [on|off|toggle]\tSet shuffled playback. Default: toggle. Note: toggle doesn't support the MiniPlayer." 111 echo "\tvol [0-100|up|down]\tGet or set the volume. 0 to 100 sets the volume. 'up' / 'down' increases / decreases by 10 points. No argument displays current volume." 112 echo "\tplaying|status\tShow what song is currently playing in Music." 113 echo "\tplaylist [playlist name]\t Play specific playlist" 114 return 0 115 ;; 116 *) 117 print "Unknown option: $opt" 118 return 1 119 ;; 120 esac 121 osascript -e "tell application \"$APP_NAME\" to $opt" 122} 123 124function _music() { 125 local app_name 126 case "$words[1]" in 127 itunes) app_name="iTunes" ;; 128 music|*) app_name="Music" ;; 129 esac 130 131 local -a cmds subcmds 132 cmds=( 133 "launch:Launch the ${app_name} app" 134 "play:Play ${app_name}" 135 "pause:Pause ${app_name}" 136 "stop:Stop ${app_name}" 137 "rewind:Rewind ${app_name}" 138 "resume:Resume ${app_name}" 139 "quit:Quit ${app_name}" 140 "mute:Mute the ${app_name} app" 141 "unmute:Unmute the ${app_name} app" 142 "next:Skip to the next song" 143 "previous:Skip to the previous song" 144 "vol:Change the volume" 145 "playlist:Play a specific playlist" 146 {playing,status}":Show what song is currently playing" 147 {shuf,shuff,shuffle}":Set shuffle mode" 148 {-h,--help}":Show usage" 149 ) 150 151 if (( CURRENT == 2 )); then 152 _describe 'command' cmds 153 elif (( CURRENT == 3 )); then 154 case "$words[2]" in 155 vol) subcmds=( 'up:Raise the volume' 'down:Lower the volume' ) 156 _describe 'command' subcmds ;; 157 shuf|shuff|shuffle) subcmds=('on:Switch on shuffle mode' 'off:Switch off shuffle mode' 'toggle:Toggle shuffle mode (default)') 158 _describe 'command' subcmds ;; 159 esac 160 elif (( CURRENT == 4 )); then 161 case "$words[2]" in 162 playlist) subcmds=('play:Play the playlist (default)' 'stop:Stop the playlist') 163 _describe 'command' subcmds ;; 164 esac 165 fi 166 167 return 0 168} 169 170compdef _music music itunes 171