#!/bin/bash # # .---. . . # | | | # |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-. # | | (.-' (.-' ( | ( )| | | | )( )| | (.-' # ' ' --' --' -' - -' ' ' -' -' -' ' - --' # # Freedom in the Cloud # # Icecast application # # Notes: An attempt was made to get ices2 running with systemd, but that # was very unsuccessful. Instead there's a hacky cron entry which # starts icecast2 and ices2 if necessary # # License # ======= # # Copyright (C) 2017 Bob Mottram # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . VARIANTS='full' IN_DEFAULT_INSTALL=0 SHOW_ON_ABOUT=1 SHOW_ICANN_ADDRESS_ON_ABOUT=0 ICECAST_DOMAIN_NAME= ICECAST_CODE= ICECAST_PORT=8005 ICECAST_ONION_PORT=8146 ICECAST_DIR=/icestream ICECAST_PLAYLIST_FILE=/etc/ices2/playlist.txt ICECAST_LOGIN_TEXT=$"Icecast login" icecast_variables=(MY_USERNAME MY_EMAIL_ADDRESS ONION_ONLY ICECAST_DOMAIN_NAME ICECAST_CODE DEFAULT_LANGUAGE) function icecast_rescan { if [ -d $ICECAST_DIR ]; then if [ -f $ICECAST_PLAYLIST_FILE ]; then rm $ICECAST_PLAYLIST_FILE fi icecast_add_file_to_playlist $ICECAST_DIR fi } function icecast_update_daemon { systemctl stop icecast2 if [ -f /etc/init.d/icecast2 ]; then rm /etc/init.d/icecast2 fi echo '#!/bin/sh' > /usr/bin/stop_icecast echo 'kill $(pidof ices2)' >> /usr/bin/stop_icecast echo 'systemctl stop icecast2' >> /usr/bin/stop_icecast chmod +x /usr/bin/stop_icecast # Note that the sleep here actually is important echo '#!/bin/bash' > /usr/bin/start_icecast echo 'isrunning=$(ps aux | grep ices2)' >> /usr/bin/start_icecast echo 'if [[ "$isrunning" != *"ices-playlist"* ]]; then' >> /usr/bin/start_icecast echo ' systemctl start icecast2' >> /usr/bin/start_icecast echo ' sleep 3' >> /usr/bin/start_icecast echo ' cd /etc/ices2' >> /usr/bin/start_icecast echo ' ices2 ices-playlist.xml' >> /usr/bin/start_icecast echo 'fi' >> /usr/bin/start_icecast chmod +x /usr/bin/start_icecast echo '[Unit]' > /etc/systemd/system/icecast2.service echo 'Description=Icecast' >> /etc/systemd/system/icecast2.service echo 'After=network.target' >> /etc/systemd/system/icecast2.service echo 'After=tor.service' >> /etc/systemd/system/icecast2.service echo '' >> /etc/systemd/system/icecast2.service echo '[Service]' >> /etc/systemd/system/icecast2.service echo 'User=icecast2' >> /etc/systemd/system/icecast2.service echo 'Group=icecast' >> /etc/systemd/system/icecast2.service echo 'ExecStart=/usr/bin/icecast2 -c /etc/icecast2/icecast.xml' >> /etc/systemd/system/icecast2.service echo 'Restart=on-failure' >> /etc/systemd/system/icecast2.service echo 'RestartSec=10' >> /etc/systemd/system/icecast2.service echo '' >> /etc/systemd/system/icecast2.service echo '[Install]' >> /etc/systemd/system/icecast2.service echo 'WantedBy=multi-user.target' >> /etc/systemd/system/icecast2.service chown -R icecast2:icecast /etc/ices2 chown -R icecast2:icecast /etc/icecast2 systemctl daemon-reload systemctl enable icecast2 if ! grep -q "start_icecast" /etc/crontab; then echo '*/1 * * * * root /usr/bin/start_icecast > /dev/null' >> /etc/crontab fi } function change_password_icecast { curr_username="$1" new_user_password="$2" stop_icecast sed -i -e "s|[^<]*|$new_user_password|" \ -e "s|[^<]*|$new_user_password|" \ -e "s|[^<]*|$new_user_password|" \ /etc/icecast2/icecast.xml sed -i "s|.*|${new_user_password}|g" /etc/ices2/ices-playlist.xml ${PROJECT_NAME}-pass -u "$curr_username" -a icecast -p "$new_user_password" start_icecast } function logging_on_icecast { echo -n '' } function logging_off_icecast { echo -n '' } function reconfigure_icecast { echo -n '' } function icecast_convert_files { clear cd ${1} echo $'Converting any mp3 files to ogg format' find . -type f -name '*.mp3' -exec bash -c 'ffmpeg -i "$0" -c:a libvorbis -q:a 4 "${0/%mp3/ogg}"' '{}' \; find . -name "*.mp3" -print0 | xargs -0 rm -f echo $'Converting any mp4 files to ogv format' find . -type f -name '*.mp4' -exec bash -c 'ffmpeg -i "$0" -c:a libvorbis -q:a 4 "${0/%mp3/ogv}"' '{}' \; find . -name "*.mp4" -print0 | xargs -0 rm -f chown -R icecast2:icecast $ICECAST_DIR } function icecast_add_file_to_playlist { files_dir=${1} if [ ! -d $files_dir ]; then return fi echo $'Adding ogg files to playlist' find $files_dir -type f -name '*.ogg' -print0 | while read -d $'\0' file; do if ! grep -q "$file" $ICECAST_PLAYLIST_FILE; then echo "$file" >> $ICECAST_PLAYLIST_FILE fi done echo $'Adding ogv files to playlist' find $files_dir -type f -name '*.ogv' -print0 | while read -d $'\0' file; do if ! grep -q "$file" $ICECAST_PLAYLIST_FILE; then echo "$file" >> $ICECAST_PLAYLIST_FILE fi done chown icecast2:icecast $ICECAST_PLAYLIST_FILE stop_icecast start_icecast } function icecast_import_from_directory { data=$(tempfile 2>/dev/null) dialog --title "Choose a directory containing stream files" --dselect /home/$MY_USERNAME/ 30 60 2> $data selected_dir=$(cat $data) rm $data if [[ "$selected_dir" == "$ICECAST_DIR" ]]; then return fi if [ ! -d $selected_dir ]; then return fi if [[ "$selected_dir" == "/home/$MY_USERNAME/" ]]; then return fi if [[ "$selected_dir" == "/home/$MY_USERNAME/."* ]]; then return fi if [[ "$selected_dir" == *"/Maildir" || "$selected_dir" == *"/Sync" ]]; then return fi dialog --title $"Import stream files directory into Icecast" \ --backtitle $"Freedombone Control Panel" \ --defaultno \ --yesno $"\nImport the directory:\n\n $selected_dir" 12 75 sel=$? case $sel in 1) return;; 255) return;; esac if [ ! -d $ICECAST_DIR ]; then mkdir -p $ICECAST_DIR fi dest_dir=$(basename "$selected_dir") mv "$selected_dir" $ICECAST_DIR icecast_convert_files $ICECAST_DIR/$dest_dir icecast_add_file_to_playlist $ICECAST_DIR/$dest_dir dialog --title $"Import stream files directory into Icecast" \ --msgbox $"Import success" 6 40 } function icecast_import_from_usb { clear detect_usb_drive if [ ! -b $USB_DRIVE ]; then dialog --title $"Import stream files from USB drive" --msgbox $'No USB drive found' 6 50 return fi backup_mount_drive ${USB_DRIVE} if [ ! -d $USB_MOUNT$ICECAST_DIR ]; then dialog --title $"Import stream files from USB drive" --msgbox $'No stream files directory found on USB drive' 6 50 backup_unmount_drive ${USB_DRIVE} fi cp -ru $USB_MOUNT$ICECAST_DIR/* $ICECAST_DIR backup_unmount_drive ${USB_DRIVE} icecast_convert_files $ICECAST_DIR dialog --title $"Import stream files from USB drive" --msgbox $'Import complete. You may now remove the USB drive' 6 50 } function icecast_export_to_usb { clear detect_usb_drive if [ ! -b $USB_DRIVE ]; then dialog --title $"Export stream files to USB drive" --msgbox $'No USB drive found' 6 50 return fi backup_mount_drive ${USB_DRIVE} if [ ! -d $USB_MOUNT$ICECAST_DIR ]; then mkdir -p $USB_MOUNT$ICECAST_DIR fi cp -ru $ICECAST_DIR/* $USB_MOUNT$ICECAST_DIR backup_unmount_drive ${USB_DRIVE} dialog --title $"Export stream files to USB drive" --msgbox $'Export complete. You may now remove the USB drive' 6 50 } function icecast_format_drive { detect_usb_drive data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title $"Format USB drive $USB_DRIVE for stream file storage" \ --backtitle $"Freedombone Control Panel" \ --defaultno \ --yesno $"\nPlease confirm that you wish to format drive\n\n ${USB_DRIVE}\n\nAll current data on the drive will be lost, and you will be prompted to give a password used to encrypt the drive.\n\nDANGER: If you screw up here and format the wrong drive it's your own fault!" 16 60 sel=$? case $sel in 1) return;; 255) return;; esac rm $data clear echo '' echo $"Formatting drive $USB_DRIVE. ALL CONTENTS WILL BE LOST." echo '' ${PROJECT_NAME}-format $USB_DRIVE dialog --title $"Format USB drive $USB_DRIVE for stream file storage" --msgbox $'Format complete. You may now export stream files or remove the USB drive' 6 50 } function icecast_edit_playlist { editor $ICECAST_PLAYLIST_FILE stop_icecast start_icecast } function icecast_change_login { read_config_param $MY_USERNAME ICECAST_USER_PASSWORD=$(${PROJECT_NAME}-pass -u $MY_USERNAME -a icecastuser) data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --title $"Change Icecast stream visitor login" \ --backtitle $"Freedombone Control Panel" \ --inputbox $"Enter the new login password for stream visitors" 8 60 "$ICECAST_USER_PASSWORD" 2>$data sel=$? case $sel in 0) ICECAST_USER_PASSWORD=$(<$data) if [[ "$ICECAST_USER_PASSWORD" != *' '* ]]; then if [ ${#ICECAST_USER_PASSWORD} -gt 8 ]; then ${PROJECT_NAME}-pass -u $MY_USERNAME -a icecastuser -p $ICECAST_USER_PASSWORD dialog --title $"Change Icecast stream visitor login" \ --msgbox $"Password changed to $ICECAST_USER_PASSWORD" 6 75 fi fi ;; esac rm $data } function icecast_enable_login { dialog --title $"Enable Icecast login" \ --backtitle $"Freedombone Control Panel" \ --defaultno \ --yesno $"\nDo you want to add a login so that random web users can't access your stream?" 10 60 sel=$? case $sel in 0) if grep -q '#auth_basic' /etc/nginx/sites-available/icecast; then sed -i 's|#auth_basic|auth_basic|g' /etc/nginx/sites-available/icecast systemctl restart nginx fi read_config_param $MY_USERNAME ICECAST_USER_PASSWORD=$(${PROJECT_NAME}-pass -u $MY_USERNAME -a icecastuser) dialog --title $"Enable Icecast login" \ --msgbox $"Icecast logins are now enabled with the password $ICECAST_USER_PASSWORD" 6 65 ICECAST_USER_PASSWORD= ;; 1) if ! grep -q '#auth_basic' /etc/nginx/sites-available/icecast; then sed -i 's|auth_basic|#auth_basic|g' /etc/nginx/sites-available/icecast systemctl restart nginx fi dialog --title $"Disable Icecast login" \ --msgbox $"Icecast logins are now disabled. Anyone can access your stream." 6 65 ;; esac } function configure_interactive_icecast { while true do data=$(tempfile 2>/dev/null) trap "rm -f $data" 0 1 2 5 15 dialog --backtitle $"Freedombone Control Panel" \ --title $"Icecast" \ --radiolist $"Choose an operation:" 17 70 10 \ 1 $"Import stream files from directory" off \ 2 $"Import stream files from USB drive" off \ 3 $"Manually edit playlist" off \ 4 $"Export stream files to USB drive" off \ 5 $"Format a USB drive for stream file storage" off \ 6 $"Enable login for stream visitors" off \ 7 $"Change password for stream visitors" off \ 8 $"Re-scan playlist" off \ 9 $"Restart stream" off \ 10 $"Exit" on 2> $data sel=$? case $sel in 1) break;; 255) break;; esac case $(cat $data) in 1) icecast_import_from_directory;; 2) icecast_import_from_usb;; 3) icecast_edit_playlist;; 4) icecast_export_to_usb;; 5) icecast_format_drive;; 6) icecast_enable_login;; 7) icecast_change_login;; 8) clear echo $'Rescanning Icecast playlist' icecast_rescan;; 9) clear echo $'Restarting Icecast stream' stop_icacast start_icecast;; 10) break;; esac done } function upgrade_icecast { icecast_update_daemon } function backup_local_icecast { if [ ! -d $ICECAST_DIR ]; then return fi stop_icecast cp /etc/nginx/.icepasswd $ICECAST_DIR cp /etc/ices2/ices-playlist.xml $ICECAST_DIR function_check backup_directory_to_usb backup_directory_to_usb $ICECAST_DIR icecast rm $ICECAST_DIR/.icepasswd start_icecast } function restore_local_icecast { if [ ! -d $ICECAST_DIR ]; then return fi stop_icecast temp_restore_dir=/root/tempicecast function_check restore_directory_from_usb restore_directory_from_usb $temp_restore_dir icecast if [ -d $temp_restore_dir$ICECAST_DIR ]; then cp -r $temp_restore_dir$ICECAST_DIR $ICECAST_DIR/ else cp -r $temp_restore_dir/* $ICECAST_DIR/* fi cp $ICECAST_DIR/.icepasswd /etc/nginx/.icepasswd rm $ICECAST_DIR/.icepasswd cp $ICECAST_DIR/ices-playlist.xml /etc/ices2 rm $ICECAST_DIR/ices-playlist.xml chown -R icecast2:icecast $ICECAST_DIR chown -R icecast2:icecast /etc/ices2 start_icecast rm -rf $temp_restore_dir } function backup_remote_icecast { if [ ! -d $ICECAST_DIR ]; then return fi stop_icecast cp /etc/nginx/.icepasswd $ICECAST_DIR cp /etc/ices2/ices-playlist.xml $ICECAST_DIR function_check backup_directory_to_friend backup_directory_to_friend $ICECAST_DIR icecast rm $ICECAST_DIR/.icepasswd start_icecast } function restore_remote_icecast { if [ ! -d $ICECAST_DIR ]; then return fi stop_icecast temp_restore_dir=/root/tempicecast function_check restore_directory_from_friend restore_directory_from_friend $temp_restore_dir icecast if [ -d $temp_restore_dir$ICECAST_DIR ]; then cp -r $temp_restore_dir$ICECAST_DIR $ICECAST_DIR/ else cp -r $temp_restore_dir/* $ICECAST_DIR/* fi cp $ICECAST_DIR/.icepasswd /etc/nginx/.icepasswd rm $ICECAST_DIR/.icepasswd cp $ICECAST_DIR/ices-playlist.xml /etc/ices2 rm $ICECAST_DIR/ices-playlist.xml chown -R icecast2:icecast $ICECAST_DIR start_icecast rm -rf $temp_restore_dir } function remove_icecast { nginx_dissite icecast sed -i '/start_icecast/d' /etc/crontab stop_icecast systemctl disable icecast2 rm /etc/systemd/system/icecast2.service rm /usr/bin/start_icecast rm /usr/bin/stop_icecast if [ -f /etc/nginx/sites-available/icecast ]; then rm /etc/nginx/sites-available/icecast fi if [ -d /var/www/icecast ]; then rm -rf /var/www/icecast fi apt-get -yq remove --purge icecast2 if [ -d /etc/icecast2 ]; then rm -rf /etc/icecast2 fi if [ -d /etc/ices2 ]; then rm -rf /etc/ices2 fi sed -i '/icecast/d' $COMPLETION_FILE } function install_icecast { apt-get -yq install software-properties-common debconf-utils apt-get -yq update debconf-set-selections <<< "icecast2 icecast2/icecast-setup boolean false" apt-get -yq install icecast2 ices2 ffmpeg apache2-utils if [ ! -f /etc/icecast2/icecast.xml ]; then echo $'Icecast not installed' exit 7923528 fi if [ ! ${ICECAST_PASSWORD} ]; then if [ -f ${IMAGE_PASSWORD_FILE} ]; then ICECAST_PASSWORD="$(printf `cat $IMAGE_PASSWORD_FILE`)" else ICECAST_PASSWORD="$(create_password ${MINIMUM_PASSWORD_LENGTH})" fi fi ICECAST_ONION_HOSTNAME=$(add_onion_service icecast 80 ${ICECAST_ONION_PORT}) sed -i -e "s|[^<]*|$ICECAST_PASSWORD|" \ -e "s|[^<]*|$ICECAST_PASSWORD|" \ -e "s|[^<]*|$ICECAST_PASSWORD|" \ -e "s|[^<]*|$ICECAST_ONION_HOSTNAME|" \ /etc/icecast2/icecast.xml sed -i "s|.*|10|g" /etc/icecast2/icecast.xml sed -i "s|.*|$ICECAST_PORT|g" /etc/icecast2/icecast.xml sed -i "s|.*|$MY_USERNAME|g" /etc/icecast2/icecast.xml sed -i "s|.*|$MY_EMAIL_ADDRESS|g" /etc/icecast2/icecast.xml sed -i "s|.*|The Interwebs|g" /etc/icecast2/icecast.xml #sed -i 's|' >> /etc/ices2/ices-playlist.xml echo ' 1' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' /var/log/ices' >> /etc/ices2/ices-playlist.xml echo ' ices.log' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 1' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 0' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' Example stream name' >> /etc/ices2/ices-playlist.xml echo ' Example genre' >> /etc/ices2/ices-playlist.xml echo ' A short description of your stream' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' playlist' >> /etc/ices2/ices-playlist.xml echo ' basic' >> /etc/ices2/ices-playlist.xml echo " $ICECAST_PLAYLIST_FILE" >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 0' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 0' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 0' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' localhost' >> /etc/ices2/ices-playlist.xml echo " $ICECAST_PORT" >> /etc/ices2/ices-playlist.xml echo " $ICECAST_PASSWORD" >> /etc/ices2/ices-playlist.xml echo ' /example1.ogg' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 2' >> /etc/ices2/ices-playlist.xml echo ' 5 ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 80' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' 64000' >> /etc/ices2/ices-playlist.xml echo ' 22050' >> /etc/ices2/ices-playlist.xml echo ' 1' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml echo ' ' >> /etc/ices2/ices-playlist.xml echo '' >> /etc/ices2/ices-playlist.xml sed -i 's|ENABLE=.*|ENABLE=true|g' /etc/default/icecast2 if [ ! -d $ICECAST_DIR ]; then mkdir $ICECAST_DIR fi chown -R icecast2:icecast $ICECAST_DIR # create a password for users ICECAST_USER_PASSWORD="$(create_password ${MINIMUM_PASSWORD_LENGTH})" if grep -q "$MY_USERNAME:" /etc/nginx/.icepasswd; then sed -i "/$MY_USERNAME:/d" /etc/nginx/.icepasswd fi echo "$ICECAST_USER_PASSWORD" | htpasswd -i -s -c /etc/nginx/.icepasswd $MY_USERNAME if [ ! -f /etc/nginx/.icepasswd ]; then echo $'/etc/nginx/.icepasswd not found' exit 73528235 fi ${PROJECT_NAME}-pass -u $MY_USERNAME -a icecast -p "$ICECAST_PASSWORD" ${PROJECT_NAME}-pass -u $MY_USERNAME -a icecastuser -p "$ICECAST_USER_PASSWORD" groupadd icecast useradd -c "Icecast system account" -d /etc/icecast2 -m -r -g icecast icecast2 icecast_update_daemon nginx_ensite icecast systemctl restart nginx icecast_rescan start_icecast APP_INSTALLED=1 } function install_interactive_icecast { install_icecast } # NOTE: deliberately no exit 0