Zu einem Icecast Server streamen auf der Konsole unter Linux

Irgendwie bin ich in der letzten Zeit durch “Sielenc” auf die Idee gekommen, einen Icecast Server testweise zu betreiben :)

Zum Testen wollte ich natürlich auch meine Musik an den Server senden.

Da ich ja unter Linux arbeite, war die Programmauswahl etwas schwieriger; zum Senden der Daten an den Server benutze ich Ices2. Ausserdem wollte ich das komplett auf der Konsole machen können und eine gute Integration in den Music-On-Console Player haben.

In der Konfiguration von Ices2 stellt man entweder eine Playlist ein oder ein Script, welches genau einen Dateienamen zurückliefert. Ich benutze letzteres und habe mir hierfür ein kleines Hilfs-Script geschrieben.

Aus Sicht von Ices gibt dieses Script jedes mal nur einen Dateinamen aus der aktuellen Wartschlange zurück. Falls die Warteschlange leer ist, wird solange automatisch ein Lied aus der “Notfall-Warteschlange” (manche nennen das AutoDJ) geliefert, bis die Warteschlange wieder was zu bieten hat.

<WRAP center round tip> Mit einem Befehl wie find /Music_Free/Electro/ -iname "*ogg" -exec /bin/feed_ices.sh addtoequeue "{}" \; kann man die eQueue ziemlich einfach mit viel Musik befüllen. </WRAP>

Der größere Teil des Scriptes kümmert sich um das Auffüllen der beiden Warteschlangen (Queues).
Beim Aufruf gibt es folgende Möglichkeiten:

  • showqueue – Zeigt die aktuelle Warteschlange an
  • showequeue – Zeigt die Auto-DJ-Warteschlange an
  • addtoqueue file/dir – fügt die Datei oder das Verzeichnis zur Warteschlange hinzu
  • addtoequeue file/dir – wie oben, aber zur Auto-DJ Warteschlange
  • get – Auf diese Weise ruft Ices2 das Script auf, um eine Datei zu bekommen
  • played – Liefert eine Liste aller bisher gespielter Dateien
  • help – Zeigt eine kurze Hilfe an

Im Script kann man damit sehr einfach eine Datei oder ein ganzes Verzeichnis in die Warteschlange übernehmen. Dabei wird für jede einzelne Datei geprüft, ob sie als Ogg vorliegt und falls nicht, automatisch encodiert (Ices2 mag nur Ogg streamen :)). Sollte die Datei bereits encodiert worden sein (im temporären Feed-Ices Verzeichnis), entfällt das Encodieren.

Es wird auch überprüft, ob die Datei, die aktuell zur Queue hinzugefügt werden soll, mit der letzten auf der Warteschlange übereinstimmt und verweigert dann das Hinzufügen. Dies liegt daran, dass Ices2 sich weigert dieselbe Datei mehrmals hintereinander abzuspielen und sich irgendwann wegen zu vieler Fehler beendet.

Sox macht es richtig und es funktioniert somit auch mit Ices2. Jedoch ist es trotzdem nicht möglich, denselben Song zweimal hintereinander abzuspielen.

Dieses Script ist mal wieder so ein “es reicht mir aus”-Fall, es gibt mit Sicherheit bessere.

Ich werde auch nicht wirklich streamen sondern wollte mich nur mal mit dem Thema auseinandersetzen. Zur Not kann man so mal dem einen oder anderen seine Musik nahe bringen :)

Status

Abgeschlossen

Das Script

Hier die aktuelle Version des Scripts zum Download: feed_ices.zip Oder hier als Quellcode (Bash); wie man sieht sind noch einige Debug Sachen drin …

#!/bin/bash AUTHOR="Natenom" VERSION="0.1.5" LASTEDIT="2010-02-21" # Ices sends only ogg files; if you give me an NOT-ogg I will encode it. # Use "$0 help" FI__IS_RUNNING=/tmp/feed_ices.pid #Create this file while running FI__QUEUE=/home/ices/queue.list #Ices Queue FI__EQUEUE=/home/ices/equeue.list #These songs will be played if normal playlist is empty. FI__PLAYED=/home/ices/played.list #List of played songs taken from any queue. FI__TMP_DIR=/tmp/feed_ice #FI__STREAM_CODEC=ogg NOTIFY="notify-send" FI__NOTIFY_TIME_MS=5000 #Default Queue is the normal one. FI__QUEUE_USE="${FI__QUEUE}" ##################################### #### DO NOT EDIT BELOW THIS LINE #### ##################################### #If there are not queue files, create them [ ! -f "${FI__QUEUE}" ] && touch "${FI__QUEUE}" [ ! -f "${FI__EQUEUE}" ] && touch "${FI__EQUEUE}" [ ! -f "${FI__PLAYED}" ] && touch "${FI__PLAYED}" #If Ctrl+C remove pid file. trap "rm ${FI__IS_RUNNING}" 2 15 __FI__COUNTER=0 while [ -f "${FI__IS_RUNNING}" ]; #remove ! after testing do if [ ${__FI__COUNTER} -gt 5 ]; then echo "Waited 5 times, thats too much, bye" exit 15 else echo $0 is already running PID: $(cat "${FI__IS_RUNNING}") echo "Sleeping for 2 Seconds ..." sleep 2 fi __FI__COUNTER=$((${__FI__COUNTER}+1)) done #No other script is running # Write our pid to pid-file. ############################echo $$ > "${FI__IS_RUNNING}" #currently disabled until I find a better way FI_GIVEN_PATH="${2}" function popupinfo() { if [ "$KDE_FULL_SESSION" == true ]; then $NOTIFY -t ${FI__NOTIFY_TIME_MS} "${1}" "${2}" else #Does not really work <img src="bla.domain.tld/wp-includes/images/smilies/icon_razz.gif" alt=":P" class="wp-smiley"> $NOTIFY_GNOME -i sound -t ${FI__NOTIFY_TIME_MS} "${1}" "${2}" fi } function encode_file_to_tmp() { #Encodes a File from *.* to *.ogg into $FI__TMP_DIR # 1 = SourceFile # 2 = DestFile [ ! -d "${FI__TMP_DIR}" ] && mkdir -p "${FI__TMP_DIR}" #If temporary directory doesn't exist, create it. #ffmpeg here does not work because it uses serial number always 0; second it does not write correct vorbis headers. #sox instead does a great job #_ENCODE_FILE="${1}" clear sox -V4 "${1}" "${2}" # & #Do that in background because it needs some time. return 0 } function add_file_to_playlist() { #Add a file to playlist; if it is not already .ogg, encode it. local _directory="${1}" local _file="${2}" local _queue_it="1" #0 means to enqueue it <>0 to not enqueue #Will contain the suffix of the given file. local _in_suffix="0" #To get the filetype we first need to get it. case $(echo "${_file}" | egrep -o '\.ogg$|\.mp3$|\.flac$|\.wav$') in .ogg) #Ogg file _in_suffix=.ogg _return=0 #if not 0, would not work below ;; .mp3) #Ogg file _in_suffix=.mp3 ;; .flac) #Ogg file _in_suffix=.flac ;; .wav) #Ogg file _in_suffix=.flac ;; *) #anything different _in_suffix=UNKNOWN ;; esac #Create the new filename local __encode_to_file="${FI__TMP_DIR}/${_file/$_in_suffix/.ogg}" #*********************************** #IFS needed if spaces in files IFS=" " local _last_on_queue_fullpath=$(tail -n 1 "${FI__QUEUE_USE_NOW}") #Get the last song on queue. _last_on_queue_filename=$(basename "${_last_on_queue_fullpath}") #Get only the filename of the last queue entry unset IFS #*********************************** #If current file is the same as the last added file, it won't be added because ices2 won't play the same file twice in direct order. #Compare always the filename, not the full path. if [ "${_file/$_in_suffix/.ogg}" == "${_last_on_queue_filename}" ]; then clear echo "ERROR: This is the same file as the last one, ignoring. Ices2 would not play this" echo "\"${_file/$_in_suffix/.ogg}\" (you want to add)" echo "\"${_last_on_queue_filename}\" (last file in your queue)" echo "Press Enter to continue" read lala rm "${FI__IS_RUNNING}" return 0 else #Now we can encode it. case "${_in_suffix}" in .flac|.mp3|.wav) #If not ogg, we need to encode if [ -f "${__encode_to_file}" ]; then clear echo "File already exists, no encoding needed ... (May be a previous session)." echo "Press enter to enqueue this file" read waitforme #Without following, you would just get the above message and file would not be added to the queue. _queue_it="0" else encode_file_to_tmp "${_directory}/${_file}" "${__encode_to_file}" _queue_it=$? fi ;; .ogg) #Is an ogg file, nothing to encode _queue_it="0" #Encode_to_file must be full path of original file not of /tmp/feed_ice/... __encode_to_file="${_directory}/${_file}" ;; esac #If Encoding was correct, or it was ogg ... add to queue. [ "${_queue_it}" == "0" ] && echo "${__encode_to_file}" >> "${FI__QUEUE_USE_NOW}" || echo "Error in encoding or not an music file." fi } function add_directory_to_playlist() { #Use add_file_to_playlist to add a complete directory local _directory="${1}" IFS=" " for _filename in $(ls "${_directory}"); do add_file_to_playlist "${_directory}" "${_filename}" done unset IFS return 0 } function addthis() { #Determines if it is a directory or a file and ... . # 1 = given path local _path="${1}" if [ -d "${_path}" ]; then #It is not a file but a directory, add some special features clear echo -e "This is a directory, do you want all content to be added to the playlist?\ny/n" read __ask [ "${__ask}" == "y" ] && add_directory_to_playlist "${_path}" else #Is a File, not a directory. #Split into dir and filename as add_file_to_playlist() needs it. local _dir=$(dirname "${_path}") local _file=$(basename "${_path}") add_file_to_playlist "${_dir}" "${_file}" fi return 0 } function showqueue() { #Shows the current queue. local _queue="${1}" IFS=" " clear echo "Queue (First will be played first)" for i in $(cat "${_queue}") do #__TITLE=$(ogginfo "${i}" | egrep -i 'TITLE=' | tr -d '\t') #Get title from ogginfo. #__ARTIST=$(ogginfo "${i}" | egrep -i 'ARTIST=' | grep -v -i album | tr -d '\t') #Get artist from ogginfo. echo "${i}" " - ${__ARTIST} ${__TITLE}" #And show. done #Show how many files are in the emergency playlist. echo "Songs in Emergency Playlist (${FI__EQUEUE}): $(cat "${FI__EQUEUE}" | wc -l)" unset IFS } case ${1} in showqueue) #Show the queue. showqueue "${FI__QUEUE}" ;; showequeue) #Show the queue. showqueue "${FI__EQUEUE}" ;; add|addtoqueue) #Add a file to the queue. FI__QUEUE_USE_NOW="${FI__QUEUE}" addthis "${FI_GIVEN_PATH}" ;; addtoequeue) #Add the file to the emergency queue (equeue). FI__QUEUE_USE_NOW="${FI__EQUEUE}" addthis "${FI_GIVEN_PATH}" ;; addrecursiveogg) #Add only oggfiles recursive from path addthis "${FI_GIVEN_PATH}" _ONLYOGG=true ;; get) #Get the first file entry from the playlist; if playlist is empty, use the emergency playlist in the same way. # If emergency playlist is also empty, ices stops working. if [ ! -z "$(cat ${FI__QUEUE})" ]; then #Playlist is not empty. #Fetch the first filename from playlist. __PLAYLIST="${FI__QUEUE}" else #Queue is empty; Use Equeue instead. popupinfo "" "Queue is empty, using emergency-queue with <b>$(cat "${FI__EQUEUE}" | wc -l)</b> Songs" __PLAYLIST="${FI__EQUEUE}" fi #FIFO FI__RETURN_FILE=$(head -n 1 "${__PLAYLIST}") #And now delete the first entry from playlist. sed -i 1d "${__PLAYLIST}" #Write filename to already played filelist. echo "${FI__RETURN_FILE}" >> "${FI__PLAYED}" #Return filename. echo "${FI__RETURN_FILE}" __COUNT=$(cat "${__PLAYLIST}" | wc -l) popupinfo "Feed-Ices" "Still <b>${__COUNT}</b> titles in the queue" ;; played) #Shows already played songs echo "Playlist (Played from top)" cat "${FI__PLAYED}" ;; help|*) cat<<EOF USAGE $0 [ACTION] [FILE] ACTIONS showqueue Shows current queue. showequeue Shows current emergency queue. addtoqueue|add file/directory Adds the file to the current queue. addtoequeue file/directory Adds the file to the current emergency queue. get Get the next file from queue. If queue is empty, the program returns the first file from emergency queue. After that, the first entry in the queue/equeue will be deleted. played Get a list of already played songs. help This help Have fun 2010 - Natenom EOF ;; esac ###################################################rm "${FI__IS_RUNNING}" exit 0
Zuletzt geändert: 2025-01-28 21:40:17 +0000 UTC: fix(banner): add padding