music 5.66 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#!/usr/bin/env zsh

function music itunes() {
  local APP_NAME=Music sw_vers=$(sw_vers -productVersion 2>/dev/null)

  autoload is-at-least
  if [[ -z "$sw_vers" ]] || is-at-least 10.15 $sw_vers; then
    if [[ $0 = itunes ]]; then
      echo >&2 The itunes function name is deprecated. Use \'music\' instead.
      return 1
    fi
  else
    APP_NAME=iTunes
  fi

  local opt=$1 playlist=$2
  (( $# > 0 )) && shift
  case "$opt" in
    launch|play|pause|stop|rewind|resume|quit)
      ;;
    mute)
      opt="set mute to true"
      ;;
    unmute)
      opt="set mute to false"
      ;;
    next|previous)
      opt="$opt track"
      ;;
    vol)
      local new_volume volume=$(osascript -e "tell application \"$APP_NAME\" to get sound volume")
      if [[ $# -eq 0 ]]; then
        echo "Current volume is ${volume}."
        return 0
      fi
      case $1 in
        up) new_volume=$((volume + 10 < 100 ? volume + 10 : 100)) ;;
        down) new_volume=$((volume - 10 > 0 ? volume - 10 : 0)) ;;
        <0-100>) new_volume=$1 ;;
        *) echo "'$1' is not valid. Expected <0-100>, up or down."
           return 1 ;;
      esac
      opt="set sound volume to ${new_volume}"
      ;;
    playlist)
      # Inspired by: https://gist.github.com/nakajijapan/ac8b45371064ae98ea7f
      if [[ -n "$playlist" ]]; then
        osascript 2>/dev/null <<EOF
          tell application "$APP_NAME"
            set new_playlist to "$playlist" as string
            play playlist new_playlist
          end tell
EOF
        if [[ $? -eq 0 ]]; then
          opt="play"
        else
          opt="stop"
        fi
      else
        opt="set allPlaylists to (get name of every playlist)"
      fi
      ;;
    playing|status)
      local currenttrack currentartist state=$(osascript -e "tell application \"$APP_NAME\" to player state as string")
      if [[ "$state" = "playing" ]]; then
        currenttrack=$(osascript -e "tell application \"$APP_NAME\" to name of current track as string")
        currentartist=$(osascript -e "tell application \"$APP_NAME\" to artist of current track as string")
        echo -E "Listening to ${fg[yellow]}${currenttrack}${reset_color} by ${fg[yellow]}${currentartist}${reset_color}"
      else
        echo "$APP_NAME is $state"
      fi
      return 0
      ;;
    shuf|shuff|shuffle)
      # The shuffle property of current playlist can't be changed in iTunes 12,
      # so this workaround uses AppleScript to simulate user input instead.
      # Defaults to toggling when no options are given.
      # The toggle option depends on the shuffle button being visible in the Now playing area.
      # On and off use the menu bar items.
      local state=$1

      if [[ -n "$state" && "$state" != (on|off|toggle) ]]; then
        print "Usage: $0 shuffle [on|off|toggle]. Invalid option."
        return 1
      fi

      case "$state" in
        on|off)
          # Inspired by: https://stackoverflow.com/a/14675583
          osascript >/dev/null 2>&1 <<EOF
            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" )
EOF
          return 0
          ;;
        toggle|*)
          osascript >/dev/null 2>&1 <<EOF
            tell application "System Events" to perform action "AXPress" of (button 2 of process "iTunes"'s window "iTunes"'s scroll area 1)
EOF
          return 0
          ;;
      esac
      ;;
    ""|-h|--help)
      echo "Usage: $0 <option>"
      echo "option:"
      echo "\t-h|--help\tShow this message and exit"
      echo "\tlaunch|play|pause|stop|rewind|resume|quit"
      echo "\tmute|unmute\tMute or unmute $APP_NAME"
      echo "\tnext|previous\tPlay next or previous track"
      echo "\tshuf|shuffle [on|off|toggle]\tSet shuffled playback. Default: toggle. Note: toggle doesn't support the MiniPlayer."
      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."
      echo "\tplaying|status\tShow what song is currently playing in Music."
      echo "\tplaylist [playlist name]\t Play specific playlist"
      return 0
      ;;
    *)
      print "Unknown option: $opt"
      return 1
      ;;
  esac
  osascript -e "tell application \"$APP_NAME\" to $opt"
}

function _music() {
  local app_name
  case "$words[1]" in
    itunes) app_name="iTunes" ;;
    music|*) app_name="Music" ;;
  esac

  local -a cmds subcmds
  cmds=(
    "launch:Launch the ${app_name} app"
    "play:Play ${app_name}"
    "pause:Pause ${app_name}"
    "stop:Stop ${app_name}"
    "rewind:Rewind ${app_name}"
    "resume:Resume ${app_name}"
    "quit:Quit ${app_name}"
    "mute:Mute the ${app_name} app"
    "unmute:Unmute the ${app_name} app"
    "next:Skip to the next song"
    "previous:Skip to the previous song"
    "vol:Change the volume"
    "playlist:Play a specific playlist"
    {playing,status}":Show what song is currently playing"
    {shuf,shuff,shuffle}":Set shuffle mode"
    {-h,--help}":Show usage"
  )

  if (( CURRENT == 2 )); then
    _describe 'command' cmds
  elif (( CURRENT == 3 )); then
    case "$words[2]" in
      vol) subcmds=( 'up:Raise the volume' 'down:Lower the volume' )
        _describe 'command' subcmds ;;
      shuf|shuff|shuffle) subcmds=('on:Switch on shuffle mode' 'off:Switch off shuffle mode' 'toggle:Toggle shuffle mode (default)')
        _describe 'command' subcmds ;;
    esac
  elif (( CURRENT == 4 )); then
    case "$words[2]" in
      playlist) subcmds=('play:Play the playlist (default)' 'stop:Stop the playlist')
        _describe 'command' subcmds ;;
    esac
  fi

  return 0
}

compdef _music music itunes