From 44037c85a08c090286317017bdfb9e829295ee5c Mon Sep 17 00:00:00 2001 From: buttstuf Date: Sat, 6 Mar 2021 23:47:06 -0800 Subject: [PATCH] Initial commit --- README.txt | 9 + audio_queued/.gitkeep | 0 config/.gitkeep | 0 playlists/.gitkeep | 0 playlists/playlist.m3u | 4 + scripts/cron/main-cron_activate | 19 + scripts/cron/main-cron_deactivate | 17 + scripts/cron/main-cron_status | 23 + scripts/playlist/playlist_create | 66 +++ scripts/playlist/playlist_edit | 25 ++ scripts/playlist/playlist_view | 411 ++++++++++++++++++ scripts/queued/queued_folder_contents | 56 +++ scripts/streaming/main/main-stream_files | 93 ++++ scripts/streaming/main/main-stream_live_alsa | 113 +++++ .../streaming/testing/testing-stream_files | 99 +++++ .../testing/testing-stream_live_alsa | 113 +++++ scripts/system/system-alsa_mixer | 18 + scripts/system/system-config | 356 +++++++++++++++ scripts/system/system-config_copy | 67 +++ scripts/system/system-config_delete | 97 +++++ scripts/system/system-config_edit | 54 +++ scripts/system/system-config_empty_trash | 29 ++ scripts/system/system-config_new | 66 +++ scripts/system/system-config_rename | 108 +++++ scripts/system/system-config_use | 46 ++ scripts/system/system-declarations | 68 +++ scripts/system/system-functions | 216 +++++++++ scripts/system/system-killall_and_restart | 44 ++ .../system-update_hardware_audio_frame_size | 92 ++++ soapdish.sh | 236 ++++++++++ var/active_config_name | 0 var/log/.gitkeep | 0 var/main-cron_gateway | 0 var/templates/config-sample.json | 36 ++ var/version | 3 + 35 files changed, 2584 insertions(+) create mode 100755 README.txt create mode 100755 audio_queued/.gitkeep create mode 100755 config/.gitkeep create mode 100755 playlists/.gitkeep create mode 100755 playlists/playlist.m3u create mode 100755 scripts/cron/main-cron_activate create mode 100755 scripts/cron/main-cron_deactivate create mode 100755 scripts/cron/main-cron_status create mode 100755 scripts/playlist/playlist_create create mode 100755 scripts/playlist/playlist_edit create mode 100755 scripts/playlist/playlist_view create mode 100755 scripts/queued/queued_folder_contents create mode 100755 scripts/streaming/main/main-stream_files create mode 100755 scripts/streaming/main/main-stream_live_alsa create mode 100755 scripts/streaming/testing/testing-stream_files create mode 100755 scripts/streaming/testing/testing-stream_live_alsa create mode 100755 scripts/system/system-alsa_mixer create mode 100755 scripts/system/system-config create mode 100755 scripts/system/system-config_copy create mode 100755 scripts/system/system-config_delete create mode 100755 scripts/system/system-config_edit create mode 100755 scripts/system/system-config_empty_trash create mode 100755 scripts/system/system-config_new create mode 100755 scripts/system/system-config_rename create mode 100755 scripts/system/system-config_use create mode 100755 scripts/system/system-declarations create mode 100755 scripts/system/system-functions create mode 100755 scripts/system/system-killall_and_restart create mode 100755 scripts/system/system-update_hardware_audio_frame_size create mode 100755 soapdish.sh create mode 100755 var/active_config_name create mode 100755 var/log/.gitkeep create mode 100755 var/main-cron_gateway create mode 100755 var/templates/config-sample.json create mode 100755 var/version diff --git a/README.txt b/README.txt new file mode 100755 index 0000000..b91000c --- /dev/null +++ b/README.txt @@ -0,0 +1,9 @@ + +App: soapdish +Author: buttstuf@tilde.club + +-------------------------------------------------------------------------------- + + + +(END) diff --git a/audio_queued/.gitkeep b/audio_queued/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/config/.gitkeep b/config/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/playlists/.gitkeep b/playlists/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/playlists/playlist.m3u b/playlists/playlist.m3u new file mode 100755 index 0000000..588e07f --- /dev/null +++ b/playlists/playlist.m3u @@ -0,0 +1,4 @@ +# Playlist created date: +# +# +# Playlist tracks: diff --git a/scripts/cron/main-cron_activate b/scripts/cron/main-cron_activate new file mode 100755 index 0000000..4475fb8 --- /dev/null +++ b/scripts/cron/main-cron_activate @@ -0,0 +1,19 @@ +#!/bin/bash +# MAIN: CRON ACTIVATE +# Copy code to cront-show_gateway file + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# HEREDOC the script into a file named "cron-show_gateway" +cat <<-'EOF' > ${APPLICATION_ROOT}/var/main-cron_gateway +#!/bin/bash +${APPLICATION_ROOT}/scripts/main/main-stream_files +EOF + +# Echo result +confirmation_message "[A] Activating main stream cron (CRON ON)" +echo ""; diff --git a/scripts/cron/main-cron_deactivate b/scripts/cron/main-cron_deactivate new file mode 100755 index 0000000..ad4da61 --- /dev/null +++ b/scripts/cron/main-cron_deactivate @@ -0,0 +1,17 @@ +#!/bin/bash +# SHOW: CRON DEACTIVATE +# Empty cron-show_gateway file + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Deactivate cron job by emptying contents of cron-gateway +sudo cat /dev/null > ${APPLICATION_ROOT}/var/main-cron_gateway + + +# Echo result +confirmation_message "[D] Deactivating main stream cron (CRON OFF)" +echo ""; diff --git a/scripts/cron/main-cron_status b/scripts/cron/main-cron_status new file mode 100755 index 0000000..b1407c4 --- /dev/null +++ b/scripts/cron/main-cron_status @@ -0,0 +1,23 @@ +#!/bin/bash +# MAIN: CRON STATUS +# Check if cron-main_gateway is empty + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Check if cron-gateway is NOT empty +if [ -s ${APPLICATION_ROOT}/var/main-cron_gateway ] +then + # Echo if cron-gateway is empty (cron job is active) + confirmation_message "[S] Cron main stream status: ON / ACTIVE"; + echo ""; + +else + # Echo if cron-gateway is not empty (cron job is inactive!) + confirmation_message "[S] Cron main stream status: OFF / INACTIVE"; + echo ""; +fi + diff --git a/scripts/playlist/playlist_create b/scripts/playlist/playlist_create new file mode 100755 index 0000000..ff1c5d0 --- /dev/null +++ b/scripts/playlist/playlist_create @@ -0,0 +1,66 @@ +#!/bin/bash +# MAIN: CREATE/UPDATE PLAYLIST +# Creates and/or updates a playlist to reflect what's in main-audio_queued folder + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# If playlist exists, delete it. +if test -f "$PLAYLIST_PATH"; then + sudo rm "$PLAYLIST_PATH"; +fi +sudo touch "$PLAYLIST_PATH"; + + +# Create array of directory files +declare -a FILES_ARRAY=() +for FILE in "$AUDIO_QUEUED_DIRECTORY"/*.mp3 ; do + FILES_ARRAY+=("$FILE") +done + + +# Check if array is empty, then construct accordingly +if (( ${#FILES_ARRAY[@]} )); then + + # If files: Append header + CURRENT_DATE=$(date +"%D %T") + echo "# Playlist created date:" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "# $CURRENT_DATE" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "#" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + + # Then append tracks + echo "# Playlist tracks:" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + for TRACK in "${FILES_ARRAY[@]}" ; do + echo "$TRACK" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + done + +else + + # If no files: Append header + CURRENT_DATE=$(date +"%D %T") + echo "# Playlist date created:" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "# $CURRENT_DATE" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "#" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + + # Then append empty tracklist + echo "# Playlist tracks:" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "# (((--- PLAYLIST EMPTY ---)))" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "#" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + echo "#" | sudo tee -a "$PLAYLIST_PATH" >/dev/null + error_message + +fi + + +# Set permissions after file creation +sudo chmod 755 "$PLAYLIST_PATH"; +sudo chown "$APPLICATION_FILE_OWNER" "$PLAYLIST_PATH"; + + +# Echo result +confirmation_message "[C] Playlist create: Playlist created." +echo "" + diff --git a/scripts/playlist/playlist_edit b/scripts/playlist/playlist_edit new file mode 100755 index 0000000..6136a54 --- /dev/null +++ b/scripts/playlist/playlist_edit @@ -0,0 +1,25 @@ +#!/bin/bash +# SHOW: EDIT PLAYLIST +# Opens show playlist for editing in nano + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Check file exists, then reset permissions to ensure editing +if [[ -z $PLAYLIST_PATH ]]; then + sudo chmod 755 $PLAYLIST_PATH ; + sudo chown $PLAYLIST_PATH ; +fi + + +# Edit playlist +sudo nano $PLAYLIST_PATH; + + +# Confirm after editing +confirmation_message "[E] Main Stream Playlist Editing Completed" +echo ""; + diff --git a/scripts/playlist/playlist_view b/scripts/playlist/playlist_view new file mode 100755 index 0000000..764a43a --- /dev/null +++ b/scripts/playlist/playlist_view @@ -0,0 +1,411 @@ +#!/bin/bash +# MAIN: PLAYLIST VIEW +# Displays Playlist, with details such as time and commented out tracks + + +# $PLAYLIST_PATH +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Arrays Declarations +MASTER_USABLE_FILE_CONTENTS_ARRAY=() + + +# FUNCTION: Sum Times +function sum_times { + + + # Receive parmeters + INBOUND_ARRAY_FOR_SUMMING=("$@") + + # Get array length + INBOUND_ARRAY_FOR_SUMMING_LENGTH=${#INBOUND_ARRAY_FOR_SUMMING[@]} + + + # Sum - Centiseconds in array + + for ((i=0; i&1 | grep "Duration"); + FF_OUTPUT=${FF_OUTPUT:12}; + FF_OUTPUT=${FF_OUTPUT::-36}; + + # Return value + echo $FF_OUTPUT; + + +} + + +function calculate_playlist_time { + + + # Instsantiate Array + MASTER_USABLE_FILE_CONTENTS_ARRAY=() + + # Read playlist file contents + while IFS= read -r PLAYLIST_FILE_LINE + do + + # Remove leading spaces + PLAYLIST_LINE_NO_LEADING_SPACES=$(echo -e "${PLAYLIST_FILE_LINE}" | sed -e 's/^[[:space:]]*//') + + # If file line is not empty and ends in .mp3 + if [[ "$PLAYLIST_LINE_NO_LEADING_SPACES" != "" && $PLAYLIST_LINE_NO_LEADING_SPACES == *.mp3 ]]; then + + + # Add file to master file contents array, get length + MASTER_USABLE_FILE_CONTENTS_ARRAY+=("$PLAYLIST_LINE_NO_LEADING_SPACES") + + # Master usable array length + MASTER_USABLE_ARRAY_LENGTH=${#MASTER_USABLE_FILE_CONTENTS_ARRAY[@]} + + + fi + + done < "$PLAYLIST_PATH" + + + # Create arrays for both commented and non commented lines + ARRAY_OF_QUEUED_TIMES=() + ARRAY_OF_ALL_TIMES=() + + for LINE_FOR_HASH_CHECK in "${MASTER_USABLE_FILE_CONTENTS_ARRAY[@]}"; do + + + # If first character beings with hash + if [[ ${LINE_FOR_HASH_CHECK:0:1} = "#" ]]; then + + + # Remove Hash + # LINE_FOR_HASH_CHECK=$(echo $LINE_FOR_HASH_CHECK | sed -e "s/\#//") + LINE_FOR_HASH_CHECK=$(echo -e "${LINE_FOR_HASH_CHECK}" | sed -e 's/^[#| ]*//') + LINE_FOR_HASH_CHECK=$(echo -e "${LINE_FOR_HASH_CHECK}" | sed -e 's/^[[:space:]]*//') + + # Run get_ffprobe_time for value + FF_PROBE_RESULT=$(get_ffprobe_time "${LINE_FOR_HASH_CHECK}") + + # Add to arrays (both, in this case) + ARRAY_OF_ALL_TIMES=( "${ARRAY_OF_ALL_TIMES[@]}" "$FF_PROBE_RESULT" ) + + + # Else if line doesn't start with hash + else + + + # Run get_ffprobe_time for value + FF_PROBE_RESULT=$(get_ffprobe_time "${LINE_FOR_HASH_CHECK}") + + # # Add to all array only + ARRAY_OF_QUEUED_TIMES=( "${ARRAY_OF_QUEUED_TIMES[@]}" "$FF_PROBE_RESULT" ) + ARRAY_OF_ALL_TIMES=( "${ARRAY_OF_ALL_TIMES[@]}" "$FF_PROBE_RESULT" ) + + + fi + + + done + + + # Render Results + printf "${COLOR_GREEN}[V] Playlist view:${COLOR_DEFAULT}\n"; + echo "" + echo "" + echo " ${FONT_BOLD}PLAYLIST FILES (HH:MM:SS.MS)${FONT_DEFAULT}" + echo "" + + # Numbmering Indexes (the printable ones) + FRIENDLY_INDEX=1; + COMPLETE_INDEX=1; + + # Create Array + ARRAY_OF_QUEUED_TRACKS=() + + for (( i = 0; i < $MASTER_USABLE_ARRAY_LENGTH; i++ )); do + + + # Prepare Filename to Echo + FILENAME_TO_ECHO=${MASTER_USABLE_FILE_CONTENTS_ARRAY[$i]} + FILENAME_TO_ECHO=$(sed -e s/"^.*queued\/"// <<< ${FILENAME_TO_ECHO}) + + # check if line begins with # + if [[ ${MASTER_USABLE_FILE_CONTENTS_ARRAY[$i]:0:1} == "#" ]]; then + + if [[ ${MASTER_USABLE_FILE_CONTENTS_ARRAY[$i]:0:1} == "#" ]]; then + + # Prepare "printable complete index" + if [[ ${#COMPLETE_INDEX} = 1 ]]; then + printf " ${COLOR_GRAY}[0$COMPLETE_INDEX] ${ARRAY_OF_ALL_TIMES[$i]} – # ${FILENAME_TO_ECHO}${COLOR_DEFAULT}\n" + else + printf " ${COLOR_GRAY}[$COMPLETE_INDEX] ${ARRAY_OF_ALL_TIMES[$i]} – # ${FILENAME_TO_ECHO}${COLOR_DEFAULT}\n" + fi + + fi + + # Else if line doesn't start with # + else + + # If does not start with # + if [[ ${#FRIENDLY_INDEX} = 1 ]]; then + printf " 0$FRIENDLY_INDEX" + else + printf " $FRIENDLY_INDEX" + fi + FRIENDLY_INDEX=$((FRIENDLY_INDEX+1)) + + # Prepare "printable complete index" (later gets indexed outside loop) + if [[ ${#COMPLETE_INDEX} = 1 ]]; then + printf " $SYMBOL_RAQUO [0$COMPLETE_INDEX] " + else + printf " $SYMBOL_RAQUO [$COMPLETE_INDEX] " + fi + + # Echo Time + echo -e " ${ARRAY_OF_ALL_TIMES[$i]} – ${FILENAME_TO_ECHO}" + + + fi + + # Index "complete index" + COMPLETE_INDEX=$((COMPLETE_INDEX+1)) + + done + + + # Deincrement friendly index, because increment happens in loop after it's printed + FRIENDLY_INDEX=$(("$FRIENDLY_INDEX-1")) # Get final count of queued times + FINAL_COUNT_OF_QUEUED_ITEMS=${#ARRAY_OF_QUEUED_TIMES[@]} + + # Unsetariables and get sum of time arrays (for all files and queued files) + SUM_OF_QUEUED_TIMES="" + # SUM_OF_NT_OF_ALL_ITEMS=${#ARRAY_OF_ALL_TIMES[@]}ALL_TIMES="" + SUM_OF_QUEUED_TIMES=$(sum_times "${ARRAY_OF_QUEUED_TIMES[@]}") + SUM_OF_ALL_TIMES=$(sum_times "${ARRAY_OF_ALL_TIMES[@]}") + + # Echo Output + echo -e "" + echo -e " ${FONT_BOLD}Total (${FINAL_COUNT_OF_QUEUED_ITEMS}/${MASTER_USABLE_ARRAY_LENGTH} tracks): $SUM_OF_QUEUED_TIMES / $SUM_OF_ALL_TIMES${FONT_DEFAULT}\n" + echo -e "" + echo -e "" + echo -e "" + + +} + +function verify_playlist_integrity() { + + + # Clear Array + INTEGRITY_CHECK_FILE_LINES_ARRAY=() + + # Declare integrity check flag + INTEGRITY_CHECK_FLAG="true" + + # Read playlist file contents + while IFS= read -r PLAYLIST_FILE_LINE + do + + # Remove leading spaces + PLAYLIST_LINE_WITH_NO_LEADING_SPACES=$(echo -e "${PLAYLIST_FILE_LINE}" | sed -e 's/^[[:space:]]*//') + + # If line isn't blank + if [[ -n $PLAYLIST_LINE_WITH_NO_LEADING_SPACES ]]; + then + + # If ends in .mp3 + if [[ "$PLAYLIST_LINE_WITH_NO_LEADING_SPACES" == *.mp3 ]]; then + + # remove pound + PLAYLIST_LINE_WITH_NO_LEADING_POUND=$(echo -e "${PLAYLIST_LINE_WITH_NO_LEADING_SPACES}" | sed -e 's/^[#| ]*//') + + # Add file to master file contents array, get length + INTEGRITY_CHECK_FILE_LINES_ARRAY+=("$PLAYLIST_LINE_WITH_NO_LEADING_POUND") + + fi + + # If line is blank (then don't add to array / continue) + else + + continue + + fi + + done < "$PLAYLIST_PATH" + + # Check that a file exists for each playlist line + for INTEGRITY_CHECK_ITEM in "${INTEGRITY_CHECK_FILE_LINES_ARRAY[@]}" + do + + # If doesn't exist then throw notice + if [[ ! -f "$INTEGRITY_CHECK_ITEM" ]]; + + then + + # Flag as failed + INTEGRITY_CHECK_FLAG="false" + + + fi + + done + echo $INTEGRITY_CHECK_FLAG + + +} + + +# If playlist file exists, then do routine +if test -f "$PLAYLIST_PATH"; + + # Execute calcualte_playlist_time + then + + MASTER_PLAYLIST_INTEGRITY_CHECK=$(verify_playlist_integrity) + if [[ "$MASTER_PLAYLIST_INTEGRITY_CHECK" == "true" ]]; + + # If playlist integrity check passed + then + echo "Calculating playlist time..." + calculate_playlist_time + + # else error + else + error_message "[V] View playlist: playlist contains invalid refs. Please edit or recreate for summary." + echo "" + + fi + + + # else if playlist file doesn't exist + else + error_message "[V] View playlist: playlist file not found. Run \"C\" to create."; + echo "" + +fi diff --git a/scripts/queued/queued_folder_contents b/scripts/queued/queued_folder_contents new file mode 100755 index 0000000..5c08548 --- /dev/null +++ b/scripts/queued/queued_folder_contents @@ -0,0 +1,56 @@ +#!/bin/bash +# SHOW: CREATE/UPDATE PLAYLIST +# Creates and/or updates a playlist to reflect what's in openmic-audio_queued folder + + +# Includes and Declarations (global variables, formatting, and functions) +source "$APPLICATION_ROOT/scripts/system/system-functions" +source "$APPLICATION_ROOT/scripts/system/system-declarations" + + +# Check if directory is empty +if [[ $(ls "$AUDIO_QUEUED_DIRECTORY") ]]; then + + # If not empty, render list + echo -e "${COLOR_GREEN}[Q] \"audio_queued\" folder contents (${i} items):${COLOR_DEFAULT}" + echo -e "" + echo -e "" + echo -e " ${FONT_BOLD}SHOW QUEUED FOLDER CONTENTS${FONT_DEFAULT}" + echo -e "" + + + # Cycle through openmic audio queued directory, and print each line (just filename) + i=1 + for FILE in "$AUDIO_QUEUED_DIRECTORY"/*; do + + + # Check i's length. If less than 10, add zero to front + STRLENGTH=${#i} + if [[ $STRLENGTH == 1 ]]; then + LEADING_ZERO_INSERTION="0" + else + LEADING_ZERO_INSERTION="" + fi + + # Render line (FILE printout) with number in front + JUST_FILENAME=$(echo "$FILE" | sed "s/.*\///") + echo -e " $LEADING_ZERO_INSERTION$i: \"$JUST_FILENAME\"" + + # Increment i + i=$((i+1)); + + done + FILE_COUNT=$((i-1)) + echo -e ""; + echo -e " ${FONT_BOLD}[${FILE_COUNT} Files Found]${FONT_DEFAULT}\n" + echo -e ""; + echo -e ""; + echo -e ""; + +else + + # If directory is empty + error_message "[Q] The \"audio_queued\" directory is empty. Add audio files."; + echo "" + +fi diff --git a/scripts/streaming/main/main-stream_files b/scripts/streaming/main/main-stream_files new file mode 100755 index 0000000..1e7208f --- /dev/null +++ b/scripts/streaming/main/main-stream_files @@ -0,0 +1,93 @@ +#!/bin/bash +# SHOW: STREAM FILES +# Streams files as indexed in show-playlist.m3u (which is based on show-audio_queud) + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Get active config name, construct path to streamable config file (for validation) +CURRENTLY_ACTIVE_CONFIG_NAME=$(<"$CONFIG_FILE_IDENTIFIER_PATH") +STREAMABLE_CONFIG_FILE_PATH="$CONFIG_DIRECTORY/config-$CURRENTLY_ACTIVE_CONFIG_NAME.json" + + +# Check if config file exists +if [[ -f "$STREAMABLE_CONFIG_FILE_PATH" ]]; + + # If exists + then + + # Parse JSON config file for each variable + v1='main_host' + MAIN_HOST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v1//p" $STREAMABLE_CONFIG_FILE_PATH)) + v2='main_port' + MAIN_PORT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v2//p" $STREAMABLE_CONFIG_FILE_PATH)) + v3='main_user' + MAIN_USER=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v3//p" $STREAMABLE_CONFIG_FILE_PATH)) + v4='main_password' + MAIN_PASSWORD=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v4//p" $STREAMABLE_CONFIG_FILE_PATH)) + v5='main_mount' + MAIN_MOUNT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v5//p" $STREAMABLE_CONFIG_FILE_PATH)) + v6='playlist_url' + PLAYLIST_URL=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v6//p" $STREAMABLE_CONFIG_FILE_PATH)) + v7='randomize_playlist_files' + RANDOMIZE_PLAYLIST_FILES=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v7//p" $STREAMABLE_CONFIG_FILE_PATH)) + v8='hardware_audio_frame_size' + HARDWARE_AUDIO_FRAME_SIZE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v8//p" $STREAMABLE_CONFIG_FILE_PATH)) + + + # Ensure all configuration files are not blank + if [ -z "${MAIN_HOST}" ] || [ -z "${MAIN_PORT}" ] || [ -z "${MAIN_USER}" ] || [ -z "${MAIN_PASSWORD}" ] || [ -z "${MAIN_MOUNT}" ] || [ -z "${PLAYLIST_URL}" ] || [ -z "${RANDOMIZE_PLAYLIST_FILES}" ] || [ -z "${HARDWARE_AUDIO_FRAME_SIZE}" ] + then + + # Fault if config variable is blank + printf "${COLOR_RED}[F] Stream Files (to Main): Streaming failed. Check your playlist, files, and/or settings.${COLOR_DEFAULT}\n\n"; + + else + + printf "${COLOR_GREEN}[F] Stream Files (to Main):${COLOR_DEFAULT}\n"; + printf "\n" + printf "\n" + printf "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[STARTING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + printf "${COLOR_MAGENTA}" + + # Launch Liquidsoap using variables + # liquidsoap 'set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); output.icecast(%mp3,host="'$MAIN_HOST'",port='$MAIN_PORT',user="'$MAIN_USER'",password="'$MAIN_PASSWORD'",mount="'$MAIN_MOUNT'",mksafe(playlist.once(random='$MAIN_RANDOMIZE_PLAYLIST_FILES',on_done=shutdown,"'$PLAYLIST_URL'")))'; + liquidsoap ' + set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); + + stream_master_source = output.icecast( + %mp3, + host="'$MAIN_HOST'", + port='$MAIN_PORT', + user="'$MAIN_USER'", + password="'$MAIN_PASSWORD'", + mount="'$MAIN_MOUNT'", + fallible=true, + on_stop=shutdown, + playlist.once( + random='$RANDOMIZE_PLAYLIST_FILES', + "'$PLAYLIST_URL'" + ) + ) + + stream_master_source + ' + + printf ${COLOR_DEFAULT} + printf "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[EXITING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + printf "\n" + printf "\n" + printf "\n" + + fi + + # If no config file exists + else + error_message "[F] Stream Files (to Main): No config file specified. To stream, please assign a config." + echo "" + +fi + diff --git a/scripts/streaming/main/main-stream_live_alsa b/scripts/streaming/main/main-stream_live_alsa new file mode 100755 index 0000000..a0c4034 --- /dev/null +++ b/scripts/streaming/main/main-stream_live_alsa @@ -0,0 +1,113 @@ +#!/bin/bash +# SHOW: STREAM LIVE +# Streams show live from input/ALSA + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Get active config name, construct path to streamable config file (for validation) +CURRENTLY_ACTIVE_CONFIG_NAME=$(<"$CONFIG_FILE_IDENTIFIER_PATH") +STREAMABLE_CONFIG_FILE_PATH="$CONFIG_DIRECTORY/config-$CURRENTLY_ACTIVE_CONFIG_NAME.json" + + +# Check if config file exists +if [[ -f "$STREAMABLE_CONFIG_FILE_PATH" ]]; + + # If exists + then + + # Parse JSON config file for each crucial streaming variable + v1='main_host' + MAIN_HOST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v1//p" $STREAMABLE_CONFIG_FILE_PATH)) + v2='main_port' + MAIN_PORT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v2//p" $STREAMABLE_CONFIG_FILE_PATH)) + v3='main_user' + MAIN_USER=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v3//p" $STREAMABLE_CONFIG_FILE_PATH)) + v4='main_password' + MAIN_PASSWORD=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v4//p" $STREAMABLE_CONFIG_FILE_PATH)) + v5='main_mount' + MAIN_MOUNT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v5//p" $STREAMABLE_CONFIG_FILE_PATH)) + v6='playlist_url' + PLAYLIST_URL=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v6//p" $STREAMABLE_CONFIG_FILE_PATH)) + v7='randomize_playlist_files' + RANDOMIZE_PLAYLIST_FILES=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v7//p" $STREAMABLE_CONFIG_FILE_PATH)) + v8='hardware_audio_frame_size' + HARDWARE_AUDIO_FRAME_SIZE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v8//p" $STREAMABLE_CONFIG_FILE_PATH)) + + # Parse JSON config file for each metadata streaming variable + v9='main_metadata_artist' + MAIN_METADATA_ARTIST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v9//p" $STREAMABLE_CONFIG_FILE_PATH)) + # MAIN_METADATA_ARTIST="${MAIN_METADATA_ARTIST// /\+}" + vA='main_metadata_title' + MAIN_METADATA_TITLE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$vA//p" $STREAMABLE_CONFIG_FILE_PATH)) + # MAIN_METADATA_TITLE="${MAIN_METADATA_TITLE// /\+}" + + + + # Ensure all configuration files are not blank + if [ -z "${MAIN_HOST}" ] || [ -z "${MAIN_PORT}" ] || [ -z "${MAIN_USER}" ] || [ -z "${MAIN_PASSWORD}" ] || [ -z "${MAIN_MOUNT}" ] || [ -z "${PLAYLIST_URL}" ] || [ -z "${RANDOMIZE_PLAYLIST_FILES}" ] || [ -z "${HARDWARE_AUDIO_FRAME_SIZE}" ] + then + + # Fault if config variable is blank + error_message "[L] Stream ALSA (to Main): Streaming failed. Please check your configuration settings."; + echo "" + + else + + # Notice of Execution + confirmation_message "${COLOR_GREEN}[L] Stream ALSA (to Main):${COLOR_DEFAULT}"; + + + # Encode and Submit Metadata Change (Hack: two requests to get changes to take) + CONVERTED_MAIN_METADATA_TITLE=$(url_encode_string "$MAIN_METADATA_TITLE") + CONVERTED_MAIN_METADATA_ARTIST=$(url_encode_string "$MAIN_METADATA_ARTIST") + curl "http://$MAIN_USER:$MAIN_PASSWORD@$MAIN_HOST:$MAIN_PORT/admin/metadata?mode=updinfo&mount=/&title='$CONVERTED_MAIN_METADATA_TITLE'&artist='$CONVERTED_MAIN_METADATA_ARTIST'" + sleep 5 + curl "http://$MAIN_USER:$MAIN_PASSWORD@$MAIN_HOST:$MAIN_PORT/admin/metadata?mode=updinfo&mount=/&title='$CONVERTED_MAIN_METADATA_TITLE'&artist='$CONVERTED_MAIN_METADATA_ARTIST'" + + + # Liquidsoap Log + echo -e "\n" + echo -e "\n" + echo -e "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[STARTING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + echo -e "${COLOR_MAGENTA}" + + + # Launch Liquidsoap using variables + # liquidsoap 'set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); output.icecast(%mp3,host="'$MAIN_HOST'",port='$MAIN_PORT',user="'$MAIN_USER'",password="'$MAIN_PASSWORD'",mount="'$MAIN_MOUNT'",mksafe(playlist.once(random='$MAIN_RANDOMIZE_PLAYLIST_FILES',on_done=shutdown,"'$PLAYLIST_URL'")))'; + liquidsoap ' + set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); + + stream_master_source = output.icecast( + %mp3(bitrate=192,samplerate=44100), + host="'$MAIN_HOST'", + port='$MAIN_PORT', + user="'$MAIN_USER'", + password="'$MAIN_PASSWORD'", + mount="'$MAIN_MOUNT'", + input.alsa(bufferize = true) + ) + + stream_master_source + ' + + printf ${COLOR_DEFAULT} + printf "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[EXITING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + printf "\n" + printf "\n" + printf "\n" + + + fi + + + # If no config file exists + else + error_message "[L] Stream ALSA (to Main): No config file specified. To stream, please assign a config." + echo "" + +fi + diff --git a/scripts/streaming/testing/testing-stream_files b/scripts/streaming/testing/testing-stream_files new file mode 100755 index 0000000..3900888 --- /dev/null +++ b/scripts/streaming/testing/testing-stream_files @@ -0,0 +1,99 @@ +#!/bin/bash +# TESTING: STREAM FILES +# Streams files as indexed in openmic-playlist.m3u (which is based on openmic-audio_queud) + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Get active config name, construct path to streamable config file (for validation) +CURRENTLY_ACTIVE_CONFIG_NAME=$(<"$CONFIG_FILE_IDENTIFIER_PATH") +STREAMABLE_CONFIG_FILE_PATH="$CONFIG_DIRECTORY/config-$CURRENTLY_ACTIVE_CONFIG_NAME.json" + + +# Check if config file exists +if [[ -f "$STREAMABLE_CONFIG_FILE_PATH" ]]; + + # If exists + then + + # Parse JSON config file for each variable + v1='testing_host' + TESTING_HOST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v1//p" $STREAMABLE_CONFIG_FILE_PATH)) + v2='testing_port' + TESTING_PORT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v2//p" $STREAMABLE_CONFIG_FILE_PATH)) + v3='testing_user' + TESTING_USER=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v3//p" $STREAMABLE_CONFIG_FILE_PATH)) + v4='testing_password' + TESTING_PASSWORD=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v4//p" $STREAMABLE_CONFIG_FILE_PATH)) + v5='testing_mount' + TESTING_MOUNT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v5//p" $STREAMABLE_CONFIG_FILE_PATH)) + v6='playlist_url' + PLAYLIST_URL=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v6//p" $STREAMABLE_CONFIG_FILE_PATH)) + v7='randomize_playlist_files' + RANDOMIZE_PLAYLIST_FILES=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v7//p" $STREAMABLE_CONFIG_FILE_PATH)) + v8='hardware_audio_frame_size' + HARDWARE_AUDIO_FRAME_SIZE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v8//p" $STREAMABLE_CONFIG_FILE_PATH)) + + + # Ensure all configuration files are not blank + if [ -z "${TESTING_HOST}" ] || [ -z "${TESTING_PORT}" ] || [ -z "${TESTING_USER}" ] || [ -z "${TESTING_PASSWORD}" ] || [ -z "${TESTING_MOUNT}" ] || [ -z "${PLAYLIST_URL}" ] || [ -z "${RANDOMIZE_PLAYLIST_FILES}" ] || [ -z "${HARDWARE_AUDIO_FRAME_SIZE}" ] + then + + # Fault if config variable is blank + error_message "[f] Stream Files (to Testing): Streaming failed. Check your playlist, files, and/or settings.${COLOR_DEFAULT}"; + echo "" + + else + + confirmation_message "[f] Stream Files (to Testing):"; + echo "" + echo "" + echo -e "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[STARTING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + echo -e "${COLOR_MAGENTA}" + + + # Launch Liquidsoap using variables + # liquidsoap 'set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); output.icecast(%mp3,host="'$TESTING_HOST'",port='$TESTING_PORT',user="'$TESTING_USER'",password="'$TESTING_PASSWORD'",mount="'$TESTING_MOUNT'",mksafe(playlist.once(random='$RANDOMIZE_PLAYLIST_FILES',on_done=shutdown,"'$PLAYLIST_URL'")))'; + liquidsoap ' + set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); + + stream_master_source = output.icecast( + %mp3, + host="'$TESTING_HOST'", + port='$TESTING_PORT', + user="'$TESTING_USER'", + password="'$TESTING_PASSWORD'", + mount="'$TESTING_MOUNT'", + fallible=true, + on_stop=shutdown, + playlist.once( + random='$RANDOMIZE_PLAYLIST_FILES', + "'$PLAYLIST_URL'" + ) + ) + + stream_master_source + ' + + echo -e ${COLOR_DEFAULT} + echo -e "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[EXITING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + echo -e "\n" + echo -e "\n" + echo -e "\n" + + + fi + + + # If no config file exists + else + error_message "[f] Stream Files (to Testing): No config file specified. To stream, please assign a config." + echo "" + +fi + + + diff --git a/scripts/streaming/testing/testing-stream_live_alsa b/scripts/streaming/testing/testing-stream_live_alsa new file mode 100755 index 0000000..ad12b6d --- /dev/null +++ b/scripts/streaming/testing/testing-stream_live_alsa @@ -0,0 +1,113 @@ +#!/bin/bash +# OPENMIC: STREAM LIVE +# Streams openmic live from input/ALSA + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Get active config name, construct path to streamable config file (for validation) +CURRENTLY_ACTIVE_CONFIG_NAME=$(<"$CONFIG_FILE_IDENTIFIER_PATH") +STREAMABLE_CONFIG_FILE_PATH="$CONFIG_DIRECTORY/config-$CURRENTLY_ACTIVE_CONFIG_NAME.json" + + +# Check if config file exists +if [[ -f "$CURRENTLY_ACTIVE_CONFIG_NAME" ]]; + + # If exists + then + + # Parse JSON config file for each crucial streaming variable + v1='testing_host' + TESTING_HOST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v1//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v2='testing_port' + TESTING_PORT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v2//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v3='testing_user' + TESTING_USER=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v3//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v4='testing_password' + TESTING_PASSWORD=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v4//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v5='testing_mount' + TESTING_MOUNT=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v5//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v6='playlist_url' + PLAYLIST_URL=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v6//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v7='randomize_playlist_files' + RANDOMIZE_PLAYLIST_FILES=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v7//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + v8='hardware_audio_frame_size' + HARDWARE_AUDIO_FRAME_SIZE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v8//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + + # Parse JSON config file for each metadata streaming variable + v9='testing_metadata_artist' + TESTING_METADATA_ARTIST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$v9//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + # TESTING_METADATA_ARTIST="${TESTING_METADATA_ARTIST// /\+}" + vA='testing_metadata_title' + TESTING_METADATA_TITLE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$vA//p" $CURRENTLY_ACTIVE_CONFIG_NAME)) + # TESTING_METADATA_TITLE="${TESTING_METADATA_TITLE// /\+}" + + + + # Ensure all configuration files are not blank + if [ -z "${TESTING_HOST}" ] || [ -z "${TESTING_PORT}" ] || [ -z "${TESTING_USER}" ] || [ -z "${TESTING_PASSWORD}" ] || [ -z "${TESTING_MOUNT}" ] || [ -z "${PLAYLIST_URL}" ] || [ -z "${RANDOMIZE_PLAYLIST_FILES}" ] || [ -z "${HARDWARE_AUDIO_FRAME_SIZE}" ] + then + + # Fault if config variable is blank + error_message "[l] Stream ALSA (to Testing): Streaming failed. Please check your configuration settings." + echo "" + + else + + # Notice of Execution + confirmation_message "${COLOR_GREEN}[l] Stream ALSA (to Testing):${COLOR_DEFAULT}"; + + + # Encode and Submit Metadata Change (Hack: two requests to get changes to take) + CONVERTED_TESTING_METADATA_TITLE=$(url_encode_string "$TESTING_METADATA_TITLE") + CONVERTED_TESTING_METADATA_ARTIST=$(url_encode_string "$TESTING_METADATA_ARTIST") + curl "http://$TESTING_USER:$TESTING_PASSWORD@$TESTING_HOST:$TESTING_PORT/admin/metadata?mode=updinfo&mount=/&title='$CONVERTED_TESTING_METADATA_TITLE'&artist='$CONVERTED_TESTING_METADATA_ARTIST'" + sleep 5 + curl "http://$TESTING_USER:$TESTING_PASSWORD@$TESTING_HOST:$TESTING_PORT/admin/metadata?mode=updinfo&mount=/&title='$CONVERTED_TESTING_METADATA_TITLE'&artist='$CONVERTED_TESTING_METADATA_ARTIST'" + + + # Liquidsoap Log + echo -e "\n" + echo -e "\n" + echo -e "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[STARTING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + echo -e "${COLOR_MAGENTA}" + + + # Launch Liquidsoap using variables + # liquidsoap 'set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); output.icecast(%mp3,host="'$TESTING_HOST'",port='$TESTING_PORT',user="'$TESTING_USER'",password="'$TESTING_PASSWORD'",mount="'$TESTING_MOUNT'",mksafe(playlist.once(random='$RANDOMIZE_PLAYLIST_FILES',on_done=shutdown,"'$PLAYLIST_URL'")))'; + liquidsoap ' + set("frame.audio.size",'$HARDWARE_AUDIO_FRAME_SIZE'); + + stream_master_source = output.icecast( + %mp3(bitrate=192,samplerate=44100), + host="'$TESTING_HOST'", + port='$TESTING_PORT', + user="'$TESTING_USER'", + password="'$TESTING_PASSWORD'", + mount="'$TESTING_MOUNT'", + input.alsa(bufferize = true) + ) + + stream_master_source + ' + + echo -e ${COLOR_DEFAULT} + echo -e "${COLOR_LIGHT_MAGENTA}${FONT_BOLD}[EXITING LIQUIDSOAP]${FONT_DEFAULT}${COLOR_DEFAULT}\n" + echo -e "\n" + echo -e "\n" + echo -e "\n" + + + fi + + # If no config file exists + else + error_message "[l] Stream ALSA (to Testing): No config file specified. To stream, please assign a config." + echo "" + +fi + + diff --git a/scripts/system/system-alsa_mixer b/scripts/system/system-alsa_mixer new file mode 100755 index 0000000..cb626b2 --- /dev/null +++ b/scripts/system/system-alsa_mixer @@ -0,0 +1,18 @@ +#!/bin/bash +# SYSTEM: ALSA MIXER +# Launch alsamixer + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# If playlist exists, delete it. +sudo alsamixer + + +# Echo result +confirmation_message "[M] ALSA mixer visitation completed" +echo ""; + diff --git a/scripts/system/system-config b/scripts/system/system-config new file mode 100755 index 0000000..0fddf64 --- /dev/null +++ b/scripts/system/system-config @@ -0,0 +1,356 @@ +#!/bin/bash +# SYSTEM: CONFIG Options +# Edit System Configuration (.json) file + +# COPY HAS VALIDATION BUGS +# RENAME IS NOT YET DONE + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# +# +# FUNCTION: Refresh Config File Reference Array +# Creates two new arrays in parallel of availalble configurations +# Array 1 - $CONFIG_PROFILES_ARRAY : list of profile names +# Array 2 - $CONFIG_PROFILES_PATHS_ARRAY : list of profile paths +# +# +function refresh_config_file_reference_array () { + + + # Empty Arrays + unset CONFIG_PROFILES_ARRAY + unset CONFIG_PROFILES_PATHS_ARRAY + + + # If Config Directory is empty + if [ -z "$(ls -A $CONFIG_DIRECTORY)" ]; then + + echo - "Config directory is currently empty. Please create a new config file using option 'n'." + + + # Else if Config Directory is not empty + else + + + # Instantiate counter, then read directory (declared in file 'system-declarations') + for CONFIG_DIRECTORY_ITEM in "$CONFIG_DIRECTORY"/*; do + + # If file is of type json, proceed + if [[ $CONFIG_DIRECTORY_ITEM == *.json ]]; then + + # if file is of pitfall condition, rename with timestamp + CONFIG_NAME=$(echo "${CONFIG_DIRECTORY_ITEM}" | sed "s|$CONFIG_DIRECTORY/||") + if [[ $CONFIG_NAME == "config-.json" ]] || [[ $CONFIG_NAME == "config.json" ]]; then + + # Create hex value of 6 length, and rename violating files + RANDOM_HEX_VALUE=$( generate_random_hex_value 6 ) + CONFIG_NAME_RENAMED="config-${RANDOM_HEX_VALUE}.json" + mv "$CONFIG_DIRECTORY/$CONFIG_NAME" "$CONFIG_DIRECTORY/$CONFIG_NAME_RENAMED" + + # Declare chaneges for main name and directory variable (then alert) + CONFIG_DIRECTORY_ITEM="$CONFIG_DIRECTORY/$CONFIG_NAME_RENAMED" + warning_message "[Alert] Unnamed config \"$CONFIG_NAME\" renamed \"$CONFIG_NAME_RENAMED\" " + CONFIG_NAME="$CONFIG_NAME_RENAMED" + + fi + + + # Full File Path, and sed a Display Name (ennumerated) + CONFIG_NAME_TRUNCATED=$(echo "${CONFIG_NAME}" | sed "s|config-||" | sed "s/.json//") + + # Apply to master arrays + CONFIG_PROFILES_ARRAY+=("$CONFIG_NAME_TRUNCATED") + CONFIG_PROFILES_PATHS_ARRAY+=("$CONFIG_DIRECTORY_ITEM") + + + fi + + + done + + # # Debug: + # echo "CONFIG PROFILES ARRAY: ${CONFIG_PROFILES_ARRAY[*]}" + # echo "CONFIG PROFILES PATHS ARRAY: ${CONFIG_PROFILES_PATHS_ARRAY[*]}" + + fi + + +} + + +# +# +# FUNCTION: List existing config files +# Echos a list of available profile names (called in render_config_menu) +# +# +function list_existing_config_files { + + # Get active file name + CURRENTLY_ACTIVE_CONFIG_FILE=$(<"$CONFIG_FILE_IDENTIFIER_PATH") + + # List menu section heading + echo -e " ${COLOR_WHITE}${FONT_BOLD}CONFIG PROFILES & META:${FONT_DEFAULT}${COLOR_DEFAULT}"; + + + if (( ${#CONFIG_PROFILES_ARRAY[@]} )); then + + # If config array does exist + PROFILE_COUNTER=0 + for i in ${CONFIG_PROFILES_ARRAY[*]} + + + do : + + # Check if active profile name is current 'for' item + if [[ $i == "$CURRENTLY_ACTIVE_CONFIG_FILE" ]]; then + + # Render profile name + echo -e " ${COLOR_CYAN}${FONT_BOLD}${SYMBOL_RAQUO}${COLOR_DEFAULT}${FONT_DEFAULT} $i ${COLOR_CYAN}(using)${COLOR_DEFAULT}" + + # Render profile metadata + JSON_FIELD_NAME_META_ARTIST='main_metadata_artist' + MAIN_METADATA_ARTIST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$JSON_FIELD_NAME_META_ARTIST//p" ${CONFIG_PROFILES_PATHS_ARRAY[$PROFILE_COUNTER]})) + # MAIN_METADATA_ARTIST="${MAIN_METADATA_ARTIST// /\+}" + echo -e " Artist: \"$MAIN_METADATA_ARTIST\""; + JSON_FIELD_NAME_META_TITLE='main_metadata_title' + MAIN_METADATA_TITLE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$JSON_FIELD_NAME_META_TITLE//p" ${CONFIG_PROFILES_PATHS_ARRAY[$PROFILE_COUNTER]})) + # MAIN_METADATA_TITLE="${MAIN_METADATA_TITLE// /\+}" + echo -e " Title: \"$MAIN_METADATA_TITLE\""; + + # Empty metadata display variables + MAIN_METADATA_ARTIST="" + MAIN_METADATA_TITLE="" + + + else + + # Render profile name + echo -e " $i" + + # Render profile metadata + JSON_FIELD_NAME_META_ARTIST='main_metadata_artist' + MAIN_METADATA_ARTIST=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$JSON_FIELD_NAME_META_ARTIST//p" ${CONFIG_PROFILES_PATHS_ARRAY[$PROFILE_COUNTER]})) + # MAIN_METADATA_ARTIST="${MAIN_METADATA_ARTIST// /\+}" + echo -e " Artist: \"$MAIN_METADATA_ARTIST\""; + JSON_FIELD_NAME_META_TITLE='main_metadata_title' + MAIN_METADATA_TITLE=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/$JSON_FIELD_NAME_META_TITLE//p" ${CONFIG_PROFILES_PATHS_ARRAY[$PROFILE_COUNTER]})) + # MAIN_METADATA_TITLE="${MAIN_METADATA_TITLE// /\+}" + echo -e " Title: \"$MAIN_METADATA_TITLE\""; + + # Empty metadata display variables + MAIN_METADATA_ARTIST="" + MAIN_METADATA_TITLE="" + + + fi + + # Increment Counter + PROFILE_COUNTER=$((PROFILE_COUNTER+1)) + + done + + + else + + echo -e " ${COLOR_RED}${FONT_BOLD}[Empty! - run \"n\" to create a profile!]${FONT_DEFAULT}${COLOR_DEFAULT}" + + + fi + + # Empty variables + PROFILE_COUNTER=0 + + +} + + +# +# +# FUNCTION: Verify Configuration Filename Characters +# Verifies inbound string against specified $REGEX, returning true or false match +# Returns a true or false confirmation +# +# +function verify_configuration_filename_characters() +{ + + REGEX="^[a-zA-Z0-9\ \_-]+$" + if [[ "$*" =~ ${REGEX} ]] + then + TEMP="true" + else + TEMP="false" + fi + echo $TEMP + +} + + +# +# +# FUNCTION: Convert Spaces to Underscores +# Converts inbound string's spaces to underscores, returns converted string +# +# +function convert_spaces_to_underscores() { + TEMP=${*// /_} + echo "$TEMP" +} + + +# +# +# FUNCTION: Render Config Menu +# Renders main configuration menu (option "J" from main menu) +# +# +function render_config_menu { + + list_existing_config_files + echo -e "" + + # Mini HR + printf " " + render_mini_horizontal_rule + echo -e "" + + # Render + echo -e " ${COLOR_WHITE}${FONT_BOLD}CONFIG OPTIONS:${FONT_DEFAULT}${COLOR_DEFAULT}"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}e${FONT_DEFAULT}${COLOR_DEFAULT} : edit"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}n${FONT_DEFAULT}${COLOR_DEFAULT} : new"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}d${FONT_DEFAULT}${COLOR_DEFAULT} : delete"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}c${FONT_DEFAULT}${COLOR_DEFAULT} : copy"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}r${FONT_DEFAULT}${COLOR_DEFAULT} : rename"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}x${FONT_DEFAULT}${COLOR_DEFAULT} : empty deleted trash"; + echo -e "" + echo -e " ${COLOR_WHITE}${FONT_BOLD}CONFIG ACTIVATION:${FONT_DEFAULT}${COLOR_DEFAULT}"; + echo -e " ${COLOR_CYAN}${FONT_BOLD}u${FONT_DEFAULT}${COLOR_DEFAULT} : use"; + echo -e "" + echo -e "" + echo -e "" + +} + + +# +# +# FUNCTION: Process Config Menu Selection +# Processes main input from config menu +# +# +function process_config_menu_selection() { + + # Case Switch + case $1 in + + e) # Edit JSON Streaming Profile: + source "${APPLICATION_ROOT}/scripts/system/system-config_edit" ;; + n) # New JSON Streaming Profile: + source "${APPLICATION_ROOT}/scripts/system/system-config_new" ;; + d) # Delete JSON Streaming Profile: + source "${APPLICATION_ROOT}/scripts/system/system-config_delete" ;; + c) # Copy Profile + source "${APPLICATION_ROOT}/scripts/system/system-config_copy" ;; + r) # Rename Profile + source "${APPLICATION_ROOT}/scripts/system/system-config_rename" ;; + u) # Use Profile + source "${APPLICATION_ROOT}/scripts/system/system-config_use" ;; + x) # Empty Trash + source "${APPLICATION_ROOT}/scripts/system/system-config_empty_trash" ;; + + esac + +} + + +# +# +# FUNCTION: Main Program Function +# Master program run routine (and run execution) +# +# +function execute_config_routine { + + + # Refresh Array of Available Configs and render menu + printf "${COLOR_GREEN}[J] Config Options menu:${COLOR_DEFAULT}\n"; + echo -e "" + echo -e "" + + # Declare, localize, and refresh arrays + unset CONFIG_PROFILES_ARRAY + declare -a CONFIG_PROFILES_ARRAY=() >/dev/null + local $CONFIG_PROFILES_ARRAY >/dev/null + unset CONFIG_PROFILES_PATHS_ARRAY + declare -a CONFIG_PROFILES_PATHS_ARRAY=() >/dev/null + local $CONFIG_PROFILES_PATHS_ARRAY >/dev/null + + + # Refresh config file list and render menu + refresh_config_file_reference_array + render_config_menu + + + # Read Command Input + while : + do + + + # Declare, localize, and refresh arrays + unset CONFIG_PROFILES_ARRAY + declare -a CONFIG_PROFILES_ARRAY=() >/dev/null + local $CONFIG_PROFILES_ARRAY >/dev/null + unset CONFIG_PROFILES_PATHS_ARRAY + declare -a CONFIG_PROFILES_PATHS_ARRAY=() >/dev/null + local $CONFIG_PROFILES_PATHS_ARRAY >/dev/null + + + # Refresh config file list + refresh_config_file_reference_array + + + # Refresh config list array and read input + MENU_NAME=`echo -e "${COLOR_CYAN}[Config Menu]${COLOR_DEFAULT}"` + read -p "$MENU_NAME Choice? (RETURN main menu, or \"J\" config options menu): " CONFIG_MENU_INPUT; + + + # If "J" entered + if [[ $CONFIG_MENU_INPUT == "J" ]]; then + + # Refresh Array of Available Configs and render menu + printf "${COLOR_GREEN}[J] Config options menu.${COLOR_DEFAULT}\n" + echo "" + echo "" + refresh_config_file_reference_array + render_config_menu + + + # If no key entered + elif [[ -z $CONFIG_MENU_INPUT ]]; then + + printf "${COLOR_GREEN}[RETURN] Main menu.${COLOR_DEFAULT}\n" + echo "" + refresh_config_file_reference_array + break + + + # Evaluate Character entered + else + + refresh_config_file_reference_array + process_config_menu_selection $CONFIG_MENU_INPUT + + fi + + done + + +} +execute_config_routine + diff --git a/scripts/system/system-config_copy b/scripts/system/system-config_copy new file mode 100755 index 0000000..13173a8 --- /dev/null +++ b/scripts/system/system-config_copy @@ -0,0 +1,67 @@ +#!/bin/bash +# SYSTEM: CONFIG Copy + + +# If profiles exist +if (( ${#CONFIG_PROFILES_ARRAY[@]} )); + then + + # Read input + read -p "Profile to Copy?: " PROFILE_NAME_TO_COPY + + # Input validate (check if empty) + if [[ -z "$PROFILE_NAME_TO_COPY" ]]; then + error_message "[c] Config (copy): Input blank. No file identied for copying." + echo -e "" + + # Input validate (check for alphanum & "-_") + elif [[ "$PROFILE_NAME_TO_COPY" =~ [^a-zA-Z0-9_-] ]]; then + + # Validate response: Invalid characters + error_message "[c] Config (copy): Filenames are alphanum only (no spaces). Try again." + echo -e "" + + else + + # Check if in array of available files. If not, then create new. + if [[ "${CONFIG_PROFILES_ARRAY[*]}" =~ ${PROFILE_NAME_TO_COPY} ]]; then + + # Read Input + read -p "New name for Copy?: " PROFILE_COPY_NAME + + # Input validate (check if empty) + if [[ -z "$PROFILE_COPY_NAME" ]]; then + error_message "[c] Config (copy): No filename provide for new copy." + echo -e "" + + # Input validate (check for alphanum & "-_") + elif [[ "$PROFILE_COPY_NAME" =~ [^a-zA-Z0-9_-] ]]; then + error_message "[c] Config (copy): New filenames are alphanum only (no spaces). Try again." + echo -e "" + + else + + # Proceed with copy procedure + sudo cp "$CONFIG_DIRECTORY/config-$PROFILE_NAME_TO_COPY.json" "$CONFIG_DIRECTORY/config-$PROFILE_COPY_NAME.json" + confirmation_message "[c] Config (copy): Copy \"$PROFILE_COPY_NAME\" created from \"$PROFILE_NAME_TO_COPY\"." + echo -e "" + + fi + + else + error_message "[c] Config (copy): No file \"$PROFILE_NAME_TO_COPY\" exists to copy." + echo -e "" + + fi + + fi + + + # If no profiles exist + else + + error_message "[c] Config (copy): No config profiles to Copy. Create with \"new\"." + echo -e "" + +fi + diff --git a/scripts/system/system-config_delete b/scripts/system/system-config_delete new file mode 100755 index 0000000..3e465eb --- /dev/null +++ b/scripts/system/system-config_delete @@ -0,0 +1,97 @@ +#!/bin/bash +# SYSTEM: CONFIG Delete + + +# If profiles exist +if (( ${#CONFIG_PROFILES_ARRAY[@]} )); + then + + # Read input + read -p "Name of profile to Delete? (spaces allowable): " CONFIG_PROFILE_TO_DELETE + + # Input validate (check if empty) + if [[ -z "$CONFIG_PROFILE_TO_DELETE" ]] + then + error_message "[d] Config (delete): Input blank. No file identied for deletion deleted." + echo -e "" + + # Input validate (check for alphanum & "-_ ") + elif [[ "$CONFIG_PROFILE_TO_DELETE" =~ [^a-zA-Z0-9_-] ]] + then + error_message "[n] Config (delete): Filenames are alphanum only (spaces OK). Try again." + echo -e "" + + # Proceed with profile deletion + else + + + # Check if name exists, and if so mark flag + PROFILE_EXISTS_FLAG="false" + for FILE_TO_DELETE_NAME in "${CONFIG_PROFILES_ARRAY[@]}" + do + + if [[ "${FILE_TO_DELETE_NAME}" == ${CONFIG_PROFILE_TO_DELETE} ]] + then + PROFILE_EXISTS_FLAG="true" + fi + + done + + # Perform final action based on flag + if [[ $PROFILE_EXISTS_FLAG == "true" ]] + then + + # Reference $CURRENTLY_ACTIVE_CONFIG_FILE to see if deleting is current in use + CURRENTLY_ACTIVE_CONFIG_FILE=$(<"$CONFIG_FILE_IDENTIFIER_PATH") + if [[ ${CONFIG_PROFILE_TO_DELETE} == "$CURRENTLY_ACTIVE_CONFIG_FILE" ]] + + # If to delete is in use + then + + # Delete file (move to trash) + TIMESTAMP=$(date +%Y-%m-%d--%H-%M-%S) + mv "$CONFIG_DIRECTORY/config-$CONFIG_PROFILE_TO_DELETE.json" "$CONFIG_DIRECTORY/trash/config-$CONFIG_PROFILE_TO_DELETE.json_(DELETED_${TIMESTAMP})" + + # Delete config file identifier + truncate -s 0 "$CONFIG_FILE_IDENTIFIER_PATH" + + # Confirmation / Alert + warning_message "[WARNING]: Config file no longer specified. Please specify one to stream." + confirmation_message "[d] Config (delete): Deletion of \"$CONFIG_PROFILE_TO_DELETE\" completed (file moved to trash)." + echo -e "" + + + # If to delete is not in use + else + TIMESTAMP=$(date +%Y-%m-%d--%H-%M-%S) + mv "$CONFIG_DIRECTORY/config-$CONFIG_PROFILE_TO_DELETE.json" "$CONFIG_DIRECTORY/trash/config-$CONFIG_PROFILE_TO_DELETE.json_(DELETED_${TIMESTAMP})" + confirmation_message "[d] Config (delete): Deletion of \"$CONFIG_PROFILE_TO_DELETE\" completed (file moved to trash)." + echo -e "" + + fi + + # Unset currently actie config file variable + unset CURRENTLY_ACTIVE_CONFIG_FILE + + + # If profile doesn't exist + else + error_message "[d] Config (delete): No Config named \"$CONFIG_PROFILE_TO_DELETE\" to delete." + echo -e "" + + fi + + # Unset Flag + unset PROFILE_EXISTS_FLAG + + + fi + + + # If no profiles exist + else + + error_message "[d] Config (delete): No config profiles to delete. Create with \"new\"." + echo -e "" + +fi diff --git a/scripts/system/system-config_edit b/scripts/system/system-config_edit new file mode 100755 index 0000000..36a51c3 --- /dev/null +++ b/scripts/system/system-config_edit @@ -0,0 +1,54 @@ +#!/bin/bash +# SYSTEM: CONFIG Edit +# Edit System Configuration (.json) file + + +# If profiles exist +if (( ${#CONFIG_PROFILES_ARRAY[@]} )); + then + + # Read Input + read -p "Profile Name to Edit?: " CONFIG_PROFILE_TO_EDIT + + # Input validate (check if empty) + if [[ -z "$CONFIG_PROFILE_TO_EDIT" ]] + then + error_message "[e] Config (edit): Input blank. No file specified for editing." + echo -e "" + + # Input validate (check for alphanum & "-_ "), convert spaces to underscores + elif [[ "$CONFIG_PROFILE_TO_EDIT" =~ [^a-zA-Z0-9_-] ]] + then + error_message "[e] Config (edit): Files are alphanum characters only. No spaces." + + else + + # Precautionary Convert Spaces to Understores + UNDERSCORED_PROFILE_NAME_INPUT=$(convert_spaces_to_underscores "$CONFIG_PROFILE_TO_EDIT") + + # Check if in array of available files. If so, process + if [[ " ${CONFIG_PROFILES_ARRAY[*]} " =~ ${UNDERSCORED_PROFILE_NAME_INPUT} ]] + then + + + sudo nano "$CONFIG_DIRECTORY/config-$UNDERSCORED_PROFILE_NAME_INPUT.json" + TIMESTAMP=$(date +%Y-%m-%d" ("%H"h "%M"m "%S"s)") + sed -i "s/\/\/ Last modified.*/\/\/ Last modified: $TIMESTAMP/" "$CONFIG_DIRECTORY/config-$UNDERSCORED_PROFILE_NAME_INPUT.json" + confirmation_message "[e] Config (edit): Editing of \"$CONFIG_PROFILE_TO_EDIT\" completed." + echo -e "" + + + else + error_message "[e] Config (edit): No config \"$CONFIG_PROFILE_TO_EDIT\" to edit." + echo -e "" + fi + + fi + + # If no profiles exist + else + + error_message "[e] Config (edit): No config profiles to edit. Create with \"new\"." + echo -e "" + +fi diff --git a/scripts/system/system-config_empty_trash b/scripts/system/system-config_empty_trash new file mode 100755 index 0000000..7d375d1 --- /dev/null +++ b/scripts/system/system-config_empty_trash @@ -0,0 +1,29 @@ +#!/bin/bash +# SYSTEM: CONFIG Empty Trash (rm all deleted config profiles in trash can) + + +# Get number of files in folder +TRASH_FILES_COUNT=$(ls "$CONFIG_DIRECTORY/trash/" | wc -l) + + +# Delete Routine +if [[ "$TRASH_FILES_COUNT" == 0 ]] + + then + echo -e "[x] Empty Trash (deleted config files): Trash empty / no files to delete." + echo -e "" + +elif [[ "$TRASH_FILES_COUNT" == 1 ]] + + then + sudo rm -r "$CONFIG_DIRECTORY/trash/"* + confirmation_message "[x] Empty Trash (deleted config files): Completed. $TRASH_FILES_COUNT file deleted." + echo -e "" + +else + + sudo rm -r "$CONFIG_DIRECTORY/trash/"* + confirmation_message "[x] Empty Trash (deleted config files): Completed. $TRASH_FILES_COUNT files deleted." + echo -e "" + +fi diff --git a/scripts/system/system-config_new b/scripts/system/system-config_new new file mode 100755 index 0000000..49ee659 --- /dev/null +++ b/scripts/system/system-config_new @@ -0,0 +1,66 @@ +#!/bin/bash +# SYSTEM: CONFIG New +# Edit System Configuration (.json) file + + +# Read input +read -p "New Profile Name?: " NEW_PROFILE_NAME + +# Input validate (check if empty) +if [[ -z "$NEW_PROFILE_NAME" ]] + then + error_message "[n] Config (new): Input blank. No new file created." + echo -e "" + +# Input validate (check for alphanum & "-_ "), convert spaces to underscores +elif [[ "$NEW_PROFILE_NAME" =~ [^a-zA-Z0-9_-] ]] + then + error_message "[n] Config (new): Filenames are alphanum only (no spaces). No file created." + echo -e "" + +# Proceed with profile creation +else + + + # Check if name exists, and if so mark flag + PROFILE_EXISTS_FLAG="false" + for NEW_NAME_CHECK_LOOPED in "${CONFIG_PROFILES_ARRAY[@]}" + do + + if [[ "${NEW_NAME_CHECK_LOOPED}" == ${NEW_PROFILE_NAME} ]] + then + PROFILE_EXISTS_FLAG="true" + fi + + done + + # Perform final action based on flag + if [[ $PROFILE_EXISTS_FLAG == "true" ]] + + + # If profile exists + then + error_message "[n] Config (new): config profile named \"$NEW_PROFILE_NAME\" already exist." + echo -e"" + + # If profile doesn't exist + else + sudo cp "$CONFIG_TEMPLATE_DIRECTORY/config-sample.json" "$CONFIG_DIRECTORY/config-$NEW_PROFILE_NAME.json" + TIMESTAMP=$(date +%Y-%m-%d" ("%H"h "%M"m "%S"s)") + sed -i "s/%%%%config_name%%%%/$NEW_PROFILE_NAME/" "$CONFIG_DIRECTORY/config-$NEW_PROFILE_NAME.json" + sed -i "s/%%%%creation_date%%%%/$TIMESTAMP/" "$CONFIG_DIRECTORY/config-$NEW_PROFILE_NAME.json" + sed -i "s/%%%%last_modified%%%%/$TIMESTAMP/" "$CONFIG_DIRECTORY/config-$NEW_PROFILE_NAME.json" + confirmation_message "[n] Config (new): Blank config profile \"$NEW_PROFILE_NAME\" created." + echo -e "" + + fi + + # Unset Flag + unset PROFILE_EXISTS_FLAG + + +fi + + + + diff --git a/scripts/system/system-config_rename b/scripts/system/system-config_rename new file mode 100755 index 0000000..da67aaa --- /dev/null +++ b/scripts/system/system-config_rename @@ -0,0 +1,108 @@ +#!/bin/bash +# SYSTEM: CONFIG Rename + + +# If profiles exist +if (( ${#CONFIG_PROFILES_ARRAY[@]} )); + + # Main Rename Routine + then + + # Read input + read -p "Profile to Rename?: " PROFILE_TO_RENAME + + # Input validate (check if empty) + if [[ -z "$PROFILE_TO_RENAME" ]]; then + error_message "[r] Config (rename): Input blank. No file identied for renaming." + echo -e "" + + # Input validate (check for alphanum & "-_") + elif [[ "$PROFILE_TO_RENAME" =~ [^a-zA-Z0-9_-] ]]; then + error_message "[r] Config (rename): Filenames are alphanum only (no spaces). Try again." + echo -e "" + + else + + # Check if file exists + if [[ "${CONFIG_PROFILES_ARRAY[*]}" =~ ${PROFILE_TO_RENAME} ]]; then + + # Read input + read -p "New name for file?: " PROFILE_NEW_NAME + + # Input Validate (check if empty) + if [[ -z "$PROFILE_NEW_NAME" ]]; then + error_message "[r] Config (rename): New file name is blank." + echo -e "" + + # Input validate (check for alphanum & "-_") + elif [[ "$PROFILE_NEW_NAME" =~ [^a-zA-Z0-9_-] ]]; then + + error_message "[r] Config (rename): Filenames are alphanum only (no spaces). Try again." + echo -e "" + + else + + # Input validate (check for alphanum & "-_") + if [[ "${CONFIG_PROFILES_ARRAY[*]}" =~ ${PROFILE_NEW_NAME} ]]; then + error_message "[r] Config (rename): New name for file already exists." + echo -e "" + + # Renaming routine + else + + # Get name of current config + CURRENTLY_ACTIVE_CONFIG_FILE=$(<"$CONFIG_FILE_IDENTIFIER_PATH") + + if [[ "$CURRENTLY_ACTIVE_CONFIG_FILE" == "$PROFILE_TO_RENAME" ]]; + + # If profile being renamed is the currently used profile + then + + # Rename/mv file and change internal name + sudo mv "$CONFIG_DIRECTORY/config-$PROFILE_TO_RENAME.json" "$CONFIG_DIRECTORY/config-$PROFILE_NEW_NAME.json" + sed -i "s/\/\/ Config name.*/\/\/ Config name: $PROFILE_NEW_NAME/" "$CONFIG_DIRECTORY/config-$PROFILE_NEW_NAME.json" + + # Delete config file identifier contents and push new name + truncate -s 0 "$CONFIG_FILE_IDENTIFIER_PATH" + echo "$PROFILE_NEW_NAME" >> $CONFIG_FILE_IDENTIFIER_PATH + + # Confirm + confirmation_message "[r] Config (rename): Config file \"$PROFILE_TO_RENAME\" renamed to \"$PROFILE_NEW_NAME\"." + echo -e "" + + + # If profile being renamed is NOT the currently used profile + else + + # Rename/mv file and change internal name + sudo mv "$CONFIG_DIRECTORY/config-$PROFILE_TO_RENAME.json" "$CONFIG_DIRECTORY/config-$PROFILE_NEW_NAME.json" + sed -i "s/\/\/ Config name.*/\/\/ Config name: $PROFILE_NEW_NAME/" "$CONFIG_DIRECTORY/config-$PROFILE_NEW_NAME.json" + + # Confirm + confirmation_message "[r] Config (rename): Config file \"$PROFILE_TO_RENAME\" renamed to \"$PROFILE_NEW_NAME\"." + echo -e "" + + + fi + + fi + + fi + + + else + + error_message "[r] Config (Rename): No file named \"$PROFILE_TO_RENAME\" to rename." + echo -e "" + + fi + + fi + + + # No profiles exist + else + error_message "[r] Config (rename): No config profiles to rename. Create with \"new\"." + echo -e "" + +fi diff --git a/scripts/system/system-config_use b/scripts/system/system-config_use new file mode 100755 index 0000000..5dc61b4 --- /dev/null +++ b/scripts/system/system-config_use @@ -0,0 +1,46 @@ +#!/bin/bash +# SYSTEM: CONFIG Use + + +# If profiles exist +if (( ${#CONFIG_PROFILES_ARRAY[@]} )); + + # Main Use Routine + then + + # Read input + read -p "Profile to use?: " PROFILE_NAME_TO_USE + + # Check if empty + if [[ -z $PROFILE_NAME_TO_USE ]]; then + error_message "[u] Config (use): No filename entered." + echo -e "" + + # Validate: If input not alphanum/underscore + elif [[ "$PROFILE_NAME_TO_USE" =~ [^a-zA-Z0-9_-] ]]; then + error_message "[u] Config (use): Filename must be alphanum or underscored." + echo -e "" + + # Check if in array + elif [[ "${CONFIG_PROFILES_ARRAY[*]}" =~ ${PROFILE_NAME_TO_USE} ]]; then + + # Empty active config declaration file, and copy new name to it + sudo truncate -s 0 $CONFIG_FILE_IDENTIFIER_PATH + echo "$PROFILE_NAME_TO_USE" >> $CONFIG_FILE_IDENTIFIER_PATH + confirmation_message "[u] Config (use): Now using profile \"$PROFILE_NAME_TO_USE\"." + echo -e "" + + else + + error_message "[u] Config (use): No config named \"$PROFILE_NAME_TO_USE\" to use." + echo -e "" + + fi + + # No profiles exist + else + error_message "[u] Config (use): No config profiles to use. Create with \"new\"." + echo -e "" + + +fi diff --git a/scripts/system/system-declarations b/scripts/system/system-declarations new file mode 100755 index 0000000..1cea314 --- /dev/null +++ b/scripts/system/system-declarations @@ -0,0 +1,68 @@ +#!/bin/bash +# SYSTEM DECLARATIONS +# "Global" variables used in program (this document sourced in anonradio) + + + # PERMISSIONS OWNER (chown) + APPLICATION_FILE_OWNER="pi" + + # APPLICATION DIRECTORIES + DECLARATIONS_DIRECTORY="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + APPLICATION_ROOT=$(realpath "$DECLARATIONS_DIRECTORY/../..") + AUDIO_QUEUED_DIRECTORY="$APPLICATION_ROOT/audio_queued" + PLAYLIST_PATH="$APPLICATION_ROOT/playlists/playlist.m3u" + FLAGS_DIRECTORY="$APPLICATION_ROOT/.flags" + CONFIG_DIRECTORY="$APPLICATION_ROOT/config" + CONFIG_TEMPLATE_DIRECTORY="$APPLICATION_ROOT/var/templates" + CONFIG_FILE_IDENTIFIER_PATH="$APPLICATION_ROOT/var/active_config_name" + LOG_FOLDER_PATH="$APPLICATION_ROOT/var/log/" + + # DEPENDENCIES + DEPENDENCIES=("liquidsoap" "alsamixer" "ffprobe" "bc") + + # COLOR DECLARATIONS + COLOR_DEFAULT='\033[39m' + COLOR_BLACK='\033[30m' + COLOR_RED='\033[31m' + COLOR_GREEN='\033[32m' + COLOR_YELLOW='\033[33m' + COLOR_BLUE='\033[34m' + COLOR_MAGENTA='\033[35m' + COLOR_CYAN='\033[36m' + COLOR_GRAY='\033[90m' + COLOR_LIGHT_GRAY='\033[37m' + COLOR_LIGHT_RED='\033[91m' + COLOR_LIGHT_GREEN='\033[92m' + COLOR_LIGHT_YELLOW='\033[93m' + COLOR_LIGHT_BLUE='\033[94m' + COLOR_LIGHT_MAGENTA='\033[95m' + COLOR_LIGHT_CYAN='\033[96m' + COLOR_WHITE='\033[97m' + + # FONT STYLE + FONT_DEFAULT=$(tput sgr0) #Turn off all attributes + FONT_BOLD=$(tput bold) #Start bold text + FONT_UNDERLINE=$(tput smul) #Start underlined text + FONT_REMOVE_UNDERLINE=$(tput rmul) #End underlined text + FONT_REVERSE=$(tput rev) #Start reverse video + FONT_BLINK=$(tput blink) #Start blinking text + FONT_INVISIBLE=$(tput invis) #Start invisible text + FONT_STANDOUT=$(tput smso) #Start "standout" mode + FONT_REMOVE_STANDOUT=$(tput rmso) #End "standout" mode + FONT_STRIKETHROUGH='\e[9' #Start Strikethrough + FONT_REMOVE_STRIKETHROUGH='\e[0m' #End Strikethrough + FONT_UNDERLINE='\e[4' #Start Strikethrough + FONT_REMOVE_UNDERLINE='\e[0m' #End Strikethrough + SET_FOREGROUND_COLORS_=$(tput setaf) # Set foreground color + SET_BACKGROUND_COLORS=$(tput setab) # Set background color + + + # UNICODE BOX DRAWING AND SYMBOLS + SYMBOL_DOUBLE_DOT='\u205A' + SYMBOL_QUADRUPLE_DOT='\u205E' + SYMBOL_DOUBLE_PIPE='\u254E' + SYMBOL_RAQUO='\u00BB' + BORDER_VERTICAL='\u2502' + SYMBOL_HAZARD='\u25B2' + SYMBOL_CHECKMARK='\u2713' + diff --git a/scripts/system/system-functions b/scripts/system/system-functions new file mode 100755 index 0000000..8eac018 --- /dev/null +++ b/scripts/system/system-functions @@ -0,0 +1,216 @@ +#!/bin/bash +# Functions +# + + + +# +# FUNCTION: Git Keep (touch routine) +# Touch .gitkeep files to create folders where they might not exist +# +# +function git_keep_touch_routine() { + + sudo touch \ + "$APPLICATION_ROOT/audio_queued/.gitkeep" \ + "$APPLICATION_ROOT/config/.gitkeep" \ + "$APPLICATION_ROOT/config/trash/.gitkeep" \ + "$APPLICATION_ROOT/playlists/.gitkeep" \ + "$APPLICATION_ROOT/var/log/.gitkeep" \ + +} + + + +# +# FUNCTION: Verify Dependencies +# Check to make sure that all dependencies are installed, else quit +# +# +function check_for_missing_dependencies() { + + # Dependencies to check for ($DEPENDENCIES defined in system-declarations) + MISSING_DEPENDENCIES=0 + + # Iterate and check for missing + for DEPENDENCY_NAME in "${DEPENDENCIES[@]}"; do : + + # If missing, then flag as missing exists + if ! command -v "$DEPENDENCY_NAME" &> /dev/null; then + MISSING_DEPENDENCIES=1 + fi + + done + + # if missing exist, list and exit + if [[ $MISSING_DEPENDENCIES == 1 ]]; then + + echo -e "The following missing dependencies are required for soapdish (v${VERSION}):" + for DEPENDENCY_NAME in "${DEPENDENCIES[@]}"; do : + + if ! command -v "$DEPENDENCY_NAME" &> /dev/null; then + printf "%s$DEPENDENCY_NAME " + fi + + done + echo -e "\nPlease install and try again." + + # Exit + exit + + fi + +} + + + +# +# FUNCTION: Verify Config File Identifier Validity +# Check to make sure that all dependencies are installed, else quit +# +# +function verify_config_file_identifier_validity() { + + echo -e "Verifying config file identifier validity (WIP)" + + # Get value of identifier and act accordingly (if blank or not) + CURRENT_CONFIG_FILE_IDENTIFIER_VALUE=$(<$CONFIG_FILE_IDENTIFIER_PATH) + if [[ $CURRENT_CONFIG_FILE_IDENTIFIER_VALUE != "" ]] + + then + echo -e "Config File Identifier Value == $CURRENT_CONFIG_FILE_IDENTIFIER_VALUE" + echo -e "Here is where you compare flag to each config file" + echo -e "constuct array of all config names" + echo -e "cycle through to verify flag matches" + echo -e "if no match, then wipe flag" + echo -e "make sure flag in main menu updates AFTER you wipe flag" + echo -e "(run this function before anythign else runs)" + + fi + + +} + + +# +# FUNCTION: Render Horizontal Rule +# Renders an 80-character horizontal rule +# +# +function render_horizontal_rule() { + + # # HR style alternaties (uncomment desired style) + # HR_PIECE="\u2504" + # HR_PIECE="\u2508" + HR_PIECE="\u2500" + # HR_PIECE="–" + + # Render + for i in {1..80} + do + printf "$HR_PIECE" + done + echo "" + +} + + +# +# FUNCTION: Generate Random Hex Value +# Renders an a hex string of $1 character length +# +# +function generate_random_hex_value { + + HEX_NUMBER_COMPILED=$(tr -dc 'A-F0-9' < /dev/urandom | head -c$1) + echo "$HEX_NUMBER_COMPILED" + +} + + +# +# +# FUNCTION: Render Mini Horizontal Rule +# Renders an 20-character horizontal rule +# +# +function render_mini_horizontal_rule() { + + # # HR style alternaties (uncomment desired style) + # HR_PIECE="\u2504" + # HR_PIECE="\u2508" + HR_PIECE="\u2500" + # HR_PIECE="–" + + # Render + for i in {1..20} + do + printf "$HR_PIECE" + done + echo "" + +} + + +# +# +# FUNCTION: Reset Permissions +# Recursively resets permissions within application +# +# +function reset_permissions() { + + # Specify target directory ($DIR declared in system-declarations), and reset permissions + DIR=${APPLICATION_ROOT} + CURRENT_CHOWN_USER=$(whoami) + sudo chown -R "$CURRENT_CHOWN_USER" "$DIR" + sudo chmod 755 -R "$DIR" + +} + + +# +# +# FUNCTIONS: Alert Messages +# Styles input string according to message type (red:error, yellow:warning, green:alert) +# +# +function error_message() { + echo -e "${COLOR_RED}$1${COLOR_DEFAULT}" +} +function warning_message() { + echo -e "${COLOR_YELLOW}$1${COLOR_DEFAULT}" +} +function confirmation_message() { + echo -e "${COLOR_GREEN}$1${COLOR_DEFAULT}" +} + + +# +# +# FUNCTIONS: Encode URL +# Converts string to url-friendly (encoded) string +# +# +function url_encode_string () { + tab="`echo -en "\x9"`" + i="$@" + i=${i//%/%25} ; i=${i//' '/%20} ; i=${i//$tab/%09} + i=${i//!/%21} ; i=${i//'"'/%22} ; i=${i//#/%23} + i=${i//\$/%24} ; i=${i//\&/%26} ; i=${i//\'/%27} + i=${i//(/%28} ; i=${i//)/%29} ; i=${i//\*/%2a} + i=${i//+/%2b} ; i=${i//,/%2c} ; i=${i//-/%2d} + i=${i//\./%2e} ; i=${i//\//%2f} ; i=${i//:/%3a} + i=${i//;/%3b} ; i=${i///%3e} ; i=${i//\?/%3f} ; i=${i//@/%40} + i=${i//\[/%5b} ; i=${i//\\/%5c} ; i=${i//\]/%5d} + i=${i//\^/%5e} ; i=${i//_/%5f} ; i=${i//\`/%60} + i=${i//\{/%7b} ; i=${i//|/%7c} ; i=${i//\}/%7d} + i=${i//\~/%7e} + echo "$i" + i="" +} + + + + diff --git a/scripts/system/system-killall_and_restart b/scripts/system/system-killall_and_restart new file mode 100755 index 0000000..b7b306b --- /dev/null +++ b/scripts/system/system-killall_and_restart @@ -0,0 +1,44 @@ +#!/bin/bash +# SYSTEM: KILL STREAM PROCESSES +# Kill all processes with name of liquidsoap + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Kill Show +sudo pkill "liquidsoap"; + + +# Wait and restart liquidsoap +sleep 2 + + +# Attempt to restart liquidsoap as a service (if possible) +if RESULT=$(sudo systemctl restart liquidsoap 2>&1) + + then + STDOUT="$RESULT" + confirmation_message "[K] Killall and Restart liquidsoap: executed"; + echo ""; + + else + # Error code (not used) + RC=$? + # echo "code $RC" + # Error message (not used) + STDERR=$RESULT + # echo "THIS: $STDERR ok?" + + echo "Liquidsoap killed, not restarted as a service (liquidsoap not a service)." + confirmation_message "[K] Killall and Restart liquidsoap: Liquidsoap killed."; + echo ""; + + + +fi + + +# Echo result diff --git a/scripts/system/system-update_hardware_audio_frame_size b/scripts/system/system-update_hardware_audio_frame_size new file mode 100755 index 0000000..f2c478d --- /dev/null +++ b/scripts/system/system-update_hardware_audio_frame_size @@ -0,0 +1,92 @@ +#!/bin/bash +# SYSTEM: UPDATE AUDIO FRAME SIZE +# Run debug then search log for instance of frame size. Assgn to variable then write to anonradio-config.json + + +# Includes and Declarations (global variables, formatting, and functions) +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/scripts/system/system-declarations" + + +# Kill process (as a safeguard) +sudo pkill "liquidsoap"; + + +# Get active config name, construct path to streamable config file (for validation) +CURRENTLY_ACTIVE_CONFIG_NAME=$(<"$CONFIG_FILE_IDENTIFIER_PATH") +STREAMABLE_CONFIG_FILE_PATH="$CONFIG_DIRECTORY/config-$CURRENTLY_ACTIVE_CONFIG_NAME.json" + + +# Check if config file exists +if [[ -f "$STREAMABLE_CONFIG_FILE_PATH" ]]; + + # If exists + then + + # Set up timestamp formatting, path, then create file and set permission for coming log-dump + TIMESTAMP_FILENAME="log-$(date +%s)" + CURRENT_CHOWN_USER=$(whoami) + FULL_LOG_FILE_PATH="$LOG_FOLDER_PATH/buffer_evaluation_$TIMESTAMP_FILENAME" + sudo touch "$FULL_LOG_FILE_PATH" + sudo chmod 755 "$FULL_LOG_FILE_PATH" + sudo chown "$CURRENT_CHOWN_USER" "$FULL_LOG_FILE_PATH" + + + # Log color formatting of log, then export log to specified log file (butter_evaluation_log-[timestamp]) + printf "${COLOR_GRAY}"; + liquidsoap -v --debug 'input.alsa(bufferize=false)' >> $FULL_LOG_FILE_PATH & sleep 3; + sudo pkill "liquidsoap"; + sleep 2 + printf "${COLOR_DEFAULT}" + + + # Notification of command edecution + confirmation_message "[H] Review Hardware Audio Frame Size:" + + + # sed to strip away just want + # Example log line (for reference): + # 2019/11/09 19:11:09 [frame:3] Frame size must be a multiple of 1764 ticks = 1764 audio samples = 1 video samples. + BUFFER_RECOMMENDED=$(sed -e s/"^.*ticks = "// -e s/" audio samples.*$"// <<< $(sed -n "s/Frame size must be a multiple of//p" $FULL_LOG_FILE_PATH)) + BUFFER_DECLARED=$(sed -e s/'[ \t]*\"\"\:\"'// -e s/'".*'// <<< $(sed -n "s/"hardware_audio_frame_size"//p" $STREAMABLE_CONFIG_FILE_PATH)) + + + # Check if declared AFS buffer size is a multiple of recommended AFS buffer (using bc) + # Then, if checked result has 8 decimal places of zeroes, then echo appropriate notice + BUFFER_MULTIPLE_CHECK=`echo "scale=8; $BUFFER_DECLARED/$BUFFER_RECOMMENDED" | bc -l` + if [[ $BUFFER_MULTIPLE_CHECK == *".00000000"* ]]; then + NOTICE="${COLOR_GREEN}${SYMBOL_CHECKMARK}${COLOR_DEFAULT} ${FONT_BOLD}Config settings OK! (config AFS is multiple of recommended AFS)${FONT_DEFAULT}" + else + NOTICE="${FONT_BOLD}${COLOR_YELLOW}${SYMBOL_HAZARD}${COLOR_DEFAULT} Warning: Config AFS is not a multiple of recommended AFS${FONT_DEFAULT}" + fi + + + # Output / Reporting: + printf "\n" + printf "\n" + printf "${FONT_BOLD} HARDWARE, AUDIO FRAME SIZE (AFS):${FONT_DEFAULT}\n" + printf "\n" + # printf " • Default system frame size - $BUFFER_OBSERVED\n" + printf " • Recommended frame size - $BUFFER_RECOMMENDED\n" + printf " • Your current config's frame size - $BUFFER_DECLARED\n" + printf "\n" + printf " $NOTICE\n" + printf "\n" + printf "\n" + printf "\n" + + + # Unset Variables + IDENTIFYING_STRING="" + BUFFER_LINE="" + EVALUATED_SAMPLES="" + BUFFER_OBSERVED="" + NOTICE="" + + # If no config file exists + else + error_message "[H] Review Hardware Audio Frame Size: No config file to reference. Please specify." + echo "" + +fi + diff --git a/soapdish.sh b/soapdish.sh new file mode 100755 index 0000000..54355c6 --- /dev/null +++ b/soapdish.sh @@ -0,0 +1,236 @@ +#! /bin/bash +# TILDERADIO MASTER EXECUTABLE - master executable for tilderadio +# Top level runtime of tilderadio program + + +# Get Source Dir, and then source Core Declarations file +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +source "${DIR}/scripts/system/system-declarations" + + +# Includes and Declarations (global variables, formatting and functions) +source "${APPLICATION_ROOT}/scripts/system/system-declarations" +source "${APPLICATION_ROOT}/scripts/system/system-functions" +source "${APPLICATION_ROOT}/var/version" + + +# Render Main Menu +function render_main_menu { + + # Check to make sure active config file idenifier is valid. If not, then empty identifier. + CURRENT_CONFIG_NAME=$(<$CONFIG_FILE_IDENTIFIER_PATH) + CURRENT_CONFIG_FILE_CLAIMED_PATH="$CONFIG_DIRECTORY/config-${CURRENT_CONFIG_NAME}.json" + if ! [[ -f "$CURRENT_CONFIG_FILE_CLAIMED_PATH" ]]; then + + truncate -s 0 "$CONFIG_FILE_IDENTIFIER_PATH" + CURRENT_CONFIG_NAME=$(<$CONFIG_FILE_IDENTIFIER_PATH) + + fi + + # Prepare Pretty Header + APP_AND_VERSION_PREFIX="soapdish - v${VERSION}" + APP_AND_VERSION_CHARCOUNT=${#APP_AND_VERSION_PREFIX} + + # Render Main Menu - Appropriate pretty menuheading (check if a config is specified) + if [[ -n "$CURRENT_CONFIG_NAME" ]]; then + + # If config file is set, prep variables + CURRENT_CONFIG_NAME_AND_PREFIX="[Using profile: \"${CURRENT_CONFIG_NAME}\"]" + CURRENT_CONFIG_NAME_CHARCOUNT=${#CURRENT_CONFIG_NAME_AND_PREFIX} + MENU_HEADER_SPACING_COUNT=$(( "80" - "$CURRENT_CONFIG_NAME_CHARCOUNT" - "$APP_AND_VERSION_CHARCOUNT" )) + MENU_HEADER_SPACING="" + for (( i = 0; i < MENU_HEADER_SPACING_COUNT; i++ )); do + MENU_HEADER_SPACING="${MENU_HEADER_SPACING} " + done + + # Render + echo -e ""; + echo -e ""; + echo -e "${FONT_BOLD}${APP_AND_VERSION_PREFIX}${MENU_HEADER_SPACING}${CURRENT_CONFIG_NAME_AND_PREFIX}${FONT_DEFAULT}" + render_horizontal_rule + echo ""; + + else + + # If config file is NOT set, prep variables + CURRENT_CONFIG_NAME_AND_PREFIX="[No config specified!]" + CURRENT_CONFIG_NAME_CHARCOUNT=${#CURRENT_CONFIG_NAME_AND_PREFIX} + MENU_HEADER_SPACING_COUNT=$(( "80" - "$CURRENT_CONFIG_NAME_CHARCOUNT" - "$APP_AND_VERSION_CHARCOUNT" )) + MENU_HEADER_SPACING="" + for (( i = 0; i < MENU_HEADER_SPACING_COUNT; i++ )); do + MENU_HEADER_SPACING="${MENU_HEADER_SPACING} " + done + + # Render + echo -e ""; + echo -e ""; + echo -e "${FONT_BOLD}${APP_AND_VERSION_PREFIX}${MENU_HEADER_SPACING}${COLOR_RED}${CURRENT_CONFIG_NAME_AND_PREFIX}${FONT_DEFAULT}" + render_horizontal_rule + echo ""; + + fi + + # Render Main Menu - Streaming Commands + echo -e " ${FONT_BOLD}${COLOR_DARK_GRAY}STREAM ALSA:${COLOR_DEFAULT}${FONT_DEFAULT} "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}L${FONT_DEFAULT}${COLOR_DEFAULT} - stream ALSA/live (to Main) "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}l${FONT_DEFAULT}${COLOR_DEFAULT} - stream ALSA/live (to Testing) "; + echo -e ""; + + + # Render Main Menu - Broadcast Commands + echo -e " ${FONT_BOLD}${COLOR_DARK_GRAY}STREAM FILES:${COLOR_DEFAULT}${FONT_DEFAULT} "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}F${FONT_DEFAULT}${COLOR_DEFAULT} - stream files (to Main) "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}f${FONT_DEFAULT}${COLOR_DEFAULT} - stream files (to Testing) "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}V${FONT_DEFAULT}${COLOR_DEFAULT} - playlist view "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}C${FONT_DEFAULT}${COLOR_DEFAULT} - playlist create "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}E${FONT_DEFAULT}${COLOR_DEFAULT} - playlist edit "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}Q${FONT_DEFAULT}${COLOR_DEFAULT} - queued folder contents "; + echo -e ""; + + # Render Main Menu - Cron + echo -e " ${FONT_BOLD}${COLOR_DARK_GRAY}CRON${COLOR_DEFAULT}${FONT_DEFAULT} "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}S${FONT_DEFAULT}${COLOR_DEFAULT} - cron status "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}A${FONT_DEFAULT}${COLOR_DEFAULT} - cron activate "; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}D${FONT_DEFAULT}${COLOR_DEFAULT} - cron deactivate "; + echo -e ""; + + # Render Main Menu - System + echo -e " ${COLOR_DARK_GRAY}${FONT_BOLD}SYSTEM${FONT_DEFAULT}${COLOR_DEFAULT}"; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}K${FONT_DEFAULT}${COLOR_DEFAULT} - killall and restart liquidsoap"; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}J${FONT_DEFAULT}${COLOR_DEFAULT} - config profile options"; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}H${FONT_DEFAULT}${COLOR_DEFAULT} - review hardware audio frame size"; + echo -e " ${COLOR_LIGHT_MAGENTA}${FONT_BOLD}M${FONT_DEFAULT}${COLOR_DEFAULT} - alsa mixer"; + echo -e ""; + echo -e ""; + echo -e ""; + +} + + +# Process input variable +function process_input_variable() { + + # Case Switch + case $INPUTCOMMAND in + + # SHOW COMMANDS: + + # LIVE-STREAMING + + # (L) ---- main, stream live/alsa + L) source "${APPLICATION_ROOT}/scripts/streaming/main/main-stream_live_alsa" ;; + # (l) ---- testing, stream live/alsa + l) source "${APPLICATION_ROOT}/scripts/streaming/testing/testing-stream_live_alsa" ;; + + + # FILE-STREAMING + + # (F) ---- main, stream files + F) source "${APPLICATION_ROOT}/scripts/streaming/main/main-stream_files" ;; + # (f) ---- testing, stream files + f) source "${APPLICATION_ROOT}/scripts/streaming/testing/testing-stream_files" ;; + # (V) ---- main, playlist view + V) source "${APPLICATION_ROOT}/scripts/playlist/playlist_view" ;; + # (C) ---- main, playlist create + C) source "${APPLICATION_ROOT}/scripts/playlist/playlist_create" ;; + # (E) ---- main, playlist edit + E) source "${APPLICATION_ROOT}/scripts/playlist/playlist_edit" ;; + # (Q) ---- main, queued folder contents + Q) source "${APPLICATION_ROOT}/scripts/queued/queued_folder_contents" ;; + + # CRON + + # (S) ---- cron status + S) source "${APPLICATION_ROOT}/scripts/cron/main-cron_status" ;; + # (A) ---- cron activate + A) source "${APPLICATION_ROOT}/scripts/cron/main-cron_activate" ;; + # (D) ---- cron deactivate + D) source "${APPLICATION_ROOT}/scripts/cron/main-cron_deactivate" ;; + + + # SYSTEM COMMANDS + + # (K) ---- killall and restart + K) source "${APPLICATION_ROOT}/scripts/system/system-killall_and_restart" ;; + # (J) ---- edit config + J) source "${APPLICATION_ROOT}/scripts/system/system-config" ;; + # (H) ---- review hardware audio frame size + H) source "${APPLICATION_ROOT}/scripts/system/system-update_hardware_audio_frame_size" ;; + # (M) ---- alsa mixer + M) source "${APPLICATION_ROOT}/scripts/system/system-alsa_mixer" ;; + + + # Fallback if command not recognized + *) + printf "${COLOR_RED}[-] Command not recognized.${COLOR_DEFAULT}\n" + echo "" + ;; + + esac + +} + + +# Main Program Function +function execute_program { + + + # Check for missing dependencies (if missing, exits) + check_for_missing_dependencies + + # Git touch routine to add .gitkeep and create any missing folders + git_keep_touch_routine + + # Read Command Input + while : + do + + # Render Main Menu + echo "" + render_main_menu + + + # Read main application input command + MENU_NAME=$(echo -e "${COLOR_LIGHT_MAGENTA}[Main Menu]${COLOR_DEFAULT}") + read -p "$MENU_NAME Choice? (\"quit\" to exit, RETURN for menu): " INPUTCOMMAND; + + # If "quit" entered + if [[ $INPUTCOMMAND == "quit" ]]; then + + + # Kill, just in case + sudo pkill "liquidsoap"; + + # Wait and restart liquidsoap, just in case + sleep 2 + sudo systemctl restart liquidsoap + + # Notify of exit + printf "${COLOR_GREEN}[quit] Exiting...${COLOR_DEFAULT}\n" + echo "" + echo "" + break + + # If no key entered + elif [[ -z $INPUTCOMMAND ]]; then + printf "${COLOR_GREEN}[RETURN] Main menu.${COLOR_DEFAULT}\n" + echo "" + render_main_menu + + # Evaluate Character entered + else + process_input_variable + + fi + + done + +} + + +# Master execution of program +execute_program + + +# Closing change of permissions on execution of script +reset_permissions diff --git a/var/active_config_name b/var/active_config_name new file mode 100755 index 0000000..e69de29 diff --git a/var/log/.gitkeep b/var/log/.gitkeep new file mode 100755 index 0000000..e69de29 diff --git a/var/main-cron_gateway b/var/main-cron_gateway new file mode 100755 index 0000000..e69de29 diff --git a/var/templates/config-sample.json b/var/templates/config-sample.json new file mode 100755 index 0000000..486f755 --- /dev/null +++ b/var/templates/config-sample.json @@ -0,0 +1,36 @@ +{ + +// CONFIG SETTINGS: +// Config Name: "%%%%config_name%%%%" +// Creation date: %%%%creation_date%%%% +// Last modified: %%%%last_modified%%%% + + + // Streaming Configuration Settings ("Main" stream) + "main_host":"", + "main_port":"", + "main_user":"", + "main_password":"", + "main_mount":"", + "main_crontab_time":"", + "main_metadata_artist":"", + "main_metadata_title":"", + + // Streaming Configuration Settings ("Testing" stream) + "testing_host":"", + "testing_port":"", + "testing_user":"", + "testing_password":"", + "testing_mount":"", + "testing_metadata_artist":"", + "testing_metadata_title":"", + + // Playlist Configuration + "playlist_url":"", + "randomize_playlist_files":"false", + + // System Configuration Settings + "hardware_audio_frame_size":"3528", + +} + diff --git a/var/version b/var/version new file mode 100755 index 0000000..09c428c --- /dev/null +++ b/var/version @@ -0,0 +1,3 @@ +# Application Version +# Example: 1.2.1 +VERSION="4.3.2"