plait/plait0000700000076500007650000010246311063223530014735 0ustar sjungelssjungels00000000000000#! /bin/sh # Plait -- Search music library or Shoutcast radio streams and make # one of the supported music players play the results. # # Copyright (C) 2005-200* Stephen Jungels # # # 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. # # See COPYING for the full text of the license. # # See README for supported platforms and installation instructions. # # To contact the author: sjungels@gmail.com usage () { echo "Usage is:" echo " \"plait [[not] ]...[as ]\", or" echo " \"plait --stream [[not] ]...\"" echo "Options:" echo " --list,-l -- show matching tracks but don't play" echo " --mix,-m -- play tracks matching any hint (make a mix)" echo " --queue,-q -- add tracks to queue" echo " --random,-r -- play in random order" echo " --sort -- play in sorted order" echo " --stripe -- play in alternating order" echo " --stripe2 -- play in random alternating order" echo " --fade -- play in gaussian fade order" echo " --group -- play randomly in groups" echo " --tracks,-t -- play n tracks, if possible" echo " --stream,-s -- play Shoutcast radio streams" echo " --mixfile,-f -- read hints from mixfile" echo " --device,-d -- choose target device" echo " --platform -- choose platform" echo " --coverart -- cover art mode (0 or 1)" echo " --guest,-g -- use guest configuration" echo " --interactive,-i -- interactive mode" echo " --cache,-c -- rebuild cache" echo " --install -- install Plait" echo " --uninstall -- uninstall Plait" echo " --play " echo " --pause " echo " --stop " echo " --next " echo " --prev " echo " --help -- show help" echo " --version -- show version" } version () { echo "Plait v 1.6.2" echo "Written by Stephen Jungels (http://stephenjungels.com/contact)" echo "" echo "Copyright (c) 2005-2008 by Stephen Jungels. Released under the GPL." echo "Latest version and more info at http://plait.sourceforge.net/" } create_winamp_scripts () { if ! test -f "$HOME/.plait/commands/cmd-play.vbs" then echo 1>&2 Installing Winamp scripts mkdir -p "$HOME/.plait/commands" PLAYLIST="`cygpath -aw \"$HOME/.plait/playlist2.m3u\"`" cat > "$HOME/.plait/commands/play.vbs" < "$HOME/.plait/commands/queue.vbs" < "$HOME/.plait/commands/cmd-play.vbs" < "$HOME/.plait/commands/cmd-pause.vbs" < "$HOME/.plait/commands/cmd-stop.vbs" < "$HOME/.plait/commands/cmd-next.vbs" < "$HOME/.plait/commands/cmd-prev.vbs" <&2 Installing iTunes scripts mkdir -p "$HOME/.plait/commands" PLAYLIST="`cygpath -am \"$HOME/.plait/playlist2.m3u\"`" cat > "$HOME/.plait/commands/itunes-play.js" < "$HOME/.plait/commands/itunes-queue.js" < "$HOME/.plait/commands/itunes-cmd-play.js" < "$HOME/.plait/commands/itunes-cmd-pause.js" < "$HOME/.plait/commands/itunes-cmd-stop.js" < "$HOME/.plait/commands/itunes-cmd-next.js" < "$HOME/.plait/commands/itunes-cmd-prev.js" </dev/null /etc/motd if test $? = 0 then INSTALLDIR=/usr/local else INSTALLDIR="$HOME" fi else if test $(id -u) = 0 then INSTALLDIR=/usr/local else INSTALLDIR="$HOME" fi fi fi echo Installing in $INSTALLDIR mkdir -p $INSTALLDIR/bin mkdir -p $INSTALLDIR/share/man/man1 mkdir -p $INSTALLDIR/share/plait mkdir -p $INSTALLDIR/share/doc/plait if test -f plait then sed "s:%INSTALLDIR%:$INSTALLDIR:g" plait > $INSTALLDIR/bin/plait chmod +x $INSTALLDIR/bin/plait fi if test -f plait.1 then cp plait.1 $INSTALLDIR/share/man/man1 fi if test -f plaiter then cp plaiter $INSTALLDIR/bin fi if test -f plaiter.1 then cp plaiter.1 $INSTALLDIR/share/man/man1 fi if test -f querystream.awk then cp querystream.awk $INSTALLDIR/share/plait fi if test -f postprocess.awk then cp postprocess.awk $INSTALLDIR/share/plait fi if test -f device.awk then cp device.awk $INSTALLDIR/share/plait fi if test -f interactive.awk then cp interactive.awk $INSTALLDIR/share/plait fi if test -f interactivestream.awk then cp interactivestream.awk $INSTALLDIR/share/plait fi if test -f robots.awk then cp robots.awk $INSTALLDIR/share/plait fi if test -f xspf.awk then cp xspf.awk $INSTALLDIR/share/plait fi if test -f treecopy.awk then cp treecopy.awk $INSTALLDIR/share/plait fi if test -f coverart.awk then cp coverart.awk $INSTALLDIR/share/plait fi if test -f playlist.html then cp playlist.html $INSTALLDIR/share/plait fi if test -f README then cp README $INSTALLDIR/share/doc/plait fi if test -f README.plaiter then cp README.plaiter $INSTALLDIR/share/doc/plait fi if test -f COPYING then cp COPYING $INSTALLDIR/share/doc/plait fi if test -f INSTALL then cp INSTALL $INSTALLDIR/share/doc/plait fi # always force rewrite of scripts rm -f "$HOME/.plait/commands/itunes-cmd-play.js" rm -f "$HOME/.plait/commands/cmd-play.vbs" # clean up junk from old versions of plait rm -fr /etc/plait echo "1.6.2" > $INSTALLDIR/share/plait/version } uninstall () { echo Uninstall "plait"\? Type "yes" to continue, "no" to cancel. read yes if test "-$yes-" = "-yes-" then rm -fr $INSTALLDIR/share/plait if test $? != 0 then echo You need root privileges to uninstall, try su or sudo exit 1 fi rm -fr $INSTALLDIR/share/doc/plait rm -f $INSTALLDIR/share/man/man1/plait.1 rm -f $INSTALLDIR/share/man/man1/plaiter.1 rm -f $INSTALLDIR/bin/plait rm -f $INSTALLDIR/bin/plaiter echo Uninstall complete. else echo Uninstall cancelled fi } docache () { echo 1>&2 Caching music directory $MUSICDIR/$SUBDIR if test "-$SUBDIR-" = "--" then rm -f "$HOME/.plait/$CACHE" dir="$MUSICDIR" else touch "$HOME/.plait/$CACHE" dir="$MUSICDIR/$SUBDIR" cat "$HOME/.plait/$CACHE" | grep -v "$dir" > "$HOME/.plait/cache2" mv "$HOME/.plait/cache2" "$HOME/.plait/$CACHE" fi if test -d "$dir" then eval "find \"$dir\" -follow -type f" >> "$HOME/.plait/$CACHE" sort "$HOME/.plait/$CACHE" | uniq > "$HOME/.plait/$CACHE-tmp" mv "$HOME/.plait/$CACHE-tmp" "$HOME/.plait/$CACHE" else echo 1>&2 The directory $dir was not found fi touch "$HOME/.plait/$CACHE" } querylibrary () { rm -f "$HOME/.plait/mixfile" OUTMIXFILE=mix0 QUERY="" NOTQUERY="" bar="" awkhints="" colons="" while test $# -gt 0 do if test "-$1-" = "-as-" && ! test "-$2-" = "--" && test "-$bar-" = "-|-" then OUTMIXFILE=`echo "$2" | sed "s/ /-/g"` shift; shift elif test "-$1-" = "-not-" && ! test "-$2-" = "--" && test "-$bar-" = "-|-" then NOTQUERY="$NOTQUERY | grep -Eiv \"$2\"" echo "not \"$2\"" >> "$HOME/.plait/mixfile" shift; shift else if test $MIX = 1 || test "-$colons-" = "--" then awkhints="${awkhints}${colons}$1" colons="::" fi if test $MIX = 0 then QUERY="$QUERY | grep -Ei \"$1\"" else QUERY="${QUERY}${bar}$1" fi echo "\"$1\"" >> "$HOME/.plait/mixfile" shift fi bar="|" done if test $MIX = 1 then QUERY="| grep -Ei \"$QUERY\"" fi eval cat "$HOME/.plait/$CACHE" $QUERY $NOTQUERY > "$HOME/.plait/playlist.m3u" if test -e "$HOME/.plait/mixfile" && test -d "$MUSICDIR" then sort "$HOME/.plait/mixfile" | uniq > "$MUSICDIR/.plait/mixfiles/$OUTMIXFILE" fi # select device-appropriate tracks awk -f $INSTALLDIR/share/plait/device.awk types="$DEVICE" \ "$HOME/.plait/playlist.m3u" > "$HOME/.plait/playlist0.m3u" # optionally process the list interactively if test $INTERACTIVE = 1 then awk -f $INSTALLDIR/share/plait/interactive.awk prefix="$MUSICDIR/" levelsep="$LEVELSEP" \ "$HOME/.plait/playlist0.m3u" > "$HOME/.plait/playlist.m3u" mv "$HOME/.plait/playlist.m3u" "$HOME/.plait/playlist0.m3u" fi # balance and sort if test $ORDER = "sort" then awk -f $INSTALLDIR/share/plait/postprocess.awk hints="$awkhints" order=$ORDER tracks=$TRACKS \ "$HOME/.plait/playlist0.m3u" state=2 "$HOME/.plait/playlist0.m3u" \ > "$HOME/.plait/playlist.m3u" else awk -f $INSTALLDIR/share/plait/postprocess.awk hints="$awkhints" order=$ORDER tracks=$TRACKS \ "$HOME/.plait/playlist0.m3u" state=2 "$HOME/.plait/playlist0.m3u" \ | sort -n | cut -f "2-" > "$HOME/.plait/playlist.m3u" fi } querystream () { wget >/dev/null 2>&1 -O "$HOME/.plait/robots.txt" -r \ -U "Plait \(http://plait.sourceforge.net/bot.html\)" \ "http://classic.shoutcast.com/robots.txt" if test -f "$HOME/.plait/robots.txt" then ok=`cat "$HOME/.plait/robots.txt" | awk -f $INSTALLDIR/share/plait/robots.awk` if test $ok = "NOT OK" then echo 1>&2 "The Plait bot was excluded by Shoutcast's robots.txt file, exiting" exit 1 fi fi if test $MIX = 0 then wget >/dev/null 2>&1 -O "$HOME/.plait/shoutcast.html" \ -U "Plait (http://plait.sourceforge.net/bot.html)" \ "http://classic.shoutcast.com/directory/?s=$HINT1&numresult=100&orderby=listeners" else rm -f "$HOME/.plait/shoutcast.html" fi awkhints="" space="" while test $# -gt 0 do awkhints="${awkhints}${space}`echo "$1" | sed "s/ /_/g"`" space=" " if test $MIX = 1 then if test "-$1-" = "-not-" && ! test "-$2-" = "--" then shift awkhints="${awkhints}${space}`echo "$1" | sed "s/ /_/g"`" else wget >/dev/null 2>&1 -O "$HOME/.plait/shoutcast2.html" \ -U "Plait (http://plait.sourceforge.net/bot.html)" \ "http://classic.shoutcast.com/directory/?s=$1&numresult=100&orderby=listeners" cat "$HOME/.plait/shoutcast2.html" >> "$HOME/.plait/shoutcast.html" fi fi shift done awk -f $INSTALLDIR/share/plait/querystream.awk hints="$awkhints" mix=$MIX interactive=$INTERACTIVE \ "$HOME/.plait/shoutcast.html" > "$HOME/.plait/playlist.m3u" # optionally process the list interactively if test $INTERACTIVE = 1 then awk -f $INSTALLDIR/share/plait/interactivestream.awk \ "$HOME/.plait/playlist.m3u" > "$HOME/.plait/playlist0.m3u" mv "$HOME/.plait/playlist0.m3u" "$HOME/.plait/playlist.m3u" fi if test $ORDER = "random" then tmpfile="$(mktemp /tmp/plait.XXXXXX)" cat "$HOME/.plait/playlist.m3u" | awk 'BEGIN{srand()} {print rand() "\t" $0}' | \ sort -n | cut -f "2-" > $tmpfile mv $tmpfile "$HOME/.plait/playlist.m3u" fi # trim the playlist if it has not been edited interactively if test $INTERACTIVE = 0 then tmpfile="$(mktemp /tmp/plait.XXXXXX)" head -n $TRACKS > $tmpfile "$HOME/.plait/playlist.m3u" mv $tmpfile "$HOME/.plait/playlist.m3u" fi } listmixfiles () { if test -d "$MUSICDIR" then echo Mixfiles available: mkdir -p "$MUSICDIR/.plait/mixfiles" rm -f "$MUSICDIR/.plait/mixfiles/*~" ls "$MUSICDIR/.plait/mixfiles" else echo 1>&2 The music directory is unavailable fi } prefetch_stream_urls () { rm -f "$HOME/.plait/playlists.pls" cat "$HOME/.plait/playlist.m3u" | grep -i "^http" | awk \ '{ print "wget >/dev/null 2>&1 -O \"$HOME/.plait/playlist.pls\" \"" \ $0 "\"; cat \"$HOME/.plait/playlist.pls\" >> \"$HOME/.plait/playlists.pls\""}' \ > "$HOME/.plait/xme" . "$HOME/.plait/xme" # make sure there is a trailing slash, for mpg321: cat "$HOME/.plait/playlists.pls" | awk 'BEGIN {FS="="} \ /File1/ {if ($2 ~ /\/$/) print $2; else print $2 "/"}' \ > "$HOME/.plait/playlist2.m3u" } translate_to_windows_file_paths_old () { # translate to windows file paths. cygpath is very slow, so # run it just once for the top two directories (enough to # cover /cygdrive/c), then do a simple replace for the rest of # each file path root="`head -n 1 \"$HOME/.plait/playlist.m3u\" | awk \ '{match($0, "/*[^/]*/[^/]*/"); print substr($0, RSTART, RLENGTH)}'`" root="`cygpath -am $root`" tmpfile="$(mktemp /tmp/plait.XXXXXX)" cat "$HOME/.plait/playlist.m3u" | awk > $tmpfile -v r="$root" \ 'BEGIN { if (r !~ /\/$/) r = r "/"; gsub (/\//, "\\", r) } \ { s = $0; sub ("^/*[^/]*/[^/]*/", "", s); gsub (/\//, "\\", s); print r s}' mv $tmpfile "$HOME/.plait/playlist2.m3u" } translate_to_windows_file_paths () { if test $SLOW_PATH_TRANSLATION = 1 then cat "$HOME/.plait/playlist.m3u" | xargs > "$HOME/.plait/playlist2.m3u" -i cygpath -am "{}" else root="`cygpath -am \"$MUSICDIR\"`" tmpfile="$(mktemp /tmp/plait.XXXXXX)" cat "$HOME/.plait/playlist.m3u" | awk > $tmpfile -v r="$root" -v d="$MUSICDIR" \ 'BEGIN {if (r !~ /\/$/) r = r "/"; gsub (/\//, "\\", r)} \ {s = $0; sub (d "/", "", s); gsub (/\//, "\\", s); print r s}' mv $tmpfile "$HOME/.plait/playlist2.m3u" fi } prefetch_or_copy () { hasurl=`grep -ci http "$HOME/.plait/playlist.m3u"` if test $hasurl -gt 0 then prefetch_stream_urls else cp "$HOME/.plait/playlist.m3u" "$HOME/.plait/playlist2.m3u" fi } prefetch_or_translate () { hasurl=`grep -ci http "$HOME/.plait/playlist.m3u"` if test $hasurl = 0 then translate_to_windows_file_paths else prefetch_stream_urls fi } translate_or_copy () { hasurl=`grep -ci http "$HOME/.plait/playlist.m3u"` if test $hasurl = 0 then translate_to_windows_file_paths else cp "$HOME/.plait/playlist.m3u" "$HOME/.plait/playlist2.m3u" fi } CYGWIN=`uname -s | grep -ic CYGWIN` DARWIN=`uname -s | grep -ic Darwin` LINUX=`uname -s | grep -ic Linux` INSTALLDIR="%INSTALLDIR%" # file types and devices TYPES=".mp3 .wav .flac .aif .aiff .ogg" compact="mp3 MP3" medium="mp3 MP3 ogg OGG wav WAV flac FLAC aif AIF aiff AIFF" hifi="wav WAV flac FLAC aif AIF aiff AIFF mp3 MP3 ogg OGG" DEVICE="$hifi" SETDEVICE="" # option flags SHOW=0 QUEUE=0 ORDER="sort" SETORDER="" STREAM=0 CONFIG=config CACHE=cache DOCACHE=0 MIX=0 TRACKS=-4 SETTRACKS=-5 MIXFILES="" DOMIXFILE=0 DOLISTMIXFILES=0 HINTS="" HINT1="" SUBDIR="" COMMAND="" SLOW_PATH_TRANSLATION=0 INTERACTIVE=0 LEVELSEP="/" SETPLATFORM="" ARTISTIDX=1 ALBUMIDX=2 SONGIDX=3 BASEURL="" COVERART=0 SETCOVERART=-1 while test $# -gt 0 do case "$1" in --install) install "$2" exit 0 ;; --uninstall) uninstall exit 0 ;; --list|-l) SHOW=1 shift ;; --queue|-q) QUEUE=1 shift ;; --random|-r) SETORDER="random" shift ;; --stripe) SETORDER="stripe" shift ;; --stripe2) SETORDER="stripe2" shift ;; --sort) SETORDER="sort" shift ;; --fade) SETORDER="fade" shift ;; --group) SETORDER="group" shift ;; --cache|-c) DOCACHE=1 if ! test "-$2-" = "--" then SUBDIR="$2" shift fi shift ;; --coverart) if ! test "-$2-" = "--" then test 2> /dev/null $2 -gt -1 if test $? -ne 0 then echo 1>&2 Bad value for --coverart, ignoring $1 else SETCOVERART=$2 shift fi else echo 1>&2 No value for --coverart, ignoring fi shift ;; --stream|-s) STREAM=1 TRACKS=10 shift ;; --guest|-g) if ! test "-$2-" = "--" then prefix=`echo "$2" | sed "s/ /-/g"` CONFIG="$prefix-$CONFIG" CACHE="$prefix-$CACHE" shift else echo 1>&2 No guest name provided, ignoring $1 fi shift ;; --device|-d) if ! test "-$2-" = "--" then SETDEVICE="$2" shift else echo 1>&2 No device name provided, ignoring $1 fi shift ;; --platform) if ! test "-$2-" = "--" then SETPLATFORM="$2" shift else echo 1>&2 No platform provided, ignoring $1 fi shift ;; --mix|-m) MIX=1 shift ;; --tracks|-t) if ! test "-$2-" = "--" then if test $2 = "avg" then SETTRACKS=-1 elif test $2 = "min" then SETTRACKS=-2 elif test $2 = "max" then SETTRACKS=-3 elif test $2 = "all" then SETTRACKS=-4 else test 2> /dev/null $2 -gt -1 if test $? -ne 0 then echo 1>&2 Bad track count, ignoring $1 else SETTRACKS=$2 fi fi shift else echo 1>&2 No track count provided, ignoring $1 fi shift ;; --mixfile|-f) if ! test "-$2-" = "--" then MIXFILES="$MIXFILES `echo "$2" | sed "s/ /-/g"`" DOMIXFILE=1 MIX=1 shift else echo 1>&2 No mix file name provided, ignoring $1 fi shift ;; --play) COMMAND=play shift ;; --pause) COMMAND=pause shift ;; --stop) COMMAND=stop shift ;; --next) COMMAND=next shift ;; --prev) COMMAND=prev shift ;; --interactive|-i) INTERACTIVE=1 shift ;; --dump) DOLISTMIXFILES=1 shift ;; --help) usage exit 0 ;; --version) version exit 0 ;; -*) echo 1>&2 Ignoring unknown option $1 shift ;; *) if test "-$HINT1-" = "--" then HINT1="$1" fi HINTS="$HINTS \"$1\"" shift ;; esac done mkdir -p "$HOME/.plait/xspf" if test -f "$HOME/.plait/$CONFIG" then . "$HOME/.plait/$CONFIG" fi if test "-$MUSICDIR-" = "--" then echo 1>&2 Please enter the directory where your music is stored. while test 1 -gt 0 do read a if test -d "$a" then MUSICDIR="$a" echo >> "$HOME/.plait/$CONFIG" "MUSICDIR=\"$a\"" echo 1>&2 Configuration complete break else echo 1>&2 Directory $a not found, try again fi done fi if ! test "-$SETPLATFORM-" = "--" then PLATFORM=$SETPLATFORM fi if test "-$PLATFORM-" = "--" then if test $CYGWIN -ge 1 then PLATFORM=cygwin-winamp elif test $DARWIN -ge 1 then PLATFORM=osx-itunes else xmms=`which xmms 2>/dev/null` if ! test "-$xmms-" = "--" then PLATFORM=unix-xmms else bmp=`which beep-media-player 2>/dev/null` if ! test "-$bmp-" = "--" then PLATFORM=unix-beep-media-player else amarok=`which amarok 2>/dev/null` if ! test "-$amarok-" = "--" then PLATFORM=unix-amarok else mpg=`which mpg123 2>/dev/null` ogg=`which ogg123 2>/dev/null` mpg3=`which mpg321 2>/dev/null` if ! test "-${mpg}${ogg}${mpg3}-" = "--" then PLATFORM=unix-plaiter else PLATFORM=any-listonly echo 1>&2 No player is selected. Edit $HOME/.plait/config to select one. fi fi fi fi fi echo 1>&2 Platform $PLATFORM selected. echo >> "$HOME/.plait/$CONFIG" "PLATFORM=$PLATFORM" fi export ESPEAKER MUSICDIR=`echo "$MUSICDIR" | sed "s:/$::"` if test -d "$MUSICDIR" then mkdir -p "$MUSICDIR/.plait/mixfiles" fi if test $SETTRACKS -ge -4 then TRACKS=$SETTRACKS fi if ! test "-$SETDEVICE-" = "--" then eval DEVICE="\$$SETDEVICE" fi if ! test "-$SETORDER-" = "--" then ORDER=$SETORDER fi if test $SETCOVERART -ge 0 then COVERART=$SETCOVERART fi if test $STREAM = 1 && test $DOMIXFILE = 1 then STREAM=0 echo 1>&2 Mix file selected, ignoring --stream fi if test $STREAM = 1 && test $TRACKS -lt 0 then TRACKS=10 echo 1>&2 "Stream query selected, ignoring symbolic track count" fi #if test $STREAM = 1 && test $INTERACTIVE = 1 #then # INTERACTIVE=0 # echo 1>&2 "Stream query selected, disabling interactive mode" #fi if test $DOCACHE -eq 1 then docache exit 0 fi if test $DOLISTMIXFILES -eq 1 then listmixfiles exit 0 fi if test "$PLATFORM" = "cygwin-winamp" then create_winamp_scripts fi if test "$PLATFORM" = "cygwin-itunes" then create_itunes_scripts fi # if there is a command, forward it to the player and quit if ! test "-$COMMAND-" = "--" then case $PLATFORM in cygwin-winamp) cygstart "$HOME/.plait/commands/cmd-$COMMAND.vbs" ;; cygwin-itunes) cygstart "$HOME/.plait/commands/itunes-cmd-$COMMAND.js" ;; linux-plaiter|unix-plaiter) plaiter --$COMMAND ;; osx-itunes) case $COMMAND in play) osascript -e 'tell application "iTunes" to play' > /dev/null 2>&1 ;; pause) osascript -e 'tell application "iTunes" to pause' > /dev/null 2>&1 ;; stop) osascript -e 'tell application "iTunes" to stop' > /dev/null 2>&1 ;; next) osascript -e 'tell application "iTunes" to next track' > /dev/null 2>&1 ;; prev) osascript -e 'tell application "iTunes" to previous track' > /dev/null 2>&1 ;; esac ;; linux-xmms|unix-xmms|unix_xmms) case $COMMAND in play) xmms-shell -e play > /dev/null 2>&1 ;; pause) xmms-shell -e pause > /dev/null 2>&1 ;; stop) xmms-shell -e stop > /dev/null 2>&1 ;; next) xmms-shell -e next > /dev/null 2>&1 ;; prev) xmms-shell -e previous > /dev/null 2>&1 ;; esac if ! test $? = 0 then echo 1>&2 Platform $PLATFORM requires the package xmms-shell to send command $COMMAND fi ;; linux-beep-media-player|unix-beep-media-player) case $COMMAND in play) beep-media-player --play > /dev/null 2>&1 ;; pause) beep-media-player --play-pause > /dev/null 2>&1 ;; stop) beep-media-player --stop > /dev/null 2>&1 ;; next) beep-media-player --fwd > /dev/null 2>&1 ;; prev) beep-media-player --rew > /dev/null 2>&1 ;; esac ;; linux-amarok|unix-amarok) case $COMMAND in play) amarok --play > /dev/null 2>&1 ;; pause) amarok --pause > /dev/null 2>&1 ;; stop) amarok --stop > /dev/null 2>&1 ;; next) amarok --next > /dev/null 2>&1 ;; prev) amarok --previous > /dev/null 2>&1 ;; esac ;; linux-mplayer|unix-mplayer) case $COMMAND in stop) killall mplayer > /dev/null 2>&1 ;; esac ;; *) echo 1>&2 Platform $PLATFORM does not support command $COMMAND ;; esac exit 0 fi if ! test "-$HINTS-" = "--" || test $DOMIXFILE = 1 then if test $STREAM = 0 then if ! test -f "$HOME/.plait/$CACHE" then docache fi if test $DOMIXFILE = 1 then LISTNAME="`echo \"$MIXFILES\" | sed \"s/^ //\"` tracks" else LISTNAME="$HINT1 tracks" fi echo "LISTNAME=\"$LISTNAME\"" > "$HOME/.plait/listname" if test $DOMIXFILE -eq 0 then eval querylibrary $HINTS else filehints="" for MIXFILE in $MIXFILES do if test -e "$MUSICDIR/.plait/mixfiles/$MIXFILE" then filehints="$filehints `cat "$MUSICDIR/.plait/mixfiles/$MIXFILE" | awk '{printf "%s ", $0}'`" else echo 1>&2 Mixfile $MIXFILE not found fi done if test "-$HINTS-" = "--" && test "-$filehints-" = "--" then echo 1>&2 No hints, exiting exit 0 else eval querylibrary $filehints $HINTS fi fi else LISTNAME="$HINT1 streams" echo "LISTNAME=\"$LISTNAME\"" > "$HOME/.plait/listname" eval querystream $HINTS fi else # make sure there's at least an empty playlist touch "$HOME/.plait/playlist.m3u" fi if test "-$LISTNAME-" = "--" then if test -f "$HOME/.plait/listname" then . "$HOME/.plait/listname" fi if test "-$LISTNAME-" = "--" then if test $STREAM = 0 then LISTNAME="plait tracks" else LISTNAME="plait streams" fi echo "LISTNAME=\"$LISTNAME\"" > "$HOME/.plait/listname" fi fi if test $SHOW = 1 then cat "$HOME/.plait/playlist.m3u" else cuts=`cat "$HOME/.plait/playlist.m3u" | wc -l` if test $cuts = 0 then echo 1>&2 Playlist empty, try --list or --help else if ! test -d "$MUSICDIR" && test $STREAM = 0 then echo 1>&2 The music directory is unavailable, exiting exit 1 fi case $PLATFORM in cygwin-winamp) translate_or_copy if test $QUEUE = 0 then cygstart "$HOME/.plait/commands/play.vbs" else cygstart "$HOME/.plait/commands/queue.vbs" fi ;; cygwin-itunes) prefetch_or_translate ln2=`echo "$LISTNAME" | sed "s:/:-:g"` if test $QUEUE = 0 then sed "s/%PL%/$ln2/g" "$HOME/.plait/commands/itunes-play.js" > "$HOME/.plait/commands/itunes-play-2.js" cygstart "$HOME/.plait/commands/itunes-play-2.js" else sed "s/%PL%/$ln2/g" "$HOME/.plait/commands/itunes-queue.js" > "$HOME/.plait/commands/itunes-queue-2.js" cygstart "$HOME/.plait/commands/itunes-queue-2.js" fi ;; osx-itunes) if test $QUEUE -eq 1 then echo > "$HOME/.plait/play.osa" "tell application \"iTunes\"" echo >> "$HOME/.plait/play.osa" "if not (exists user playlist \"$LISTNAME\") then" echo >> "$HOME/.plait/play.osa" "make user playlist with properties {name:\"$LISTNAME\"}" echo >> "$HOME/.plait/play.osa" "end if" else echo > "$HOME/.plait/play.osa" "tell application \"iTunes\"" echo >> "$HOME/.plait/play.osa" "if (exists user playlist \"$LISTNAME\") then" echo >> "$HOME/.plait/play.osa" "delete user playlist \"$LISTNAME\"" echo >> "$HOME/.plait/play.osa" "end if" echo >> "$HOME/.plait/play.osa" "make user playlist with properties {name:\"$LISTNAME\"}" fi hasurl=`grep -ci http "$HOME/.plait/playlist.m3u"` if test $hasurl = 0 then cat "$HOME/.plait/playlist.m3u" | awk >> "$HOME/.plait/play.osa" -v pl="$LISTNAME" \ '{print "set f to \"" $0 "\""; \ print "try"; \ print "set f2 to (POSIX file f) as string"; \ print "add f2 to playlist \"" pl "\""; print "end try"}' else prefetch_stream_urls pl="$HOME/.plait/playlist2.m3u" echo >> "$HOME/.plait/play.osa" "set f to \"$pl\"" echo >> "$HOME/.plait/play.osa" "set f2 to (POSIX file f) as string" echo >> "$HOME/.plait/play.osa" "add f2 to playlist \"$LISTNAME\"" fi if test $QUEUE = 0 then echo >> "$HOME/.plait/play.osa" "play track 1 of playlist \"$LISTNAME\"" fi echo >> "$HOME/.plait/play.osa" "end tell" osascript > /dev/null 2>&1 "$HOME/.plait/play.osa" ;; linux-xmms|unix-xmms|unix_xmms) prefetch_or_copy if test $QUEUE -eq 0 then xmms "$HOME/.plait/playlist2.m3u" & else xmms --enqueue "$HOME/.plait/playlist2.m3u" & fi ;; linux-mpg321|unix-mpg321) prefetch_or_copy killall > /dev/null 2>&1 mpg321 mpg321 -q --list "$HOME/.plait/playlist2.m3u" & ;; linux-mpg321-esd|unix-mpg321-esd) prefetch_or_copy killall > /dev/null 2>&1 mpg321 if ! test "-$ESPEAKER-" = "--" then SERVEROPT="-a $ESPEAKER" fi mpg321 -q -o esd $SERVEROPT --list "$HOME/.plait/playlist2.m3u" & ;; linux-mpg123|unix-mpg123) prefetch_or_copy killall > /dev/null 2>&1 mpg123 mpg123 -q --list "$HOME/.plait/playlist2.m3u" & ;; linux-ogg123|unix-ogg123) prefetch_or_copy killall > /dev/null 2>&1 ogg123 ogg123 -q --list "$HOME/.plait/playlist2.m3u" & ;; linux-ogg123-esd|unix-ogg123-esd) prefetch_or_copy killall > /dev/null 2>&1 ogg123 ogg123 -d esd -q --list "$HOME/.plait/playlist2.m3u" & ;; linux-mpg123-esd|unix-mpg123-esd) prefetch_or_copy killall > /dev/null 2>&1 mpg123-esd mpg123-esd -q --list "$HOME/.plait/playlist2.m3u" & ;; linux-plaiter|unix-plaiter) prefetch_or_copy if test $QUEUE = 0 then plaiter "$HOME/.plait/playlist2.m3u" & else plaiter --queue "$HOME/.plait/playlist2.m3u" & fi ;; linux-beep-media-player|unix-beep-media-player) prefetch_or_copy if test $QUEUE = 0 then beep-media-player "$HOME/.plait/playlist2.m3u" & else beep-media-player --enqueue "$HOME/.plait/playlist2.m3u" & fi ;; linux-amarok|unix-amarok) prefetch_or_copy if test $QUEUE = 0 then amarok "$HOME/.plait/playlist2.m3u" & else amarok --enqueue "$HOME/.plait/playlist2.m3u" & fi ;; any-listonly) cat "$HOME/.plait/playlist.m3u" ;; cygwin-listonly) prefetch_or_translate cat "$HOME/.plait/playlist2.m3u" ;; any-xspf) prefetch_or_copy awk -f $INSTALLDIR/share/plait/xspf.awk -v title="$LISTNAME" art=$COVERART \ plait="$HOME/.plait" coverprog="$INSTALLDIR/share/plait/coverart.awk" \ sep="$LEVELSEP" d="$MUSICDIR" ar=$ARTISTIDX al=$ALBUMIDX so=$SONGIDX url="$BASEURL" \ "$HOME/.plait/playlist2.m3u" > "$HOME/.plait/xspf/playlist.xspf" sed -e "s:%TITLE%:$LISTNAME:" $INSTALLDIR/share/plait/playlist.html \ > "$HOME/.plait/xspf/index.html" echo 1>&2 "Playlist directory $HOME/.plait/xspf ready for upload" ;; any-xspf-copy) prefetch_or_copy awk -f $INSTALLDIR/share/plait/xspf.awk -v title="$LISTNAME" art=$COVERART \ plait="$HOME/.plait" coverprog="$INSTALLDIR/share/plait/coverart.awk" \ sep="$LEVELSEP" d="$MUSICDIR" ar=$ARTISTIDX al=$ALBUMIDX so=$SONGIDX url="$BASEURL" \ "$HOME/.plait/playlist2.m3u" > "$HOME/.plait/xspf/playlist.xspf" sed -e "s:%TITLE%:$LISTNAME:" $INSTALLDIR/share/plait/playlist.html \ > "$HOME/.plait/xspf/playlist.html" if ! test $hasurl -gt 0 then echo 1>&2 "Copying mp3 files to $HOME/.plait/xspf" awk -f $INSTALLDIR/share/plait/treecopy.awk d="$MUSICDIR/" to="$HOME/.plait/xspf/" \ "$HOME/.plait/playlist2.m3u" | sh fi echo 1>&2 "Playlist directory $HOME/.plait/xspf ready for upload" ;; linux-mplayer|unix-mplayer) prefetch_or_copy killall > /dev/null 2>&1 mplayer mplayer -really-quiet -playlist "$HOME/.plait/playlist2.m3u" & ;; esac fi fi plait/plait.10000700000076500007650000000402611063224304015070 0ustar sjungelssjungels00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. .TH PLAIT "1" "September 2008" "Plait v 1.6.2" "User Commands" .SH NAME Plait \- manual page for Plait v 1.6.2 .SH DESCRIPTION .SS "Usage is:" .IP "plait [[not] ]...[as ]", or "plait \fB\-\-stream\fR [[not] ]..." .SH OPTIONS .HP \fB\-\-list\fR,-l \fB\-\-\fR show matching tracks but don't play .HP \fB\-\-mix\fR,-m \fB\-\-\fR play tracks matching any hint (make a mix) .HP \fB\-\-queue\fR,-q \fB\-\-\fR add tracks to queue .HP \fB\-\-random\fR,-r \fB\-\-\fR play in random order .HP \fB\-\-sort\fR \fB\-\-\fR play in sorted order .HP \fB\-\-stripe\fR \fB\-\-\fR play in alternating order .HP \fB\-\-stripe2\fR \fB\-\-\fR play in random alternating order .HP \fB\-\-fade\fR \fB\-\-\fR play in gaussian fade order .HP \fB\-\-group\fR \fB\-\-\fR play randomly in groups .HP \fB\-\-tracks\fR,-t \fB\-\-\fR play n tracks, if possible .HP \fB\-\-stream\fR,-s \fB\-\-\fR play Shoutcast radio streams .HP \fB\-\-mixfile\fR,-f \fB\-\-\fR read hints from mixfile .HP \fB\-\-device\fR,-d \fB\-\-\fR choose target device .HP \fB\-\-platform\fR \fB\-\-\fR choose platform .HP \fB\-\-coverart\fR \fB\-\-\fR cover art mode (0 or 1) .HP \fB\-\-guest\fR,-g \fB\-\-\fR use guest configuration .HP \fB\-\-interactive\fR,-i \fB\-\-\fR interactive mode .HP \fB\-\-cache\fR,-c \fB\-\-\fR rebuild cache .HP \fB\-\-install\fR \fB\-\-\fR install Plait .HP \fB\-\-uninstall\fR \fB\-\-\fR uninstall Plait .HP \fB\-\-play\fR .HP \fB\-\-pause\fR .HP \fB\-\-stop\fR .HP \fB\-\-next\fR .HP \fB\-\-prev\fR .HP \fB\-\-help\fR \fB\-\-\fR show help .HP \fB\-\-version\fR \fB\-\-\fR show version .SH AUTHOR Written by Stephen Jungels (http://stephenjungels.com/contact) .SH COPYRIGHT Copyright \(co 2005-2008 by Stephen Jungels. Released under the GPL. Latest version and more info at http://plait.sourceforge.net/ plait/README0000700000076500007650000013417411063224254014571 0ustar sjungelssjungels00000000000000README for Plait v 1.6.2 ======================== 0. Introduction --------------- Plait (pronounced "play") can do two things for you: find and play music from your personal music library, and find and play Shoutcast radio streams. In order to actually play the music it finds, Plait hands off a play list to one of the supported music players (iTunes, Winamp, Beep Media Player, Xmms, amaroK, mpg123, ogg123, mpg321, XSPF Web Music Player, or Plaiter). The end result is that you can type, for example, plait "miles davis" and any music by Miles Davis that you own will begin playing in your music player. More complex commands allow you to play mixes of several albums or artists, read complex mixes from files, reorder the play list according to one of several patterns, select a certain number of tracks, queue tracks, send commands to the music player, and more. I wrote Plait because I was looking for an alternative to tedious point and click digging through my music library, on the one hand, and tedious typing of long file names, on the other. The solution used by Plait is based on "hints", which are basically fragments of song titles, artist's names, or album names. You specify as many hints as needed to get exactly the music you want. For example, rather than typing out the complete file name "/music/Billie Holiday/Ken Burns Jazz/Solitude.wav" or digging through a file requester to find this file, with Plait one types plait billie solitude When you already know exactly what you want to hear, this is really the quickest and easiest way to let the computer know (and when you don't know exactly what you want to hear, Plait has an interactive mode that allows you to browse tracks, albums, artists, and radio streams.) Even though it searches the entire music library every time it creates a play list, Plait is optimized for these types of queries (it caches your music directory) and can perform them very quickly. With a medium sized music collection of about 3,000 tracks, queries take less than a second. On Cygwin, which can be slow, queries take a little longer-- about 2.5 seconds on a 700 mhz system. 0.1 What's new --------------- Release 1.6.2 is a security upgrade which cleans up all security flaws related to temp files. Release 1.6.1 is a maintenance release to track recent changes in the Shoutcast.com web site. You will need it if you want to continue running stream queries. 1. About that name... ---------------------- "Plait" is French for "it pleases," because it is so pleasing to use. It also suggests the soundalike English word "play," which describes what it actually does. You might say it's a plait on words. At one point in the misty past, Plait was known as "play," but that name was taken. 2. Searching your music library ------------------------------- Plait doesn't make any assumptions about the layout of your music library, but the better organized it is, the more useful the searches you can do. Ideally your file paths contain artists, albums, and song titles. In that case you can provide a hint about an artist and get all the material by that artist: plait mingus You can provide a hint which matches just one album: plait "kind of blue" Or you can match a single song plait "blue in green" (Although examples like these will typically "just work," keep in mind that Plait doesn't actually know that "Kind of Blue" is an album or Mingus is an artist. If you have a song named "Mingus", it will play also. Other options were considered, but this method is the easiest to use, and it seems to work very well. In fact, it is almost always possible to create a hint that picks exactly the music you want. See the section on advanced hinting for more information.) Because Plait scans your entire music library when matching hints, you are not limited to results from one directory. So if you have a compilation album that is distributed by artist throughout your collection, you can play the whole thing by searching for the album name. Similarly, you can play an entire album series, as in plait --random "ken burns jazz" This type of matching is also useful when you want to play several cover versions of the same song. Querying the entire music library for songs rather than finding files by directory also helps resolve some problems of categorization that come up when ripping a CD collection. If you rip Cecilia Bartoli's "Vivaldi Album," for example, do you store that as /music/Vivaldi/The Vivaldi Album feat. Cecilia Bartoli so that you can play it as Vivaldi music, or /music/Cecilia Bartoli/The Vivaldi Album so that you can play it as Cecilia Bartoli music? With Plait, it doesn't matter because, either way, the album will turn up when you type `plait cecilia` or `plait vivaldi`. Sometimes one hint is not enough to say exactly what you mean, so Plait does not place any limit on the number of hints you can specify. This comes in handy when you have a song title that is used by more than one artist. In my music collection, for example, if I type plait "walk on" I will hear "Walk On" by Neil Young, "Walk On" by U2, and the album "Walk On" by John Hiatt (which includes a song named "Walk On"). Additional hints allow me to disambiguate: plait "walk on" neil # Neil Young's version plait "walk on" u2 # by u2 plait "walk on/" # the album by John Hiatt plait "walk on[.]" hiatt # just the song (The last two examples are a little tricky. They work by matching the path separator or the dot in ".mp3". See the section on advanced hinting for more ideas.) This feature also comes in handy when you want to avoid typing a long song title, but the short hints available are ambiguous. If I use the hint "someday" for example, I get "Someday" by the Strokes, and "Someday We'll All Be Free" by Charlie Hunter. The command plait charlie someday gives me exactly what I want. Feel free to use hints that are easy to remember rather than trying to be efficient. That is one of the purposes of hinting, beyond just putting you on a first name basis with your favorite artists (or you could type `plait someday be` and save a few keystrokes; it's up to you). There is an implicit logical "and" between the hints in these commands, although you do not need to think of it that way if you are a non-programmer. In any case, you get just the songs that match *all* the hints, rather than any of the hints. (As we will see later, there is another type of search in which there is an implicit "or" and you get songs that match *any* of the hints.) Sometimes positive assertions about the music you want to hear are not sufficient to say exactly what you mean. For these situations the `not` keyword, which allows you to exclude songs that match a hint, is provided. As an example, the following command plays some music by Herbie Hancock, leaving out one track that I set aside for special occasions: plait herbie not rockit You can use as many "not" hints as you like, but you have to make at least one positive assertion about the music you want to hear, and it has to be the first hint on the command line. Therefore plait not miles will look for a song named "not" by Miles Davis. This is intentional. If you really want to hear random selections from almost your entire collection, you can just use a very broad positive assertion, as in plait --random ".*" not miles (".*" is a regular expression that matches anything. See the section on advanced hinting.) The features explained so far allow you to pick out a particular track, artist, album, or series, but sometimes you are interested in mixing together material from several artists or albums. In that case you will want the `--mix` option, which picks tracks that match *any* of your hints rather than all of them. For example plait --mix metheny hunter "tj kirk" "broun fellinis" will create a play list with a selection of jazz artists. Because it allows me to do something that would be totally impractical with CDs, the ability to make mixes has changed my listening habits more than any other feature of Plait. 3. Playing radio streams ------------------------- Plait can search the Shoutcast web site, find stations matching your query, and play them in your music player. If you are interested in hearing trance music, for example, you might try plait --stream trance You can use a hint that contains spaces by enclosing it in quote marks, as in plait --stream "modern jazz" As of Plait 0.53, stream queries support multiple hints and the `not` keyword, just like music library queries. This allows you to search for radio stations much more selectively than before. The `--mix` keyword is also supported, but not the `as` keyword or mix files. The current thinking is that these features would be of limited usefulness with streams. Genre hints work well, because the Shoutcast directory includes a genre in the description of each radio station, but you can try other types of search, including by station name, call letters, artist or country. By default, you get the most popular stations matching your query, but if you don't like the popular stations in a certain genre, you can mix things up with the `--random` option (see below). For performance reasons, Plait limits you to ten streams (because they take a while to load into the music player), but you can request more with the `--tracks` option. In interactive mode, the number of streams is unlimited. Examples: plait --stream --random --tracks 5 jazz not smooth plait --stream 70s plait --stream bachata plait --stream NPR -i 4. Mix Files ------------- As you make more complex mixes you may begin to use so many hints that they become inconvenient to type. At this point you will be ready for mix files. Once you have created an appropriate mix file with a hint for each jazz artist in your collection, for example, you can type plait --mixfile jazz --random to play random selections from your entire jazz collection. Creating mix files is easy because they are just text files with lists of hints, but Plait is also capable of creating mix files for you. First let's look at creating a mix file by hand. Mix files are stored in a subdirectory of your music directory. Specifically, if your music directory is /music, the mixfiles are at /music/.plait/mixfiles. (Storing them here rather than in plait's working directory allows you to continue using your mix files when you are accessing your music collection as a guest on someone else's computer.) To create a mix file for jazz, then, you might type the following into /music/.plait/mixfiles/jazz: "billie" "blakey" "brubeck" "coltrane" "dolphy" "getz" "hunter" "metheny" "miles" "mingus" "ornette" "rollins" "scofield" "stanton" "surman" "thelonious" (The hints should be separated by spaces or line feeds. It is only necessary to enclose a hint in quote marks if it contains a space.) That's all there is to it. Plait also has a simple syntax for creating mix files automatically, using the `as` keyword. For example, the following command creates a mix file and plays some cuts from it simultaneously: plait --mix galactic "scott amendola" "oranj symphonette" as postjazz The `as` keyword also comes in handy when you need to maintain mix files. Let's say you have a jazz mix file and you acquire some new music by Herbie Hancock. You can add him to the jazz mix as follows: plait --mixfile jazz herbie as jazz If Herbie Hancock were already in your jazz mix, no harm would be done--Plait makes sure that each hint occurs exactly once. You can use more than one mix file with a `plait` command. This allows you to create a "mix of mixes," for example: plait --mixfile jazz --mixfile postjazz as alljazz In general, you can combine mix files and hints freely on the command line, allowing you to play variations on a given mix depending on your mood: plait --mixfile jazz not miles not ornette Because they are based on hints, mix files have some of the features of play lists and some of the features of genres. As with play lists, a given artist can be included in as many mix files as you like. This allows you to create free form, overlapping categories for artists, rather than being forced to assign each artist to a single fixed category. As with genres, on the other hand, once an artist belongs to a mix, any new music you purchase by that artist is automatically added to the mix. In this sense mix files are more dynamic than play lists. (By the way, nothing said here should be taken to mean that mix files always have to consist of artist hints. That is probably the typical case, but there is nothing to prevent you from using album hints or song hints in your mix files.) Since you create mix files yourself, they require a little more work than genres, which can probably be assigned using automated tools. But it really doesn't take long to create mix files, and you will find that the added flexibility is worth the effort. 5. Playlist optimization ------------------------- When you create a mix featuring two artists, it is most likely that you would like to hear approximately the same number of tracks from each artist. But if, for example, you have 6 albums by artist A and only 2 by artist B, tracks by artist A will dominate the playlist Plait creates. As of Plait 1.2 there is a playlist optimizer which addresses this problem by balancing the playlist. It has other nice features as well. You need to enable the playlist balancer by setting a track count with the `--tracks` option; otherwise you get the old behavior where Plait selects all the tracks that match your hints. There are special symbolic track counts which control the behavior of the playlist balancer. Some examples will clarify: plait -l --mix "miles davis" "charles mingus" --tracks all This command creates a playlist with all the available tracks from Miles Davis and Charles Mingus. This is also the default behavior if you don't specify a track count. plait -l --mix "miles davis" "charles mingus" --tracks min This command determines the number of tracks in the smallest hint group and then creates a balanced playlist by selecting that number of tracks from each group. Some tracks from larger hint groups will be skipped. plait -l --mix "miles davis" "charles mingus" --tracks max This command determines the number of tracks in the largest hint group and then creates a balanced playlist by selecting that number of tracks from each group. Some tracks from smaller hint groups will be repeated. plait -l --mix "miles davis" "charles mingus" --tracks avg This command determines the average number of tracks per group and then creates a balanced playlist by selecting that number of tracks from each group. Some tracks may be skipped and some tracks may be repeated. plait -l --mix "miles davis" "charles mingus" --tracks 20 This command creates a balanced playlist with approximately 20 tracks. Tracks may be skipped or repeated depending on the particular count you specify and the number of tracks in the source playlist. Because Plait is designed to create unique playlists every time you run it, there is a lot of random fudge in the algorithm that balances playlists. The track counts you specify are just goals; they are translated into a probability that tracks from each group will be selected and this is combined with a random number to determine whether each track is selected. As a result, the playlist will contain a number of tracks close to the goal you specify but not necessarily exactly the same. #### Weighting the balance It's not always the case that you want to hear exactly equal amounts of music from each artist, and Plait provides a simple way to weight the balance when you don't, by repeating hints. The following command creates a mix with more tracks by Miles Davis than John Coltrane: plait -l --mix davis davis coltrane --tracks 15 This sets a 2:1 ratio between Miles Davis tracks and John Coltrane tracks as a goal. Depending on the content of the source playlist, the goal may or may not be achieved exactly. Tracks will not be repeated in order to achieve the goal; the effect of repeating hints is just to give each track a "second chance" in the case where it is not printed the first time it matches a hint. This technique can be used to generate a playlist with a featured artist or featured album, for example plait -l --mixfile jazz 58 58 --tracks 30 --stripe This command creates a playlist with a variety of Jazz tracks, but featuring the album "'58 Sessions" by Miles Davis. #### Patterns The playlist optimizer also allows you to order the tracks in the playlist according to one of several patterns: plait -l --mix "miles davis" "charles mingus" --tracks 15 --sort The --sort option causes the tracks to appear in sorted order plait -l --mix "miles davis" "charles mingus" --tracks 15 --stripe The --stripe option picks one track matching hint a and then one track matching hint b, in an alternating pattern. Within the stripes, the tracks appear in sorted order. plait -l --mix "miles davis" "charles mingus" --tracks 15 --stripe2 --stripe2 is similar to --stripe, but within the stripes the tracks appear in random order. plait -l --mix "miles davis" "charles mingus" --tracks 15 --fade The --fade option arranges the tracks matching each hint according to a gaussian distribution. The effect is that tracks matching each hint are clustered around a certain position in the playlist and appear less frequently as you move away from that position. Thus each section of the playlist focuses on one artist, but there are no rigid boundaries between the sections. plait -l --mix "miles davis" "charles mingus" --tracks 15 --random In this case tracks are arranged randomly. plait -l --mix "miles davis" "charles mingus" --tracks 15 --group The --group option groups the tracks by hint and shuffles randomly within each group. #### Target devices The final new feature of the playlist optimizer is intended to help people with a mixture of lossy and lossless encodings in their music libraries. It filters the playlist so that the encoding types you specify are either preferred or used exclusively, allowing you to create playlists that are suitable for a variety of target devices, including Hi-Fi stereos, disk-based portable music players, and flash-based portable music players. Examples: plait doors --device hifi This command selects tracks in both lossless and lossy formats. If a given track is available in more than one format, the lossless encoding is preferred. It is suitable for a home stereo with high quality audio. This is also the default device. plait doors --device medium This command selects tracks in both lossless and lossy formats. If a given track is available in more than one format, the lossy encoding is preferred. It is suitable for a disk-based portable music player. plait doors --device compact This command selects tracks in the mp3 format only. It is suitable for a flash-based portable music player like the iPod Shuffle. You can define your own target devices or change the default device in the config file. See section 10. In all cases, two files are considered to be the same track in different formats if the file paths are identical except for the extension. Thus the following two files are considered to be the same track in two different formats: /music/Miles Davis/Kind of Blue/Blue in Green.wav /music/Miles Davis/Kind of Blue/Blue in Green.mp3 The following two files are not considered to be the same track in two different formats: /music/WAV/Miles Davis/Kind of Blue/Blue in Green.wav /music/MP3/Miles Davis/Kind of Blue/Blue in Green.mp3 6. Options ----------- These options provide finer control over the music you play: ### --list, -l Learning to use hints involves trial and error. The `--list` option facilitates this by allowing you to see what songs a hint will play without actually playing them. Its use is self-explanatory. If you like the songs listed, you don't have to run the query again to play them. Simply typing plait without any hints plays the list returned by the last query. ### --queue, -q Normally the songs found by a `plait` command will play instantly, interrupting whatever was playing when you typed the command. If you want the songs to be added to the play list, use `--queue`. They will begin playing after the previous play list completes (mpg123 and mpg321 do not support queuing, but Plaiter, which is a front end to those programs, supports queuing and several more features.) ### --random, -r By default, songs are sorted by file path. If your music library is organized by artist, album, and title, your playlists will be organized the same way. If your song names are preceded by track numbers, they will play in album order. `--random` is for those times when you want a little variety. It shuffles the play list before sending it to your music player. ### --sort Plays tracks in sorted order. --sort is also the default. ### --stripe Arranges tracks in an alternating pattern with one track matching hint a, followed by one track matching hint b, and so on until all of the hints have been used; then the pattern repeats. Within the stripes, tracks appear in sorted order. This option does not apply to stream queries. ### --stripe2 Arranges tracks in an alternating pattern with one track matching hint a, followed by one track matching hint b, and so on until all of the hints have been used; then the pattern repeats. Within the stripes, tracks appear in random order. The hints themselves are also shuffled, so you get a different pattern every time. This option does not apply to stream queries. ### --fade Clusters the tracks matching each hint around a particular position in the playlist, in a gaussian distribution. Thus each section of the playlist is focused on tracks matching one hint, but there are no rigid boundaries between the sections. Within each cluster, tracks are distributed randomly. This option does not apply to stream queries. ### --group Groups tracks by hint. Within hint groups, tracks appear in random order. This option does not apply to stream queries. ### --stream, -s Plays Shoutcast radio streams (see Section 3). Examples: plait --stream --random --tracks 5 salsa plait --stream kplu plait --stream chinese plait --stream --random reggaeton ### --tracks, -t Normally, Plait plays at most ten radio stations at a time, or an unlimited number of tracks. More than that and your music player will freeze for a while, which can seem broken. This option allows you to override the default values. For example plait --mix --tracks 10 "nick cave" "nick drake" plait --stream --tracks 20 industrial As of Plait 1.2, this option behaves differently depending on whether or not you are doing a stream query. For stream queries, the track count must be a number and it is a simple limit on the number of stations that will be selected. For library queries, the track count is a goal for the playlist balancer. In addition to particular numbers, there are symbolic track counts which control the behavior of the balancer, including min, max, avg, and all. See Section 5. ### --mix, -m This option selects songs which match *any* of the hints you provide rather than *all* of them. As an example, plait --mix "broun fellinis" "stanton moore" motherbug creates a play list with tracks by three bands. This option does not effect negative assertions. ### --mixfile, -f This option causes Plait to read hints from a file. Tracks are then selected from the music library just as if you had typed the hints on the command line with the `--mix` option. See Section 4. You can use this option multiple times to specify more than one mix file: plait -f punk -f rock plait --mixfile punk --mixfile rock Just as `--mixfile` causes Plait to read hints from a file, the `as` keyword causes Plait to write hints to a file, for example: plait "neil young" "john hiatt" "nick drake" "john cale" \ as folkrock In naming mix files, it is best not to use spaces. You can force Plait to accept a mix file with a space in its name by enclosing the name in quote marks, but in this case Plait will just replace the space with a dash. So plait --mix belafonte strummer as "calypso punk" will actually create a mix file named "calypso-punk". The same logic applies to the --mixfile option, so plait --mixfile "calypso punk" will correctly find the file you created. The only time you need to be aware of this rule is when you create mix files by hand--don't use spaces in their names. ### --device, -d This option specifies a target device for the playlist. The target device determines what kinds of files will be selected or preferred. There are three predefined target devices: "hifi" accepts all file types but prefers lossless encodings when a given track is available in more than one encoding; "medium" accepts all file types but prefers lossy; and "compact" accepts lossy encodings (mp3) only. It is possible to define your own target devices; see the section on customization. ### --cache, -c You need to run `plait` with this option whenever the contents of your music directory changes. Plait will rescan the entire music directory and find every new piece of music. Keep in mind that each guest configuration has its own cache. As of Plait 0.53 this option has an optional directory argument which causes the rescanning to be restricted to a subdirectory of your music library, useful for doing a quick update when you have added, renamed, or deleted music by a single artist. For example, if your music directory is /music, plait -c "David Kane Quartet" will rescan only the `/music/David Kane Quartet` directory. It only takes about a minute to scan a 3,000 track music library, so if you lose track of which directories you have scanned, you may simply want to rescan everything. Important note: if you rename an artist or album, you may have to run two cache commands to register the change correctly. If, for example, you moved music by the band R.E.M from the directory R.E.M to the directory REM, you would run the commands plait -c R.E.M plait -c REM The first command will delete old cache entries that point to songs which no longer exist. The second command will register the songs in their new location. ### --guest, -g This option provides support for multiple, named configurations. The main reason you would want this is that each configuration can have a different music directory. So if a friend has a music collection that is accessible on your LAN, he will be able to play his music from your computer. To use this feature, just provide a guest name, for example plait --guest mypal "einsturzende neubauten" The first time you use a new guest name, Plait will ask for the location of that guest's music directory. Subsequently, the location will be remembered. It is up to you to mount the guest music directory, if that is necessary. This feature should be particularly useful if you have a VPN set up, but I have not had a chance to test that. When you use a guest configuration you also get the guest's mix files (and lose your own mix files temporarily). It is done this way because mix files tend to be compatible with the collection for which they were created. ### --platform This option allows you to temporarily override the default platform. The single argument can be any of the values allowed for the variable PLATFORM. ### --coverart This option allows you to temporarily override the cover art setting. "--coverart 1" causes cover art to be located on the Amazon.com web site when creating XSPF playlists. "--coverart 0" turns off this feature. ### --interactive, -i This option selects interactive mode, in which each track or station in the playlist is presented for you to vote yes or no on. When editing tracks, the available responses are: * y or yes: play this track * n or no: don't play this track * Y or Yes: play this track and all remaining tracks * N or No: don't play this track or any of the remaining tracks * u or up: move up one level in the hierarchy (from tracks to albums, for example). * d or down: move down one level in the hierarchy * /: search forward By moving up one or two levels you can vote on albums or artists all at once. When searching, you may enter a search term immediately after the slash. A slash by itself repeats the prior search. If there was no prior search you will be prompted for a search term. For the purpose of moving through the hierarchy, the character "/" is used to separate the levels. If your music library is laid out differently, you can set this to something else in the config file, for example, LEVELSEP=" - " In more complex cases, you may want to use a regular expression, for example, LEVELSEP="(/| - )" For display purposes, the "/" character will be used as the separator, but the regular expression will be used internally. When editing radio streams, the available responses are: * y or yes: play this stream * n or no: don't play this stream * Y or Yes: play this stream and all remaining streams * N or No: don't play this stream or any of the remaining streams * /: search forward Plait does its best to present a helpful description of each stream, but sometimes the Shoutcast web page will outwit Plait's regular expression-fu and you will see HTML gunk in the description. ### --play This option forwards the command "play" to the music player. ### --pause This option forwards the command "pause" to the music player. ### --stop This option forwards the command "stop" to the music player. ### --next This option forwards the command "next track" to the music player. ### --prev This option forwards the command "previous track" to the music player. ### --install This option installs Plait. You will normally need to do this only once, but it may also come in handy if Plait stops working because an important file is deleted. To do a complete reinstall, run this command from the install directory. You should run this option as root, using the `su` or `sudo` command. ### --uninstall This option uninstalls Plait. It is up to you to uninstall any prerequisites you had to install to make it work, if you don't want them anymore. If you installed Plait as root, you should run this option as root, using the `su` or `sudo` command. ### --help Shows brief help text. ### --version Shows information about the version of `plait` you are using, the license, and the author. 7. Advanced hinting -------------------- Plait hints are actually extended regular expressions that will be executed by a `grep` command, which fact enables certain advanced queries. If you are familiar with regular expressions, some examples have probably occurred to you already. This section provides some ideas for the uninitiated. Simplicity is one of Plait's goals and as a result a division is drawn between simple queries, which include several hints that must all be matched, usually narrowing the results to a song or an album, and mix queries, which match any of their hints. But sometimes you would like a query which combines a little of both. For example, what if you want to hear "Solitude" by Billie Holiday (but not by Marc Ribot) and "Walk On" by Neil Young (but not by U2). One solution is to use two queries: plait billie solitude plait -q "walk on" neil However, there is a one line solution which depends on the fact that in regular expressions, the string ".*" matches anything. By exploiting this fact we can combine two hints into one complex hint. The resulting command is plait --mix "billie.*solitude" "neil.*walk on" In this way the "and" part of each query is built into a single hint and then the two complex hints are "or"-ed together with the `--mix` option. A variation on this idea is to combine the "or" parts of a query into a complex hint and then "and" it with another hint. For example, the following query plays three of my favorite tracks by Charlie Hunter: plait charlie "flau|dersu|revo" The fact that ".*" means "anything" is also useful if you are simply looking for a way to play a little of everything from your collection. For example, the following query plays 17 random tracks: plait --tracks 17 ".*" --random Some of the more interesting regular expressions will rely on the naming conventions you use in your music library. Here's one that works if your tracks are numbered. It will play the first two tracks of each John Coltrane album in a collection: plait coltrane "0[1-2]" #### Eponyms The fact that Plait uses whole path matching occasionally results in ambiguous hints when albums and songs are named eponymously. However, it is generally easy to come up with a precise hint with a little thought. The following suggestions assume that your music library is organized by Artist/Album/Song, but similar techniques would apply to other layouts. An example of an album and song with the same title is "Walk On" by John Hiatt. Here the trick is to match the path separator, in order to pick the album, or the dot before the file type, in order to pick the song: plait "walk on/" # the album plait "walk on[.]" # the song The brackets are necessary around the dot because dot is a regular expression matching any single character. The brackets tell Plait that we really mean a literal dot. Distinguishing an eponymous album from the artist is a little trickier because they will both end with the path separator. For example, Charlie Hunter has a self-titled album which appears in my music collection as /music/Charlie Hunter/Charlie Hunter/ Typing `plait "charlie hunter"` will give me everything by that artist, not just the album I am interested in. In this case the secret is to match a combination of artist and title which is unique to the album "Charlie Hunter," for example plait "Charlie Hunter/Charlie Hunter" or just plait "Hunter/Charlie" (or `plait ter/cha` for the terse-minded). #### Using precise hints Many of the examples in this document use a relaxed form of hinting which is convenient and easy. Most of the time hints like these will "just work". Every once in a while, though, this approach breaks down. For example, plait miles may get you /music/Byrds/Eight Miles High /music/Who/I Can See for Miles rather than the Miles Davis music you might have been looking for. Likewise, plait rem may get you /music/Talking Heads/Remain in Light rather than music by the band R.E.M. In cases like this you should just use a more precise hint, ie plait "/miles davis/" or plait /rem/ 8. Installation ---------------- Since Plait is glue ware, it has several dependencies. Follow these instructions to make it all work. ### Uninstallation As of Plait 1.5.2, it is possible to install Plait to a directory of your choice. Since this could lead to a situation where you have multiple versions of Plait installed in different directories, it's a good idea to uninstall any old versions of Plait prior to upgrading. But if you know you are installing to the same directory as the old version of Plait, this isn't really necessary. ### Windows/Cygwin prerequisites Running Plait on Windows requires that you install Cygwin, the open source UNIX compatibility layer for Windows. Follow the instructions at Cygwin.com to download and install Cygwin. Plait also requires two optional packages, wget and gawk. Be sure to select these packages when you run Cygwin Setup. For those who are using Winamp, you may need to install it. Get Winamp at Winamp.com. In order to control Winamp, Plait uses a COM object written by John Adcock. To install it: * Download gen_com.zip from www.adcock8.freeserve.co.uk/winamp.htm * Unzip. * Copy gen_com.dll into the C:\Program Files\Winamp\Plugins directory. * Restart Winamp. Winamp will detect and install the new plugin. For those using iTunes, a standard installation of that program should work without any additional steps, but you need to edit the file ~/.plait/config to make iTunes your music player. Change the line that defines PLATFORM to read PLATFORM=cygwin-itunes ### OS X prerequisites Running Plait on OS X requires one package that isn't part of the default install: wget. You can compile wget from source and install it yourself, if you know how to do that sort of thing. The easier option is to install "fink" and have fink install wget for you: * Download fink from fink.sourceforge.net. Follow the instructions provided there to install it. * Now install wget. Type sudo apt-get install wget and enter your administrator password when prompted. (Users of Plait 0.53 and earlier also need to take the following step: * Install gawk and findutils. Type sudo apt-get install gawk findutils Newer versions of Plait don't depend on these packages.) ### GNU/Linux prerequisites On GNU/Linux, Plait works with ogg123, mpg123, mpg321, Xmms, Beep Media Player, or amaroK. If you are using Xmms, xmms-shell is also required. Installation varies depending on your distro. Be sure to install the package esound if you want to play via esd. Xmms, Beep Media Player, or amaroK will be used if they are present. If not, Plaiter will be used as a front end to any command line players that are present. Otherwise Plait will work in "list only" mode unless you configure your own player. ### Finishing up (all operating systems) You now have all the prerequisites to run Plait. The last step is installing Plait itself: * Untar the package: tar xvzf plait-x.xx.tar.gz cd plait * Tell `plait` to install itself. You may run this command as a non-root user, in which case Plait will default to installing in your home directory; you may run it as root, in which case Plait will default to installing in /usr/local; or you may set the install directory to anything you like by providing an argument. Examples: su -c "./plait --install" or sudo ./plait --install or ./plait --install or sudo ./plait --install /usr If you install Plait as a non-root user, you may have to add ~/bin to your path. On Cygwin, the install routine does not actually check whether you are root, but rather whether or not you have permission to touch root's files. This works well because a typical install of Cygwin creates a non-root user with root permissions, and there is no su command. Thus (on Cygwin only), as long as you have permission to touch root's files, install will default to /usr/local. Plait is now ready to run. The first time you run it, Plait will do some additional self-installation which involves asking for the location of your music directory. You only have to do this once. ### Setting up for XSPF If you want to use the XSPF web publishing feature, you will need to install the XSPF Web Music Player (http://musicplayer.sourceforge.net). Download and unpack the player from that address and then copy the file xspf_player.swf to ~/.plait/xspf. If your music library is located on a web server, you also need to set the variable BASEURL, for example: BASEURL=http://www.example.com/mp3/ Otherwise, leave BASEURL set to the empty string. If your music directory is laid out as Artist/Album/Song, you're all set. Otherwise, you may need to set the three variables ARTISTIDX, ALBUMIDX, and SONGIDX in the config file. For Example, if your music directory is laid out as Artist/Year/Album/Song, set ARTISTIDX=1 ALBUMIDX=3 SONGIDX=4 If your music directory is laid out as Artist/Artist - Album - Song, set LEVELSEP="(/| - )" ARTISTIDX=1 ALBUMIDX=3 SONGIDX=4 9. Uninstallation ------------------ If you installed Plait as root, you must be root to uninstall it; otherwise you must be the same user as you were during installation. Type su -c "plait --uninstall" or sudo plait --uninstall or just plait --uninstall to uninstall Plait. See the instructions that came with gen_com if you want to remove that plugin. To remove wget, gawk or findutils, follow the package removal technique for Cygwin or Fink, as appropriate. If you are updating Plait, and you decide to install it into a different directory this time, uninstall the old version before installing the new one. Otherwise two versions of Plait will be installed and you can't be sure which one will run. 10. Customization ------------------ There are a few changes you can make to ~/.plait/config to customize the behavior of Plait. #### File types By default Plait looks for files of type mp3, wav, aif, ogg and flac. You can change this by setting the variable TYPES, for example: TYPES=".ogg .mp3 .flac" You may need to run `plait --cache` to rebuild the cache after changing the file types. As of Plait 1.2, you are advised to set the variable TYPES once to a very broad set of file types, and then use target devices to customize your playlists for different devices. You can either redefine one of the built-in target devices, or define a new one. For example, to define a target device that supports the same file types as an iPod, add the following line to the config file: ipod="m4a M4A mp3 MP3 wav WAV" In contrast to the TYPES variable, with devices you don't include the dot in the file extension, and you must repeat each extension twice, in upper and lower case. In this list, order is important; thus the ipod device will prefer mp3 files to wav files. To use this device to build a playlist, select it on the command line: plait britney --device ipod You can also set the default device in the config file: DEVICE="$ipod" Important note: if you redefine the default device (hifi), you should then reassign DEVICE to it in the config file, ie: hifi="wav WAV flac FLAC" DEVICE="$hifi" Otherwise DEVICE will continue to have the old value of hifi from before it was redefined. #### Alternate players Although there is a default player on each operating system, some OSs support several players. You can pick something besides the default by setting the variable PLATFORM, for example: PLATFORM=linux-plaiter The currently supported platforms are: cygwin-winamp, cygwin-itunes, osx-itunes, linux-xmms, linux-beep-media-player, linux-amarok, linux-mpg123, linux-mpg123-esd, linux-mpg321, linux-mpg321-esd, linux-ogg123, linux-ogg123-esd, linux-plaiter, any-xspf and any-xspf-copy. In the interest of accuracy, there are also "unix-" synonyms for all the "linux-" players. The "esd" platforms play via the Enlightened Sound Daemon, which can stream audio across the network to an esd server. You specify which server by setting ESPEAKER, for example: ESPEAKER=192.168.1.2:16001 See README.plaiter for information on Plaiter, which is the ideal platform choice if you currently use a command line player like mpg123. 11. XSPF Playlists ------------------- Plait can generate a complete web site with an embedded MP3 playlist, including an XSPF playlist, a web page that embeds the XSPF Web Music Player (http://musicplayer.sourceforge.net), and MP3 files. The steps are as follows: 1. Download and unpack the web music player from the site above. Copy the file xspf_player.swf to ~/.plait/xspf. 2. Customize the file /usr/share/plait/playlist.html, if you like. It is a template file in which the special text string "%TITLE%" will be replaced by the playlist title generated automatically by Plait. 3. Set the variable BASEURL appropriately in the config file (see below). You may also need to set the variables ARTISTIDX, ALBUMIDX, and SONGIDX. See the section on installation. 4. Run an appropriate Plait command to generate a playlist (see below). 5. Upload the directory ~/.plait/xspf to a new directory on your web server. 6. Test the playlist by loading the file playlist.html from the upload directory into your browser. The Plait command you run depends on where your music library is located: if it is located on your web server where MP3 files can be loaded via a URL, the MP3s can be accessed in place. In this case, set the variable BASEURL in the Plait config file to the base address of your MP3 directory, for example BASEURL=http://www.example.com/mp3/ Then generate a playlist with a command like the following: plait "Dire Straits" --tracks 7 --platform any-xspf --device compact --coverart 1 and upload the directory ~/.plait/xspf to your web server. The flag "--coverart 1" is optional and causes Plait to look up album cover art on Amazon. You can turn this feature on permanently by setting COVERART=1 in the config file (in which case you can turn it off temporarily with the flag "--coverart 0"). If your music library is not on a web server, you will need to upload the MP3 files in the playlist to your server as well. In that case, leave BASEURL set to the empty string. Then generate a playlist with a command like the following: plait "Dire Straits" --tracks 7 --platform any-xspf-copy --device compact This form of the command actually copies MP3 files into the directory ~/.plait/xspf, which you then upload. You may want to clean old MP3 files out of this directory periodically to avoid unnecessary uploads. Of course, you can always pick and choose which files to upload depending upon your application. The file playlist.html can be used as an example if you prefer to embed the playlist in a preexisting web page. 12. Bugs --------- Plait does a poor job of handling file names with various accent characters. iTunes refuses to play these files at all, because Applescript can't translate them into Macintosh file paths. On other platforms you should be able to play these files, but it is still difficult to search for them, because Plait doesn't know how to ignore accent marks when making string comparisons. The problem does not just involve comparing characters that could be considered equivalent in the current locale, which would be resolved by equivalence classes; here the problem is to compare characters which could be considered equivalent in any locale. There is a version of `agrep` for OS/2 and Windows which can do this type of accent-insensitive comparison, so if you are interested in this problem, bug the authors of `agrep` about back-porting this feature to UNIX. 13. What's next ---------------- Who knows? Copyright (c) 2005-2008 by Stephen Jungels plait/COPYING0000700000076500007650000004313510310366574014746 0ustar sjungelssjungels00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Street, Fifth Floor, Boston, MA 02110-1301, USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. plait/querystream.awk0000700000076500007650000000375110452075216016775 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { interactive = 0; } // { record = 1; row = ""; save = 0; } { if (record==1) row = row $0; } /playlist.pls/ { save = 1; } /<\/tr>/ { if (save==1) { hit = 1; nh = split(hints, hint); i = 1; while (i<=nh) { gsub ("_", " ", hint[i]); if (hint[i]=="not" && i < nh) { gsub("_", " ", hint[i+1]); if (match(tolower(row), tolower(hint[i+1]))) { hit = 0; break; } else i += 2; } else { if (mix==0 && !match(tolower(row), tolower(hint[i]))) { hit = 0; break; } else i++; } } if (hit==1) { if (interactive==1) { if (match(row, \ /.*?<\/a>/) > 0) { desc = substr(row, RSTART, RLENGTH); sub(//, "", desc); gsub("", "", desc); gsub("<[^>]*>", "", desc); if (match(row, /shoutcast-playlist.pls\?rn=[0-9]+&file=filename.pls/) > 0) { a = substr(row, RSTART, RLENGTH); printf("# %s\n", desc); printf "http://www.shoutcast.com/sbin/%s\n", a; } } } else { if (match(row, /shoutcast-playlist.pls\?rn=[0-9]+&file=filename.pls/) > 0) { a = substr(row, RSTART, RLENGTH); printf "http://www.shoutcast.com/sbin/%s\n", a; } } } } save = 0; record = 0; } plait/plaiter0000700000076500007650000004320511062604127015266 0ustar sjungelssjungels00000000000000#!/bin/bash # Plaiter -- front end to mpg123 et al # # Copyright (C) 2005, 2006 Stephen Jungels # # # 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. # # See COPYING for the full text of the license. # # See README.plaiter for supported platforms and installation # instructions. # # To contact the author: sjungels@gmail.com usage () { echo "Usage is:" echo " \"plaiter [options] [file, playlist, directory or stream ...]\"" echo "Options:" echo " --daemon,-d -- daemon mode" echo " --queue,-q -- add tracks to queue" echo " --enqueue -- add tracks to queue" echo " --random -- random shuffle" echo " --play -- play" echo " --pause -- toggle pause mode" echo " --stop,-s -- stop" echo " --latch [on|off] -- toggle or set stop after current track" echo " --next,-n [n] -- skip forward [n tracks]" echo " --prev [n] -- skip backward [n tracks]" echo " --search -- search in playlist" echo " --rsearch -- reverse search in playlist" echo " --reset,-r -- play track 1" echo " --loop [on|off] -- toggle or set loop mode" echo " --quit -- quit daemon" echo " --status -- show status" echo " --list,-l -- show playlist" echo " --help -- show help" echo " --version -- show version" echo " -v -- be verbose" } version () { echo "Plaiter v 1.4.2" echo "Written by Stephen Jungels (sjungels@gmail.com)" echo "" echo "Copyright (c) 2005, 2006 by Stephen Jungels. Released under the GPL." echo "Latest version and more info at http://jungels.net/projects/plait/" } maybe_install () { mkdir -p "$HOME/.plait" if ! test -f "$HOME/.plait/helpers" || test $INSTALL -gt 0 then echo Detecting helper applications... rm -f "$HOME/.plait/helpers" touch "$HOME/.plait/helpers" ogg=`which ogg123 2>/dev/null` if ! test "-$ogg-" = "--" then echo "ogg:ogg123" >> "$HOME/.plait/helpers" echo "httpogg:ogg123" >> "$HOME/.plait/helpers" echo "flac:ogg123" >> "$HOME/.plait/helpers" fi mpg=`which mpg123-esd 2>/dev/null` if ! test "-$mpg-" = "--" then echo "mp3:mpg123-esd" >> "$HOME/.plait/helpers" echo "httpmp3:mpg123-esd" >> "$HOME/.plait/helpers" echo "http:mpg123-esd" >> "$HOME/.plait/helpers" else mpg=`which mpg123 2>/dev/null` if ! test "-$mpg-" = "--" then echo "mp3:mpg123" >> "$HOME/.plait/helpers" echo "httpmp3:mpg123" >> "$HOME/.plait/helpers" echo "http:mpg123" >> "$HOME/.plait/helpers" else mpg=`which mpg321 2>/dev/null` if ! test "-$mpg-" = "--" then echo "mp3:mpg321" >> "$HOME/.plait/helpers" echo "httpmp3:mpg321" >> "$HOME/.plait/helpers" echo "http:mpg321" >> "$HOME/.plait/helpers" fi fi fi echo Wrote $HOME/.plait/helpers fi if ! test -f "$HOME/.plait/key.awk" || test $INSTALL -gt 0 then cat > "$HOME/.plait/key.awk" < 1) { mime = protocol[1]; n = split (\$0, suffix, "."); if (suffix[n]=="mp3" || suffix[n]=="ogg") { mime = mime suffix[n]; } } else { n = split (\$0, suffix, "."); mime = suffix[n]; } print mime } EOF fi } next_track () { if test "-$1-" = "--" then jump=1 else jump=$1 fi maxindex=`cat "$HOME/.plait/plaiter.m3u" | wc -l` j2=`expr $jump % $maxindex` if test $j2 -ne 0 then track=`expr $listindex + $j2` if test $track -gt $maxindex then if test $loopmode = 0 then track=$maxindex else track=`expr $track % $maxindex` fi fi else track=$listindex fi } prev_track () { if test "-$1-" = "--" then jump=1 else jump=$1 fi maxindex=`cat "$HOME/.plait/plaiter.m3u" | wc -l` j2=`expr $jump % $maxindex` if test $j2 -ne 0 then track=`expr $listindex - $j2` if test $track -lt 1 then if test $loopmode = 0 then track=1 else track=`expr $maxindex + $track` fi fi else track=$listindex fi } play_current_song () { while true do song=`cat "$HOME/.plait/plaiter.m3u" | awk "{if (FNR==$listindex) print}"` if ! test "-$song-" = "--" then key=`echo "$song" | awk -f "$HOME/.plait/key.awk"` HELPER=`cat "$HOME/.plait/helpers" | awk -v key=$key \ 'BEGIN{FS=":"}{if (tolower(key) ~ tolower($1)) {print $2; exit}}'` if ! test "-$HELPER-" = "--" then $HELPER "$song" & playerpid=$! HELPERNAME=`echo "$HELPER" | awk '{print $1}'` if test $VERBOSE -gt 0 then echo Ran command $HELPER $song echo "playerpid = $playerpid" echo helpername = $HELPERNAME fi break else if test $VERBOSE -gt 0 then echo "I don't have a helper for the key $key" fi next_track if test $listindex = $track then paused=1 break else listindex=$track fi fi else if test $VERBOSE -gt 0 then echo No current song fi paused=1 break fi done } handle_interrupt () { # if HELPER exited, restart it on the next track if test $paused = 0 && ! test $playerpid = 0 then tries=0 while true do tmpfile="$(mktemp /tmp/plait.XXXXXX)" ps -p $playerpid > $tmpfile foo=`grep "$HELPERNAME" $tmpfile` if test "-$foo-" = "--" then if test $VERBOSE -gt 0 then echo Did not find $HELPERNAME echo Selecting next track fi playerpid=0 next_track if test $listindex = $track then if test $VERBOSE -gt 0 then echo Reached end of playlist fi paused=1 else listindex=$track if test $stoplatch = 0 then play_current_song else stoplatch=0 paused=1 fi fi break else if test $tries -ge 1 then if test $VERBOSE -gt 0 then echo Found $HELPERNAME, giving up after second try fi break else if test $VERBOSE -gt 0 then echo Found $HELPERNAME, trying again fi tries=`expr $tries + 1` sleep 1 fi fi done fi } maybe_kill_player () { if ! test $playerpid = 0 then kill -9 >/dev/null 2>&1 $playerpid playerpid=0 return 1 else return 0 fi } do_quit () { maybe_kill_player rm -f $HOME/.plait/pdaemon exit 0 } write_status () { if test -e "$HOME/.plait/plaiter.m3u" then numtracks=`cat "$HOME/.plait/plaiter.m3u" | wc -l` song=`cat "$HOME/.plait/plaiter.m3u" | awk "{if (FNR==$listindex) print}"` else numtracks = 0 song = "" fi if test $playerpid = 0 then status="STOPPED on track $listindex of $numtracks" elif test $paused = 1 then status="PAUSED on track $listindex of $numtracks" else status="PLAYING track $listindex of $numtracks" fi if test $loopmode = 1 then status="$status -- Loop on" fi if test $stoplatch = 1 then status="$status -- Latch on" fi echo $status > "$HOME/.plait/status" echo $song >> "$HOME/.plait/status" } daemon_mode () { if test -e "$HOME/.plait/pdaemon" then echo Daemon seems to be running sleep 3 & echo nop > "$HOME/.plait/pdaemon" if test $? = 0 then kill $! echo Yes, it is running, exiting exit 1 else echo No response from daemon, cleaning up rm "$HOME/.plait/pdaemon" fi fi mkfifo "$HOME/.plait/pdaemon" trap "echo Got SIGINT, cleaning up; do_quit" INT stoplatch=0 loopmode=0 playerpid=0 listindex=1 paused=1 while true do write_status while true do read cmd args < $HOME/.plait/pdaemon if test $? -ne 0 then if test $VERBOSE -gt 0 then echo Got interrupt fi handle_interrupt write_status else break fi done if test $VERBOSE -gt 0 then echo Read command $cmd fi case "$cmd" in play) if test $playerpid = 0 then play_current_song paused=0 elif test $paused = 1 then paused=0 kill -s CONT $playerpid fi ;; pause) if ! test $playerpid = 0 then if test $paused = 0 then paused=1 kill -s STOP $playerpid if test $VERBOSE -gt 0 then echo Pausing fi else paused=0 kill -s CONT $playerpid if test $VERBOSE -gt 0 then echo Unpausing fi fi fi ;; stoplatch) if test "-$args-" = "-on-" then stoplatch=1 elif test "-$args-" = "-off-" then stoplatch=0 elif test $stoplatch = 0 then stoplatch=1 else stoplatch=0 fi if test $VERBOSE -gt 0 then echo Setting stop latch: $stoplatch fi ;; stop) maybe_kill_player if test $? = 1 then paused=1 if test $VERBOSE -gt 0 then echo Stopping fi fi ;; next) maybe_kill_player if test $? = 1 then next_track $args if test $track = $listindex then paused=1 else listindex=$track play_current_song fi else next_track $args listindex=$track fi if test $VERBOSE -gt 0 then echo New track: $listindex fi ;; prev) maybe_kill_player if test $? = 1 then prev_track $args if test $listindex = $track then paused=1 else listindex=$track play_current_song fi else prev_track $args listindex=$track fi if test $VERBOSE -gt 0 then echo New track: $listindex fi ;; search) track=`cat "$HOME/.plait/plaiter.m3u" | awk -v a="$args" -v li=$listindex \ '{if (tolower($0) ~ tolower(a) && (track==0 || (track<=li && FNR > li)) && FNR!=li) track=FNR}END{print track}'` if ! test $track = 0 then maybe_kill_player listindex=$track if test $VERBOSE -gt 0 then echo New track: $listindex fi play_current_song fi ;; rsearch) track=`cat "$HOME/.plait/plaiter.m3u" | awk -v a="$args" -v li=$listindex \ '{if (tolower($0) ~ tolower(a) && (FNR
  • li) && FNR!=li) track=FNR}END{print track}'` if ! test $track = 0 then maybe_kill_player listindex=$track if test $VERBOSE -gt 0 then echo New track: $listindex fi play_current_song fi ;; reset) maybe_kill_player listindex=1 paused=0 stoplatch=0 play_current_song if test $VERBOSE -gt 0 then echo New track: $listindex fi ;; loop) if test "-$args-" = "-on-" then loopmode=1 elif test "-$args-" = "-off-" then loopmode=0 elif test $loopmode = 0 then loopmode=1 else loopmode=0 fi if test $VERBOSE -gt 0 then echo Setting loop mode: $loopmode fi ;; quit) if test $VERBOSE -gt 0 then echo Quitting fi do_quit ;; nop) ;; *) if test $VERBOSE -gt 0 then echo Ignoring unknown command $cmd fi ;; esac done } start_daemon () { if test $VERBOSE -gt 0 then echo Starting daemon fi plaiter --daemon > /dev/null 2>&1 & # pause a moment to let the daemon start up for i in 1 2 3 4; do for j in 1 2 3 4; do echo > /dev/null; done; done while true do if test -e "$HOME/.plait/pdaemon" then break fi sleep 1 done } controller_mode () { if test $QUEUE = 0 && ! test "-$1-" = "--" then rm -f "$HOME/.plait/plaiter.m3u" fi rm -f "$HOME/.plait/plaiter0.m3u" while test $# -gt 0 do if test $VERBOSE -gt 0 then echo Adding $1 to playlist fi if test -d "$1" then odir="`pwd`" cd "$1" dir="`pwd`" cd "$odir" find "$dir" -type f | sort >> "$HOME/.plait/plaiter0.m3u" elif test -f "$1" then case "$1" in *.m3u|*.M3U|*.m3U|*.M3u) cat "$1" | awk '{if ($0 !~ /^#/) print}' >> "$HOME/.plait/plaiter0.m3u" ;; *) odir="`pwd`" cd "`dirname \"$1\"`" dir="`pwd`" cd "$odir" file="`basename \"$1\"`" echo "$dir/$file" >> "$HOME/.plait/plaiter0.m3u" ;; esac else case "$1" in http*) echo "$1" >> "$HOME/.plait/plaiter0.m3u" ;; esac fi shift done touch "$HOME/.plait/plaiter0.m3u" # possibly shuffle the playlist if test $ORDER = "random" then tmpfile="$(mktemp /tmp/plait.XXXXXX)" cat "$HOME/.plait/plaiter0.m3u" | awk 'BEGIN{srand()} {print rand() "\t" $0}' | \ sort -n | cut -f "2-" > $tmpfile mv $tmpfile "$HOME/.plait/plaiter0.m3u" fi cat "$HOME/.plait/plaiter0.m3u" >> "$HOME/.plait/plaiter.m3u" # before sending a command, make sure daemon is active if ! test -e "$HOME/.plait/pdaemon" then start_daemon fi # --status is a pseudo command that doesn't get sent to the daemon if test $DOSTATUS -gt 0 then if test -e "$HOME/.plait/status" then cat "$HOME/.plait/status" fi fi # --list is a pseudo command that doesn't get sent to the daemon if test $DOLIST -gt 0 then if test -e "$HOME/.plait/plaiter.m3u" then cat "$HOME/.plait/plaiter.m3u" fi fi # there are default commands in certain cases if test $QUEUE = 0 && test "-$COMMAND-" = "--" && test $DOSTATUS = 0 && test $DOLIST = 0 then COMMAND=reset elif test $QUEUE -gt 0 && test "-$COMMAND-" = "--" && test $DOSTATUS = 0 && test $DOLIST = 0 then COMMAND=play fi if ! test "-$COMMAND-" = "--" then while true do if test $VERBOSE -gt 0 then echo Sending command $COMMAND fi sleep 3 & echo $COMMAND > "$HOME/.plait/pdaemon" if test $? = 0 then kill $! break else if test $VERBOSE -gt 0 then echo Had to clean up pipe, trying again fi rm "$HOME/.plait/pdaemon" start_daemon fi done fi } QUEUE=0 DAEMONMODE=0 COMMAND="" VERBOSE=0 INSTALL=0 DOSTATUS=0 DOLIST=0 ORDER="sort" while test $# -gt 0 do case "$1" in --queue|--enqueue|-q) QUEUE=1 shift ;; --play) COMMAND=play shift ;; --pause) COMMAND=pause shift ;; --latch) if test "-$2-" = "-on-" || test "-$2-" = "-off-" then COMMAND="stoplatch $2" shift else COMMAND=stoplatch fi shift ;; --stop|-s) COMMAND=stop shift ;; --next|-n) if test "-$2-" = "--" then COMMAND="next" else if test 2>/dev/null $2 -gt -1 then COMMAND="next $2" shift else COMMAND=next fi fi shift ;; --prev) if test "-$2-" = "--" then COMMAND="prev" else if test 2>/dev/null $2 -gt -1 then COMMAND="prev $2" shift else COMMAND=prev fi fi shift ;; --search) COMMAND="search $2" shift shift ;; --rsearch) COMMAND="rsearch $2" shift shift ;; --reset|-r) COMMAND=reset shift ;; --loop) if test "-$2-" = "-on-" || test "-$2-" = "-off-" then COMMAND="loop $2" shift else COMMAND=loop fi shift ;; --quit) COMMAND=quit shift ;; --random) ORDER=random shift ;; --status) DOSTATUS=1 shift ;; --list|-l) DOLIST=1 shift ;; --daemon|-d) DAEMONMODE=1 shift ;; --install) INSTALL=1 shift ;; --help) usage exit 0 ;; --version) version exit 0 ;; -v) VERBOSE=1 shift ;; -*) echo Ignoring bad option $1 shift ;; *) break ;; esac done CYGWIN=`uname -s | grep -ic CYGWIN` if test $CYGWIN -ge 1 then echo Sorry, plaiter does not run on Cygwin exit 0 fi maybe_install if test $INSTALL = 1 then exit 0 elif test $DAEMONMODE = 1 then daemon_mode exit 0 else controller_mode "$@" exit 0 fi plait/plaiter.10000700000076500007650000000315211063224304015416 0ustar sjungelssjungels00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. .TH PLAITER "1" "September 2008" "Plaiter v 1.4.2" "User Commands" .SH NAME Plaiter \- manual page for Plaiter v 1.4.2 .SH DESCRIPTION .SS "Usage is:" .IP "plaiter [options] [file, playlist, directory or stream ...]" .SH OPTIONS .HP \fB\-\-daemon\fR,-d \fB\-\-\fR daemon mode .HP \fB\-\-queue\fR,-q \fB\-\-\fR add tracks to queue .HP \fB\-\-enqueue\fR \fB\-\-\fR add tracks to queue .HP \fB\-\-random\fR \fB\-\-\fR random shuffle .HP \fB\-\-play\fR \fB\-\-\fR play .HP \fB\-\-pause\fR \fB\-\-\fR toggle pause mode .HP \fB\-\-stop\fR,-s \fB\-\-\fR stop .HP \fB\-\-latch\fR [on|off] \fB\-\-\fR toggle or set stop after current track .HP \fB\-\-next\fR,-n [n] \fB\-\-\fR skip forward [n tracks] .HP \fB\-\-prev\fR [n] \fB\-\-\fR skip backward [n tracks] .HP \fB\-\-search\fR \fB\-\-\fR search in playlist .HP \fB\-\-rsearch\fR \fB\-\-\fR reverse search in playlist .HP \fB\-\-reset\fR,-r \fB\-\-\fR play track 1 .HP \fB\-\-loop\fR [on|off] \fB\-\-\fR toggle or set loop mode .HP \fB\-\-quit\fR \fB\-\-\fR quit daemon .HP \fB\-\-status\fR \fB\-\-\fR show status .HP \fB\-\-list\fR,-l \fB\-\-\fR show playlist .HP \fB\-\-help\fR \fB\-\-\fR show help .HP \fB\-\-version\fR \fB\-\-\fR show version .HP \fB\-v\fR \fB\-\-\fR be verbose .SH AUTHOR Written by Stephen Jungels (sjungels@gmail.com) .SH COPYRIGHT Copyright \(co 2005, 2006 by Stephen Jungels. Released under the GPL. Latest version and more info at http://jungels.net/projects/plait/ plait/README.plaiter0000700000076500007650000002116611062604301016216 0ustar sjungelssjungels00000000000000README for Plaiter v 1.4.2 ========================== 0. Introduction --------------- Plaiter (pronounced "player") is a command line front end to command line music players. It uses shell scripting to try to create the command line music player that Plait would have used if it already existed. It complements Plait but is also quite useful on its own, especially if you already use mpg123 or similar programs and find yourself wanting more features. What does Plaiter do that mpg123 can't already? It queues tracks, first of all. Secondly, it understands commands like play, plause, stop, next and prev. Finally, unlike most of the command line music players out there, Plaiter can handle a play list with more than one type of audio file, selecting the proper helper app to handle each type of file you throw at it. Plaiter will automatically configure itself to use ogg123, mpg123, and/or mpg321, if they are installed on your system. If you have a helper application that plays other types of audio, Plaiter can be configured to use it as well. Like many of us, Plaiter is part daemon and part controller. The controller builds a play list from the files you provide on the command line and forwards commands to the daemon. The daemon reads commands and executes them by running helper applications. 0.1. What's new --------------- Release 1.4.2 fixes a security flaw related to temp files. Upgrading is highly recommended. 1. Playing music ---------------- The simplest way to use Plaiter is to invoke it with a list of music you want to play, for example plaiter foo.mp3 bar.ogg baz.flac or plaiter http://205.234.188.20:80/ Plaiter also understands directories as arguments, in which case it tries to play every file in the directory. If some of the files are not music files, that's all right because Plaiter will discover it doesn't have a helper application for that type of file and skip it. An example would be plaiter "/music/Disco Hits of the 70s" Plaiter also understands play lists, for example, plaiter list.m3u It is the .m3u extension which identifies a file as a play list and nothing else will be treated as a play list. Plaiter does not currently understand directories of play lists, but you can use shell globbing to get the same effect, for example plaiter /music/partylists/*.m3u The shell will expand this to a list of play lists, which Plaiter *does* understand. You can also use globbing to expand a directory that contains a combination of play lists and music files. When you invoke Plaiter in this way it runs in controller mode, which is not capable of actually playing music. Behind the scenes the controller will start another instance of Plaiter in daemon mode, if one is not running already, and forward commands to it. 2. Sending commands ------------------- A variety of commands are available to control the daemon. You specify a command as a two dash option, for example plaiter --play The seven basic commands are: play, pause, stop, next, prev, reset and quit. They do pretty much what you would expect. Reset sets the current track to 1 and starts playing. It is the command that Plaiter sends automatically whenever it creates a new play list. Next and prev take optional numeric arguments that specify how many tracks to skip, counting the current track. The default is one. There is a search command that provides a search-in-playlist feature. For example, plaiter --search fly looks for a track that contains the string "fly" and plays it if found. Search proceeds forwards from the current track until the first match is found, wrapping at the end of the playlist. If no match is found the current track continues playing. The search string can be a regular expression. There is also an rsearch command that does reverse search. It proceeds backwards from the current track until the first match is found, wrapping at the beginning of the list. For example, plaiter --rsearch one The loop command toggles or sets loop mode. When loop mode is on and the end of the playlist is reached, play continues on the first track. When loop mode is off and the end of the playlist is reached, play stops. Loop mode also affects the behavior of the next and prev commands. The loop command looks like this: plaiter --loop plaiter --loop on plaiter --loop off The latch command toggles or sets a latch which will cause playback to stop when the current track ends. The latch command looks like this: plaiter --latch plaiter --latch on plaiter --latch off 3. Options ---------- ### --status. This option just prints basic information about what Plaiter is doing: the number of tracks in the playlist, the current track, and whether Plaiter is playing, paused, or stopped. ### --list This option displays the playlist. ### --random The --random option shuffles the playlist as it is added. Thus if you use it with the --queue option, only the new tracks are shuffled. ### --queue, -q, --enqueue The --queue option causes tracks to be queued on an existing playlist rather than replacing it. --enqueue is for compatibility with players like BMP, amaroK, and XMMS. ### --daemon, -d The --daemon option selects daemon mode. See the next section. ### --help This option shows brief help. ### --version This option shows information about the version, the license, and the author. ### --play, --pause, --stop, --next, --prev, --reset, --quit These commands are forwarded to the daemon. ### --loop, --search, --rsearch, --latch These commands are forwarded to the daemon. ### --install This option rewrites the helper file. See Section 5. 4. Daemon mode -------------- The Plaiter daemon will be started for you automatically if necessary, but there are times when you may want to start it manually. Why is that? Well, the Plaiter daemon (and the helper applications it calls) tend to be quite verbose, so the controller discards their output. If you want to see the output, you can dedicate a separate console to this purpose. This gives you a nice clean command line interface to Plaiter in the main console, with complete information, including the current track, in the daemon console. You start Plaiter in daemon mode by typing plaiter --daemon The proper way to kill the daemon is to send it the command "quit" or type Ctrl-c in its console. If you `kill -9` it, the daemon will not get a chance to clean up after itself. You can do this manually by typing rm -f ~/.plait/pdaemon If you don't, Plaiter will try to clean up the next time it runs. 5. Helper applications ---------------------- Plaiter stores a list of file types and associated helper applications in ~/.plait/helpers. This file will be created automatically the first time Plaiter is run, but you can edit it to select the helper applications you prefer. If you don't edit it, Plaiter will look for ogg123, mpg123-esd, mpg123, and mpg321. If it is present on your system, ogg123 will be associated with ogg files, flac files, and ogg streams. For mp3 files, mp3 streams, and all streams whose type can't be identified from the URL, mpg123-esd will be chosen if present, then mpg123, then mpg321. Each line of ~/.plait/helpers consists of a "key" and a helper, separated by a colon, for example mp3:mpg123-esd The key corresponding to a file is just the file suffix. For http streams it's a little more complicated. A URL with no particular file suffix, like http://192.168.1.2:80, will have the key "http". Plaiter assumes that streams like this can be played by mpg123. If the URL has an mp3 or ogg suffix, that is included in the key, so the key for http://192.168.1.2:80/stream.ogg would be "httpogg". Plaiter assumes that ogg123 can play a stream like this. Adding your own helper applications is just a matter of following these rules to create an appropriate key, followed by a colon, followed by the command line required to play that type of file. If you want Plaiter to configure itself automatically, you should install the helper applications before running it for the first time. If you didn't do that, you can run plaiter --install to force Plaiter to detect helper applications and write the helper file again. 6. Odds and ends ---------------- Plaiter requires Bash. It uses standard versions of basic commands including find, awk and sed and should be compatible with most versions of Unix. It requires a wake up call when the signal SIGCHLD is received, which seems to rule out Cygwin for now. That's all right because Cygwin users have Winamp. 7. What's next -------------- It's not known at this time what features will be in the next release. Copyright (c) 2005, 2006 by Stephen Jungels plait/INSTALL0000700000076500007650000001756011063224262014740 0ustar sjungelssjungels00000000000000Install Guide for Plait v 1.6.2 =============================== 1. Installation ---------------- Since Plait is glue ware, it has several dependencies. Follow these instructions to make it all work. ### Uninstallation As of Plait 1.5.2, it is possible to install Plait to a directory of your choice. Since this could lead to a situation where you have multiple versions of Plait installed in different directories, it's a good idea to uninstall any old versions of Plait prior to upgrading. But if you know you are installing to the same directory as the old version of Plait, this isn't really necessary. ### Windows/Cygwin prerequisites Running Plait on Windows requires that you install Cygwin, the open source UNIX compatibility layer for Windows. Follow the instructions at Cygwin.com to download and install Cygwin. Plait also requires two optional packages, wget and gawk. Be sure to select these packages when you run Cygwin Setup. For those who are using Winamp, you may need to install it. Get Winamp at Winamp.com. In order to control Winamp, Plait uses a COM object written by John Adcock. To install it: * Download gen_com.zip from www.adcock8.freeserve.co.uk/winamp.htm * Unzip. * Copy gen_com.dll into the C:\Program Files\Winamp\Plugins directory. * Restart Winamp. Winamp will detect and install the new plugin. For those using iTunes, a standard installation of that program should work without any additional steps, but you need to edit the file ~/.plait/config to make iTunes your music player. Change the line that defines PLATFORM to read PLATFORM=cygwin-itunes ### OS X prerequisites Running Plait on OS X requires one package that isn't part of the default install: wget. You can compile wget from source and install it yourself, if you know how to do that sort of thing. The easier option is to install "fink" and have fink install wget for you: * Download fink from fink.sourceforge.net. Follow the instructions provided there to install it. * Now install wget. Type sudo apt-get install wget and enter your administrator password when prompted. (Users of Plait 0.53 and earlier also need to take the following step: * Install gawk and findutils. Type sudo apt-get install gawk findutils Newer versions of Plait don't depend on these packages.) ### GNU/Linux prerequisites On GNU/Linux, Plait works with ogg123, mpg123, mpg321, Xmms, Beep Media Player, or amaroK. If you are using Xmms, xmms-shell is also required. Installation varies depending on your distro. Be sure to install the package esound if you want to play via esd. Xmms, Beep Media Player, or amaroK will be used if they are present. If not, Plaiter will be used as a front end to any command line players that are present. Otherwise Plait will work in "list only" mode unless you configure your own player. ### Finishing up (all operating systems) You now have all the prerequisites to run Plait. The last step is installing Plait itself: * Untar the package: tar xvzf plait-x.xx.tar.gz cd plait * Tell `plait` to install itself. You may run this command as a non-root user, in which case Plait will default to installing in your home directory; you may run it as root, in which case Plait will default to installing in /usr/local; or you may set the install directory to anything you like by providing an argument. Examples: su -c "./plait --install" or sudo ./plait --install or ./plait --install or sudo ./plait --install /usr If you install Plait as a non-root user, you may have to add ~/bin to your path. Plait is now ready to run. The first time you run it, Plait will do some additional self-installation which involves asking for the location of your music directory. You only have to do this once. ### Setting up for XSPF If you want to use the XSPF web publishing feature, you will need to install the XSPF Web Music Player (http://musicplayer.sourceforge.net). Download and unpack the player from that address and then copy the file xspf_player.swf to ~/.plait/xspf. If your music library is located on a web server, you also need to set the variable BASEURL, for example: BASEURL=http://www.example.com/mp3/ Otherwise, leave BASEURL set to the empty string. If your music directory is laid out as Artist/Album/Song, you're all set. Otherwise, you may need to set the three variables ARTISTIDX, ALBUMIDX, and SONGIDX in the config file. For Example, if your music directory is laid out as Artist/Year/Album/Song, set ARTISTIDX=1 ALBUMIDX=3 SONGIDX=4 If your music directory is laid out as Artist/Artist - Album - Song, set LEVELSEP="(/| - )" ARTISTIDX=1 ALBUMIDX=3 SONGIDX=4 2. Uninstallation ------------------ If you installed Plait as root, you must be root to uninstall it; otherwise you must be the same user as you were during installation. Type su -c "plait --uninstall" or sudo plait --uninstall or just plait --uninstall to uninstall Plait. See the instructions that came with gen_com if you want to remove that plugin. To remove wget, gawk or findutils, follow the package removal technique for Cygwin or Fink, as appropriate. If you are updating Plait, and you decide to install it into a different directory this time, uninstall the old version before installing the new one. Otherwise two versions of Plait will be installed and you can't be sure which one will run. 3. Customization ------------------ There are a few changes you can make to ~/.plait/config to customize the behavior of Plait. #### File types By default Plait looks for files of type mp3, wav, aif, ogg and flac. You can change this by setting the variable TYPES, for example: TYPES=".ogg .mp3 .flac" You may need to run `plait --cache` to rebuild the cache after changing the file types. As of Plait 1.2, you are advised to set the variable TYPES once to a very broad set of file types, and then use target devices to customize your playlists for different devices. You can either redefine one of the built-in target devices, or define a new one. For example, to define a target device that supports the same file types as an iPod, add the following line to the config file: ipod="m4a M4A mp3 MP3 wav WAV" In contrast to the TYPES variable, with devices you don't include the dot in the file extension, and you must repeat each extension twice, in upper and lower case. In this list, order is important; thus the ipod device will prefer mp3 files to wav files. To use this device to build a playlist, select it on the command line: plait britney --device ipod You can also set the default device in the config file: DEVICE="$ipod" Important note: if you redefine the default device (hifi), you should then reassign DEVICE to it in the config file, ie: hifi="wav WAV flac FLAC" DEVICE="$hifi" Otherwise DEVICE will continue to have the old value of hifi from before it was redefined. #### Alternate players Although there is a default player on each operating system, some OSs support several players. You can pick something besides the default by setting the variable PLATFORM, for example: PLATFORM=linux-plaiter The currently supported platforms are: cygwin-winamp, cygwin-itunes, osx-itunes, linux-xmms, linux-beep-media-player, linux-amarok, linux-mpg123, linux-mpg123-esd, linux-mpg321, linux-mpg321-esd, linux-ogg123, linux-ogg123-esd, linux-plaiter, any-xspf and any-xspf-copy. In the interest of accuracy, there are also "unix-" synonyms for all the "linux-" players. The "esd" platforms play via the Enlightened Sound Daemon, which can stream audio across the network to an esd server. You specify which server by setting ESPEAKER, for example: ESPEAKER=192.168.1.2:16001 See README.plaiter for information on Plaiter, which is the ideal platform choice if you currently use a command line player like mpg123. Copyright (c) 2005, 2006 by Stephen Jungels plait/device.awk0000700000076500007650000000322610375515062015652 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. # setup: get the list of preferred formats state==0 { numtypes = split (types, type, " "); lasttrack = ""; state = 1; } # get file extension function typename(track, n, fields) { n = split (track, fields, "."); return fields[n]; } # get file path minus extension function basename(track, j, n, fields, str, dot) { n = split (track, fields, "."); str = ""; dot = ""; for (j=1; j 0) { min = hintmatches[i]; } if (hintmatches[i] > max) { max = hintmatches[i]; } total += hintmatches[i]; if (hintmatches[i] > 0) goodhints++; } if (min==999999) min = 0; if (goodhints==0) goodhints=1; avg = total / goodhints; if (tracks==-1) mma = avg; else if (tracks==-2) mma = min; else if (tracks==-3) mma = max; else if (tracks==-4) mma = min; else mma = (tracks / goodhints); for (i=1; i<=numhints; i++) { if (hintmatches[i] > 0) hintfactors[i] = (mma / hintmatches[i]); else hintfactors[i] = 0; hintattempts[i] = 1; hintprints[i] = hintfactors[i]; } if (order=="stripe2") { for (i=0; i= 1.0) { x1 = 2.0 * rand() - 1.0; x2 = 2.0 * rand() - 1.0; w = x1 * x1 + x2 * x2; } w = sqrt((-2.0 * log(w)) / w ); gauss1 = x1 * w; gaussindex = 1; return (x2 * w); } } # print a track with a leading index such that the # tracks will be ordered properly when the list is # sorted function printtrack(track, i, songindex, n, tries) { if (order=="stripe") { songindex = hintindex[i]; hintindex[i] += numhints; print songindex "\t" track; } else if (order=="stripe2") { if (posindex[i] "/dev/stderr"; tries++; } tries = 0; while (slots[n,i]==1 && tries < 40) { n = int (rand() * max); printf "." > "/dev/stderr"; tries++; } if (slots[n,i]==1) { for (n=0; n<=max; n++) { if (slots[n,i]==0) break; printf "." > "/dev/stderr"; } } slots[n,i] = 1; songindex = n + (i / numhints); print songindex "\t" track; } else if (order=="fade") { songindex = boxmuller() + (1.2 * i); print songindex "\t" track; } else if (order=="random") { songindex = rand(); print songindex "\t" track; } else if (order=="sort") { print track; } else if (order=="group") { songindex = rand() + i; print songindex "\t" track; } } # second pass: use statistics and random fudge # to decide whether to print each track state==3 { for (i=1; i<=numhints; i++) { if (tolower($0) ~ tolower(hint[i])) { if (tracks==-4) { printtrack($0, i); break; } else { hf = (2 * hintfactors[i] - (hintprints[i] / hintattempts[i])); hintattempts[i]++; r = rand(); if (hf > r) { while (hf > r) { hintprints[i]++; printtrack($0, i); hf--; } break; } } } } } plait/interactive.awk0000700000076500007650000000722310424717144016731 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { all = ""; search = ""; levelsep = "/"; skipindex = 0; playindex = 0; } state==0 { printf \ ("y: yes\nn: no\nY: yes to all\nN: no to all\n") > "/dev/tty"; printf \ ("u: up a level\nd: down a level\n/: search\n") > "/dev/tty"; state = 1; } state==1 { brief = $0; sub(prefix, "", brief); action = ""; response = ""; len = 0; # take the advice of the longest (most specific) hint for (i=1; i<=skipindex; i++) { if (index(tolower(brief), tolower(skiphints[i])) > 0 && length(skiphints[i]) > len) { action = "n"; len = length(skiphints[i]); } } for (i=1; i<=playindex; i++) { if (index(tolower(brief), tolower(playhints[i])) > 0 && length(playhints[i]) > len) { action = "y"; break; } } if (action=="" && all!="") { action = all; } if (action=="" && search!="") { if (tolower(brief) ~ tolower(search)) { search = ""; } else { action = "n"; } } if (action=="y") { printf ("%s\n", $0); } # if hints and "all" gave no instructions, ask the user else if (action=="") { levels = split(brief, briefparts, levelsep); if (levels + levelindex < 1) { levelindex = 1 - levels; } for (i=1; i<=levels; i++) { # escape regex special chars that might appear in a filename briefparts2[i] = briefparts[i]; # gsub("\\(", "\\(", briefparts2[i]); # gsub("\\)", "\\)", briefparts2[i]); # gsub("\\+", "\\+", briefparts2[i]); # gsub("\\[", "\\[", briefparts2[i]); # gsub("\\]", "\\]", briefparts2[i]); # gsub("\\|", "\\|", briefparts2[i]); # gsub("\\*", "\\*", briefparts2[i]); } cont = 1; while (cont==1) { cont = 0; str = ""; str2 = ""; sep = ""; sep2 = ""; for (i=1; i<=levels+levelindex; i++) { str = str sep briefparts2[i]; str2 = str2 sep2 briefparts[i]; sep = levelsep; sep2 = "/"; } printf("Play %s (ynYNud/)? ", str2) > "/dev/tty"; getline response < "/dev/tty"; if (response ~ /^u(p)?/) { cont = 1; levelindex -= 1; if (levels + levelindex < 1) { levelindex = 1 - levels; } } if (response ~ /^d(own)?/) { cont = 1; levelindex += 1; if (levelindex > 0) { levelindex = 0; } } } if (response ~ /^Y(es)?/) { response = "y"; all = "y"; } else if (response ~ /^N(o)?/) { response = "n"; all = "n"; } else if (response ~ /^\//) { search = substr(response, 2); if (search=="") { search = savesearch; } if (search=="") { printf("Search string: ") > "/dev/tty"; getline search < "/dev/tty"; } savesearch = search; response = "n"; } if (response ~ /y(es)?/ || response=="") { printf("%s\n", $0); # if we're above track level, this may match more than one track, so save it if (levelindex < 0) { playhints[++playindex] = str; } } else if (response ~ /n(o)?/) { if (levelindex < 0) { skiphints[++skipindex] = str; } } } } plait/interactivestream.awk0000700000076500007650000000363610416556672020161 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { search = ""; savesearch = ""; } state==0 { printf \ ("y: yes\nn: no\nY: yes to all\nN: no to all\n/: search\n") \ > "/dev/tty"; state = 1; } state==1 { long = $0; sub("# ", "", long); brief = long; brief = substr(brief, 1, 72); action = ""; response = ""; if (all!="") { action = all; } if (action=="" && search!="") { if (tolower(long) ~ tolower(search)) { search = ""; } else { action = "n"; } } if (action=="y") { getline; printf ("%s\n", $0); } else if (action=="n") { getline; } # if search and "all" gave no instructions, ask the user else if (action=="") { printf("Play %s (ynYN/)? ", brief) > "/dev/tty"; getline response < "/dev/tty"; if (response ~ /Y(es)?/) { response = "y"; all = "y"; } else if (response ~ /N(o)?/) { response = "n"; all = "n"; } else if (response ~ /^\//) { search = substr(response, 2); if (search=="") { search = savesearch; } if (search=="") { printf("Search string: ") > "/dev/tty"; getline search < "/dev/tty"; } savesearch = search; response = "n"; } if (response ~ /y(es)?/ || response=="") { getline; printf ("%s\n", $0); } else { getline; } } } plait/robots.awk0000700000076500007650000000173110452634370015722 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { ok = 1; check = 0; } /^User-agent:/ { check = 0; } /^User-agent: \* *(#.*)?$/ { check = 1; } /^User-agent: Plait *(#.*)?$/ { check = 1; } /^Disallow: ?\/ *(#.*)?$/ { if (check==1) ok = 0; } /^Disallow: ?\/directory/ { if (check==1) ok = 0; } /^Allow: ?\/directory/ { if (check==1) ok = 1; } END { if (ok==1) print("OK"); else print("NOT OK"); } plait/xspf.awk0000700000076500007650000000531611030313446015364 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { title = toupper (substr (title, 1, 1)) substr (title, 2); print ""; print ""; print " " title ""; print " "; } function myurlencode(str) { gsub (" ", "%20", str); gsub ("'", "%27", str); gsub ("&", "and", str); gsub (";", "%3b", str); gsub ("/", "%2f", str); gsub ("\\?", "%3f", str); gsub (":", "%3a", str); gsub ("@", "%40", str); gsub ("=", "%3d", str); return str; } { p2 = plait "/art.url"; s = $0; sub (d "/", "", s); split (s, fields, sep); artist = fields[ar]; album = fields[al]; song = fields[so]; split (song, f2, "[.]"); song = f2[1]; gsub ("_", " ", song); sub ("[0-9][0-9]? ?- ?", "", song); song = toupper (substr (song, 1, 1)) substr (song, 2); album = toupper (substr (album, 1, 1)) substr (album, 2); artist = toupper (substr (artist, 1, 1)) substr (artist, 2); if (index(s, "http://") != 1) { print " "; print " " artist ""; print " " album ""; print " " song ""; print " " url s ""; if (art==1) { ar2 = myurlencode(artist); al2 = myurlencode(album); url2 = "http://ws.audioscrobbler.com/1.0/album/" ar2 "/" al2 "/info.xml"; if (url2 in images) { image = images[url2]; } else { if (mustdelay==1) { system ("sleep 1"); } system ("wget > /dev/null 2>&1 -O \"$HOME/.plait/art.xml\" " url2); mustdelay = 1; system ("awk -f " coverprog " \"$HOME/.plait/art.xml\" > \"$HOME/.plait/art.url\""); close (p2); getline image < p2; images[url2] = image; } if (image != "No art available") { print " " image ""; } } print " "; } else { print " "; print " " s ""; print " " s ""; print " "; } } END { print " "; print ""; } plait/treecopy.awk0000700000076500007650000000226211030314775016241 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. function deregex(str) { gsub ("\\(", "\\(", str); gsub ("\\)", "\\)", str); gsub ("\\[", "\\[", str); gsub ("\\]", "\\]", str); gsub ("\\.", "\\.", str); gsub ("\\?", "\\?", str); gsub ("\\*", "\\*", str); gsub ("\\|", "\\|", str); gsub ("\\+", "\\+", str); return str; } { if (index ($0, "http://") != 1) { path = $0; d2 = deregex(d); sub (d2, "", path); n = split (path, subdirs, "/"); base = subdirs[n]; b2=deregex(base); sub (b2, "", path); print "mkdir -p \"" to path "\""; print "cp \"" $0 "\" \"" to path "\""; } } plait/playlist.html0000700000076500007650000000103611030315547016426 0ustar sjungelssjungels00000000000000 %TITLE%

    Playlist: %TITLE%.

    Generated by Plait command line jukebox. plait/coverart.awk0000700000076500007650000000200010476204102016215 0ustar sjungelssjungels00000000000000# # Copyright (C) 2005, 2006 Stephen Jungels # # 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. # # See COPYING for the full text of the license. BEGIN { state = 0; } { if (state==0 && $0 ~ //) state = 1; if (state==1 && $0 ~ //) { state = 2; art = ""; } if (state==2) { art = art $0; } if (state==2 && $0 ~ /<\/medium>/) { state = 3; sub (".*[ \t]*", "", art); sub ("[ \t]*.*", "", art); } } END { if (state==3) print art; else print "No art available"; }