#!/bin/zsh -i # zomg: ZOMG # Copyright (C) 2005, 2006, 2007, 2008 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ZOMG_VERSION="0.3.10" cat < 1 )) then exit 0 fi } #include audioscrobbler functions # audioscrobbler: ZOMG audioscrobbler functions # Copyright (C) 2005, 2006, 2007 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA audioscrobbler_handshake() { local username="$1" local password="$2" local -a http_headers local -a response local xferencoding tstamp authtoken tcp_open post.audioscrobbler.com 80 scrobbler || return 2 tstamp=$(export TZ=UTC; print ${EPOCHSECONDS}) local pwsum="$(print -n "${password}" | md5sum | awk '{print $1}')${tstamp}" authtoken="$(print -n "${pwsum}" | md5sum | awk '{print $1}')" tcp_send -s scrobbler -- "GET /?hs=true&p=1.2&c=zom&v=0.1&u=${username}&t=${tstamp}&a=${authtoken} HTTP/1.1" tcp_send -s scrobbler -- "Host: post.audioscrobbler.com" tcp_send -s scrobbler -- "Accept-Charset: utf-8" tcp_send -s scrobbler -- "" sleep 2 tcp_read -d -s scrobbler tcp_close -s scrobbler if [[ $tcp_lines[1] != "HTTP/1."[01]" 200 OK " ]]; then return 1 fi http_headers=(${tcp_lines[1,(r) ]}) xferencoding="${${http_headers[(r)Transfer-Encoding:*]}#Transfer-Encoding: }" case "$xferencoding" in (chunked*) startofbody=${tcp_lines[(i) ]} (( startofbody++ )) response=(${tcp_lines[startofbody,(r)0 ]}) ;; (*) response=(${tcp_lines[(r) ,-1]}) ;; esac local rstatus=${response[2]} case "$rstatus" in (OK) sessionid="${response[3]/ (#e)/}" npurl="$response[4]" submiturl="$response[5]" ;; (BANNED) print "Client is banned. Try getting a newer version at http://zomg.alioth.debian.org/" exit 1 ;; (BADAUTH) print "Bad authentication. Check your credentials in ~/.zomg/conf" exit 1 ;; (BADTIME) print "Time mismatch. Check your system clock." exit 1 ;; (FAILED *) print "FAILURE." print $rstatus return 1 ;; (*) print $rstatus what the fuck print '[[[' print -l ${http_headers} print ']]]' print '{{{' print -l ${response} print '}}}' return 1 ;; esac as_cache_credentials "$username" "$sessionid" "$npurl" "$submiturl" } as_cache_credentials() { print "Caching credentials for $1..." cat >~/.zomg/ascreds.${1} <> ~/.zomg/cache kill "${LOCK}" lockfile-remove ~/.zomg/cache } audioscrobbler_flushcache() { local username=$1 #unused local sid=$2 local i=0 local query LOCK local authinfo="&s=${sid}" submit=1 lockfile-create ~/.zomg/cache lockfile-touch ~/.zomg/cache & LOCK="$!" while read line do query+=${line//\[0\]/[$i]} if (( i==9 )); then if audioscrobbler_submit "$authinfo$query" "$username"; then : here, purge successful submissions else kill "${LOCK}" lockfile-remove ~/.zomg/cache return 1 fi query="" i=0 else (( i++ )) fi done < ~/.zomg/cache kill "${LOCK}" lockfile-remove ~/.zomg/cache (( i == 0 )) || { audioscrobbler_submit "$authinfo$query" "$username" || return 1 } return } #include urlparse functions # urlparse: ZOMG functions for parsing URLs returned by last.fm # Copyright (C) 2005, 2006, 2007 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA parse_submiturl() { if [[ "$submiturl" == http://(#b)(*):(*)/(*) ]]; then submithost=$match[1] submitport=$match[2] submitcgi=$match[3] else submithost=post.audioscrobbler.com submitport=80 submitcgi=/protocol_1.2 fi } parse_np_submiturl() { if [[ "$npurl" == http://(#b)(*):(*)/(*) ]]; then np_submithost=$match[1] np_submitport=$match[2] np_submitcgi=$match[3] else np_submithost=post.audioscrobbler.com np_submitport=80 np_submitcgi=/np_1.2 fi } #include parsemedium functions # parsemedium: ZOMG functions for parsing media files # Copyright (C) 2005, 2006, 2007 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA parse_ogginfo() { local output album artist mbid title len tstamp output=(${(f)"$(ogginfo $1)"}) album=${${(M)output:#(#i)*ALBUM=*}#(#i)*ALBUM=} artist=${${(M)output:#(#i)*ARTIST=*}#(#i)*ARTIST=} mbid=${${(M)output:#(#i)*MUSICBRAINZ_TRACKID=*}#(#i)*MUSICBRAINZ_TRACKID=} title=${${(M)output:#(#i)*TITLE=*}#(#i)*TITLE=} len=${${(M)output:#*Playback length:*}#*Playback length: } if [[ "$len" == (#b)([0-9]##)m:([0-9.]##)s ]] then (( len = $match[1] * 60 + $match[2] + 1 )) else (( len = 0 )) fi typeset -i len tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" ${EPOCHSECONDS}) reply=("${artist}" "${title}" "${album}" "${mbid}" "${len}") } parse_zomghelper() { local output album artist mbid title len tstamp output=(${(f)"$(zomghelper $1)"}) album=${${(M)output:#(#i)ALBUM=*}#(#i)ALBUM=} artist=${${(M)output:#(#i)ARTIST=*}#(#i)ARTIST=} mbid=${${(M)output:#(#i)MUSICBRAINZ_TRACKID=*}#(#i)MUSICBRAINZ_TRACKID=} title=${${(M)output:#(#i)TITLE=*}#(#i)TITLE=} len=${${(M)output:#ZOMGSECS:*}#ZOMGSECS: } typeset -i len tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" ${EPOCHSECONDS}) reply=("${artist}" "${title}" "${album}" "${mbid}" "${len}") } parse_eyeD3() { local output album artist mbid title len tstamp output=(${(f)"$(eyeD3 --no-color $1)"}) album=${${${(M)output:#album: *}#album: }%% *} artist=${${(M)output:#* artist: *}#* artist: } mbid=${${(M)output:#Unique File ID: \[http://musicbrainz.org\] *}#Unique File ID: \[http://musicbrainz.org\] } title=${${${(M)output:#title: *}#title: }%% *} len=${${(M)output:#Time: *}#Time: } if [[ "$len" == (#b)([0-9]##):([0-9]##):([0-9]##)[^0-9]* ]] then (( len = $match[1] * 3600 + $match[2] * 60 + $match[3] + 1 )) elif [[ "$len" == (#b)([0-9]##):([0-9]##)[^0-9]* ]] then (( len = $match[1] * 60 + $match[2] + 1 )) else (( len = 0 )) fi typeset -i len tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" ${EPOCHSECONDS}) reply=("${artist}" "${title}" "${album}" "${mbid}" "${len:-0}") } parse_mutagen() { local output album artist mbid title len tstamp output=(${(f)"$(mutagen-inspect --no-apev2 --no-flac $1)"}) album=${${(M)output:#TALB=*}#TALB=} artist=${${(M)output:#TPE1=*}#TPE1=} mbid=${${(M)output:#UFID=http://musicbrainz.org=*}#UFID=http://musicbrainz.org=} title=${${(M)output:#TIT2=*}#TIT2=} len=${${(M)output:#- MPEG*seconds*}/- MPEG*(#b) ([0-9.]##) seconds*/$match[1]} typeset -i len tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" ${EPOCHSECONDS}) reply=("${artist}" "${title}" "${album}" "${mbid}" "${len:-0}") [[ "${len}" -eq 0 ]] && return 1 || return 0 } parse_mutagenflac() { local output album artist mbid title len tstamp output=(${(f)"$(mutagen-inspect --no-apev2 --no-mp3 $1)"}) album=${${(M)output:#album=*}#album=} artist=${${(M)output:#artist=*}#artist=} mbid=${${(M)output:#musicbrainz_trackid=*}#musicbrainz_trackid=} title=${${(M)output:#title=*}#title=} len=${${(M)output:#- FLAC,*seconds*Hz*}/- FLAC,(#b) ([0-9.]##) seconds*/$match[1]} typeset -i len tstamp=$(export TZ=UTC; strftime "%Y-%m-%d %H:%M:%S" ${EPOCHSECONDS}) reply=("${artist}" "${title}" "${album}" "${mbid}" "${len}") } #include shuffle functions # shuffle: ZOMG functions for shuffling tracks # Copyright (C) 2005, 2006, 2007 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA zomg_shuffle() { declare -A h local +h -Z 5 RANDOM=$EPOCHSECONDS integer i for ((i=1; i <= $#; ++i)) { h[$i.$RANDOM]=$argv[i] } reply=( $h ) } #include lastfmradio functions # lastfmradio: ZOMG last.fm radio functions # Copyright (C) 2005, 2006, 2007, 2008 Clint Adams # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA lastfm_get_np() { local lastfm_session="$1" debug="$2" local -a np local station artist album track trackduration trackprogress np=( ${(f)"$(wget -q --output-document=- http://${baseurl}${basepath}/np.php\?session=${lastfm_session}\&debug=0)"} ) if [[ $debug -eq 1 ]]; then print ">NP<" print "$np" print ">NP<" fi station=${${(M)np:#station=*}#station=} artist=${${(M)np:#artist=*}#artist=} album=${${(M)np:#album=*}#album=} track=${${(M)np:#track=*}#track=} trackduration=${${(M)np:#trackduration=*}#trackduration=} trackprogress=${${(M)np:#trackprogress=*}#trackprogress=} (( timeleft = trackduration - trackprogress )) print "" print "Station: ${station}" print "Artist: ${artist}" print "Album: ${album}" print "Track: ${track}" print "Length: ${trackduration} seconds" print "" if (( timeleft == 0 )); then (( timeleft = 10 )); fi } lastfm_quit() { if [[ -z "$BUFFER" ]]; then BUFFER="q" zle .accept-line fi } lastfm_tune() { local lastfm_session="$1" station="$2" local tunestatus print -n "Tuning to $station... " tunestatus=$(wget -q --output-document=- "http://${baseurl}${basepath}/adjust.php?session=${lastfm_session}&url=${station}&debug=0") print "$tunestatus" } lastfm_radio_getplaylist() { local session="$1" local i wget -q -O ~/.zomg/radio_playlist.xspf "http://ws.audioscrobbler.com/radio/xspf.php?sk=${session}&discovery=0&desktop=1.3.0.58" || return 99 zomghelper-xspf ~/.zomg/radio_playlist.xspf > ~/.zomg/radio_playlist || return 98 unset zomg_xspf_location zomg_xspf_title zomg_xspf_id zomg_xspf_album unset zomg_xspf_creator zomg_xspf_duration zomg_xspf_image for i in ${(f)"$(<~/.zomg/radio_playlist)"} do case "$i" in ((#b)([^=]##)\[([0-9]##)\]=(*)) eval zomg_xspf_$match[1]\[$match[2]\]="${(q)match[3]}" ;; ((#b)([^=]##)=(*)) eval zomg_xspf_$match[1]="${(q)match[2]}" ;; (*) ;; esac done if [[ -z $zomg_xspf_location ]]; then print Empty playlist, quitting. return 99 fi print Parsed radio playlist $zomg_xspf_playlist_title by $zomg_xspf_playlist_creator. for i in {1..${#zomg_xspf_location}} do print $i. $zomg_xspf_creator[$i] / $zomg_xspf_title[$i] done } lastfm_playfive() { local lastfm_session="$1" lastfm_radio_getplaylist "$lastfm_session" || exit 99 for currenttrack in {1..${#zomg_xspf_location}} do audioscrobbler_construct_np_query "$LASTFM_USER" "$sessionid" \ "$zomg_xspf_creator[$currenttrack]" "$zomg_xspf_title[$currenttrack]" \ "$zomg_xspf_album[$currenttrack]" "" \ ${${zomg_xspf_duration[$currenttrack]}/000(#e)/} "$EPOCHSECONDS" && \ audioscrobbler_np_submit ${(j::)reply} "$LASTFM_USER" print "Now playing $zomg_xspf_creator[$currenttrack] / $zomg_xspf_title[$currenttrack] / $zomg_xspf_album[$currenttrack]" starttime=$EPOCHSECONDS # "$mp3streamer[@]" $zomg_xspf_location[$currenttrack] >/dev/null 2>&1 & "$mp3streamer[@]" $zomg_xspf_location[$currenttrack] endtime=$EPOCHSECONDS skip=0 (( endtime - starttime <= (${${zomg_xspf_duration[$currenttrack]}/000(#e)/} / 2.0 ) )) && (( endtime - starttime < 240 )) && skip=1 (( ${${zomg_xspf_duration[$currenttrack]}/000(#e)/} < 30 )) && skip=1 if [[ $skip -eq 1 ]]; then print "SKIPPING" skip=0 else audioscrobbler_constructquery "$sessionid" \ "$zomg_xspf_creator[$currenttrack]" "$zomg_xspf_title[$currenttrack]" \ "$zomg_xspf_album[$currenttrack]" "" \ "${${zomg_xspf_duration[$currenttrack]}/000(#e)/}" "$starttime" \ L"$zomg_xspf_lastfm_trackauth[$currenttrack]" && audioscrobbler_submit ${(j::)reply} "$LASTFM_USER" || { submit=0; audioscrobbler_cache "$reply[2]" } fi done } lastfm_radio() { local station="$1" local passwordmd5=${${="$(print -n $LASTFM_PASSWORD | md5sum)"}[1]} local -a handshake local lastfm_session streamurl radiocmd streamstate local baseurl basepath handshake=( ${(f)"$(wget -q --output-document=- http://ws.audioscrobbler.com/radio/handshake.php\?version=1.3.0.58\&platform=linux\&username=${LASTFM_USER}\&passwordmd5=${passwordmd5}\&language=en)"} ) lastfm_session=${${(M)handshake:#session=*}#session=} streamurl=${${(M)handshake:#stream_url=*}#stream_url=} baseurl=${${${(M)handshake:#base_url=*}#base_url=}:-ws.audioscrobbler.com} basepath=${${${(M)handshake:#base_path=*}#base_path=}:-/radio} if [[ -n "$lastfm_session" && "$lastfm_session" != FAILED ]]; then print "Connecting to Last.fm session ${lastfm_session}" print "at $streamurl" else print "Handshake failed" exit 47 fi if [[ -n "$station" && "$station" == lastfm://* ]]; then lastfm_tune $lastfm_session $station fi unset HISTFILE HISTSIZE=512 SAVEHIST=512 setopt histignorealldups history -ap ~/.zomg/lastfm_history if [[ -x =mpg123 ]]; then mp3streamer=(mpg123 -b 2048 -q) else mp3streamer=(mplayer -quiet -noconsolecontrols -cache 2048 -cache-min 1) fi lastfm_playfive "$lastfm_session" print "Either tune to a new station or type 'p' to play a few more songs." zle -N lastfm_quit bindkey '^D' lastfm_quit autoload -U compinit compinit bindkey '^I' _history-complete-older while true do [[ $#jobstates -eq 1 ]] && streamstate="" || streamstate="[broken] " radiocmd="" vared -hp "${streamstate}last.fm $LASTFM_USER $timeleft> " radiocmd print -s $radiocmd case "$radiocmd" in (h) print "h: help" # print "n: show what's playing now" print "q: quit" # print "s: skip" print "p: play another five songs from the same station" print "t lastfm:// : tune to another radio station" print "tu : shortcut to tune to lastfm://user//personal" print "tl : shortcut to tune to lastfm://user//loved" print "tn : shortcut to tune to lastfm://user//neighbours" # print "love: mark this track as loved" # print "ban: ban this track" # print "discovery : turn discovery mode on or off" # print "rtp: turn scrobbling on" # print "nortp: turn scrobbling off" ;; # (n) # lastfm_get_np "${lastfm_session}" 0 # ;; # (ndebug) # lastfm_get_np "${lastfm_session}" 1 # ;; (q|exit) kill %2 exit 0 ;; # (s) # print "Skipping... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=skip&debug=0") # lastfm_get_np "${lastfm_session}" 0 # ;; (p) lastfm_playfive "${lastfm_session}" ;; (t (#b)(lastfm://[^ ]##)) lastfm_tune ${lastfm_session} $match[1] lastfm_playfive "${lastfm_session}" # lastfm_get_np "${lastfm_session}" 0 ;; (tu (#b)([^ ]##)) lastfm_tune ${lastfm_session} lastfm://user/$match[1]/personal lastfm_playfive "${lastfm_session}" # lastfm_get_np "${lastfm_session}" 0 ;; (tl (#b)([^ ]##)) lastfm_tune ${lastfm_session} lastfm://user/$match[1]/loved lastfm_playfive "${lastfm_session}" # lastfm_get_np "${lastfm_session}" 0 ;; (tn (#b)([^ ]##)) lastfm_tune ${lastfm_session} lastfm://user/$match[1]/neighbours lastfm_playfive "${lastfm_session}" # lastfm_get_np "${lastfm_session}" 0 ;; # (love) # print "Loving... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=love&debug=0") # ;; # (ban) # print "Banning... " $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=ban&debug=0") # ;; # (discovery (#b)(on|off)) # print "Turning discovery ${match[1]}..." $(wget -q --output-document=- "http://${baseurl}${basepath}/adjust.php?session=${lastfm_session}&url=lastfm://settings/discovery/${match[1]}&debug=0") # ;; # ((#b)(rtp|nortp)) # print "Setting ${match[1]}..." $(wget -q --output-document=- "http://${baseurl}${basepath}/control.php?session=${lastfm_session}&command=${match[1]}") # ;; (*) print "WTF?! Try 'h' for help" ;; esac done } if [[ ! -d ~/.zomg ]]; then mkdir ~/.zomg || exit 9 fi local starttime=0 endtime=0 filetype shuffle=0 dolastfmradio=0 nonet=0 totes=0 skip=0 [[ -d /usr/lib/zomg ]] && PATH="$PATH:/usr/lib/zomg" while getopts "nrtzh" opt; do case "$opt" in (z) shuffle=1 ;; (r) dolastfmradio=1 ;; (n) nonet=1 ;; (h) cat < 1 )) && shift $(( OPTIND - 1 )) LASTFM_USER="" LASTFM_PASSWORD="" if [[ ! -f ~/.zomg/conf ]]; then vared -p "last.fm username> " LASTFM_USER vared -p "last.fm password> " LASTFM_PASSWORD printf 'LASTFM_USER="%s"\nLASTFM_PASSWORD="%s"\n' \ "${LASTFM_USER}" "${LASTFM_PASSWORD}" >~/.zomg/conf fi [[ -r ~/.zomg/conf ]] || exit 12 source ~/.zomg/conf if (( nonet == 0 )); then if [[ -f ~/.zomg/cache ]]; then if as_validate_handshake $LASTFM_USER $LASTFM_PASSWORD then parse_submiturl parse_np_submiturl print Flushing cache... audioscrobbler_flushcache $LASTFM_USER $sessionid && { submit=1; mv ~/.zomg/cache ~/.zomg/cache.old } || { submit=0; as_invalidate_handshake $LASTFM_USER } else print HANDSHAKE FAILED submit=0 as_invalidate_handshake $LASTFM_USER fi else submit=1 as_validate_handshake $LASTFM_USER $LASTFM_PASSWORD && parse_submiturl && parse_np_submiturl || submit=0 fi else print "Not handshaking." submit=0 fi if (( dolastfmradio == 1 )); then print Connecting to Last.fm radio lastfm_radio "$@" exit 0 else trap 'skippy' INT [[ $# -gt 0 ]] || { print "No arguments; exiting."; exit 0 } if (( totes == 1 )); then for i in "$@" do [[ -d "$i" ]] && playlist+=( $i/**/*.(ogg|mp3|flac) ) done else playlist=("$@") fi if (( shuffle == 1 )); then print Shuffling $#playlist files... zomg_shuffle $playlist set -- "$reply[@]" else set -- "$playlist[@]" fi for i in "$@" do if [[ ! -r "$i" ]]; then print "Cannot read file: $i; skipping" continue fi case "$i" in (*.ogg) # assume vorbis [[ -x =zomghelper ]] && parse_zomghelper $i || parse_ogginfo $i trackreply=("$reply[@]") audioscrobbler_construct_np_query $LASTFM_USER $sessionid "$reply[1]" \ "$reply[2]" \ "$reply[3]" \ "$reply[4]" \ "$reply[5]" \ "$EPOCHSECONDS" && audioscrobbler_np_submit ${(j::)reply} "$LASTFM_USER" starttime=$EPOCHSECONDS ogg123 --audio-buffer 2048 -v $i endtime=$EPOCHSECONDS ;; (*.mp3) [[ -x =mutagen-inspect ]] && parse_mutagen $i || parse_eyeD3 $i trackreply=("$reply[@]") audioscrobbler_construct_np_query $LASTFM_USER $sessionid "$reply[1]" \ "$reply[2]" \ "$reply[3]" \ "$reply[4]" \ "$reply[5]" \ "$EPOCHSECONDS" && audioscrobbler_np_submit ${(j::)reply} "$LASTFM_USER" starttime=$EPOCHSECONDS mpg123 -C -v $i endtime=$EPOCHSECONDS ;; (*.flac) parse_mutagenflac $i trackreply=("$reply[@]") audioscrobbler_construct_np_query $LASTFM_USER $sessionid "$reply[1]" \ "$reply[2]" \ "$reply[3]" \ "$reply[4]" \ "$reply[5]" \ "$EPOCHSECONDS" && audioscrobbler_np_submit ${(j::)reply} "$LASTFM_USER" starttime=$EPOCHSECONDS ogg123 --audio-buffer 2048 -v $i endtime=$EPOCHSECONDS ;; (*) print "Unknown file extension: $i" >&2 continue ;; esac (( ctrlc >= 1 )) && (( ctrlc = 0 )) print Played for $(( endtime - starttime )) secs out of $trackreply[5] secs. (( endtime - starttime <= ($trackreply[5] / 2.0 ) )) && (( endtime - starttime < 240 )) && skip=1 (( $trackreply[5] < 30 )) && skip=1 [[ -n "$trackreply[1]" && -n "$trackreply[2]" ]] || skip=1 if [[ $skip -eq 1 ]]; then print "SKIPPING" skip=0 else audioscrobbler_constructquery "$sessionid" "$trackreply[1]" \ "$trackreply[2]" \ "$trackreply[3]" \ "$trackreply[4]" \ "$trackreply[5]" \ "$starttime" P || exit 2 audioscrobbler_submit ${(j::)reply} "$LASTFM_USER" || { submit=0; audioscrobbler_cache $reply[2] } fi done fi