diff --git a/base/base-config.tar.gz b/base/base-config.tar.gz deleted file mode 100644 index 7eb8e61..0000000 Binary files a/base/base-config.tar.gz and /dev/null differ diff --git a/docker-compose.custom.yaml b/docker-compose.custom.yaml index 236a651..79246e8 100644 --- a/docker-compose.custom.yaml +++ b/docker-compose.custom.yaml @@ -1,4 +1,2 @@ -version: "3" - # services: # Add your custom services here! diff --git a/docker-compose.example.yaml b/docker-compose.example.yaml index c43b878..105ae8a 100644 --- a/docker-compose.example.yaml +++ b/docker-compose.example.yaml @@ -1,5 +1,3 @@ -version: "3" - services: # is used to serve your media to the client devices : @@ -11,8 +9,8 @@ services: - PGID=${PGID} - VERSION=docker volumes: - - ${MEDIA_DIRECTORY}/movies:/data/movies - - ${MEDIA_DIRECTORY}/tvshows:/data/tvshows + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/${MEDIA_SERVICE}:/config ports: # plex - 8096:8096 # plex @@ -20,18 +18,36 @@ services: # qBitorrent is used to download torrents qbittorrent: - image: lscr.io/linuxserver/qbittorrent:4.6.0 + image: lscr.io/linuxserver/qbittorrent container_name: qbittorrent environment: - PUID=${PUID} - PGID=${PGID} - - WEBUI_PORT=8080 + - WEBUI_PORT=8081 volumes: - - ${MEDIA_DIRECTORY}/downloads:/downloads + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/qbittorrent:/config restart: unless-stopped ports: # qbittorrent - - 8080:8080 # qbittorrent + - 8081:8081 # qbittorrent + #network_mode: "service:gluetun" + + # SABnzbd is used to download from usenet + sabnzbd: + image: lscr.io/linuxserver/sabnzbd:latest + container_name: sabnzbd + environment: + - PUID=${PUID} + - PGID=${PGID} + - TZ=America/Montevideo + volumes: + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data + - ${INSTALL_DIRECTORY}/config/sabnzbd:/config + ports: # sabnzbd + - 8080:8080 # sabnzbd + restart: unless-stopped #network_mode: "service:gluetun" # Sonarr is used to query, add downloads to the download queue and index TV shows @@ -43,8 +59,8 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: - - ${MEDIA_DIRECTORY}/tvshows:/tv - - ${MEDIA_DIRECTORY}/downloads:/downloads + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/sonarr:/config ports: - 8989:8989 @@ -59,8 +75,8 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: - - ${MEDIA_DIRECTORY}/movies:/movies - - ${MEDIA_DIRECTORY}/downloads:/downloads + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/radarr:/config ports: - 7878:7878 @@ -75,8 +91,8 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: - - ${MEDIA_DIRECTORY}/music:/music - - ${MEDIA_DIRECTORY}/downloads:/downloads + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/lidarr:/config ports: - 8686:8686 @@ -91,8 +107,8 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: - - ${MEDIA_DIRECTORY}/books:/books - - ${MEDIA_DIRECTORY}/downloads:/downloads + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/readarr:/config ports: - 8787:8787 @@ -107,8 +123,8 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: - - ${MEDIA_DIRECTORY}/movies:/movies - - ${MEDIA_DIRECTORY}/tvshows:/tv + - /etc/localtime:/etc/localtime:ro + - ${MEDIA_DIRECTORY}:/data - ${INSTALL_DIRECTORY}/config/bazarr:/config ports: - 6767:6767 @@ -123,6 +139,7 @@ services: - PUID=${PUID} - PGID=${PGID} volumes: + - /etc/localtime:/etc/localtime:ro - ${INSTALL_DIRECTORY}/config/prowlarr:/config ports: - 9696:9696 @@ -140,15 +157,17 @@ services: - 8888:8888/tcp # HTTP proxy - 8388:8388/tcp # Shadowsocks - 8388:8388/udp # Shadowsocks + - 8003:8000/tcp # Admin #- 8080:8080/tcp # gluetun - volumes: - - ${INSTALL_DIRECTORY}/config/gluetun:/config + #- 8081:8081/tcp # gluetun environment: - VPN_SERVICE_PROVIDER=${VPN_SERVICE} - VPN_TYPE=openvpn - OPENVPN_USER=${VPN_USER} - OPENVPN_PASSWORD=${VPN_PASSWORD} - OPENVPN_CIPHERS=AES-256-GCM + - PORT_FORWARD_ONLY=on + - VPN_PORT_FORWARDING=on restart: unless-stopped # Portainer helps debugging and monitors the containers diff --git a/docs.org b/docs.org index 5c4d0ec..0e38d47 100644 --- a/docs.org +++ b/docs.org @@ -6,37 +6,24 @@ :PROPERTIES: :ID: faf95c8a-9133-4072-8544-0ef456a67611 :END: - - [[#welcome-message][Welcome message]] +- [[#constants-and-configuration][Constants and Configuration]] - [[#functions][Functions]] - [[#message-formatting][Message formatting]] - - [[#check-the-dependencies][Check the dependencies]] - - [[#running-services-location][Running services location]] -- [[#verify-all-the-dependencies][Verify all the dependencies]] -- [[#gather-all-the-required-information][Gather all the required information]] - - [[#checking-install-location][Checking install location]] - - [[#setting-the-correct-user][Setting the correct user]] - - [[#media-directory][Media directory]] - - [[#setting-perferred-media-service][Setting perferred media service]] - - [[#setting-the-vpn][Setting the VPN]] -- [[#installing-yams][Installing YAMS]] - - [[#copy-the-docker-compose-file-to-the-install-location][Copy the docker-compose file to the install location]] - - [[#set-puid-pgid-media-folder-media-service-config-folder-and-vpn-on-the-yams-scripts][Set PUID, PGID, Media Folder, Media Service, Config folder and VPN on the YAMS scripts]] - - [[#set-the-configuration-for-the-yams-binary][Set the configuration for the YAMS binary]] - - [[#success-message][Success message!]] -- [[#final-steps][Final steps]] - - [[#install-the-yams-cli][Install the YAMS CLI]] - - [[#set-the-correct-permissions-to-the-media-and-install-directories][Set the correct permissions to the media and install directories]] - - [[#create-the-config-directory][Create the config directory]] -- [[#display-closing-message][Display closing message]] + - [[#directory-handling][Directory Handling]] + - [[#check-dependencies][Check Dependencies]] + - [[#service-configuration][Service Configuration]] + - [[#file-operations][File Operations]] +- [[#script-execution][Script Execution]] + - [[#verify-prerequisites][Verify Prerequisites]] + - [[#installation-process][Installation Process]] +- [[#display-closing-message][Display Closing Message]] * Welcome message :PROPERTIES: :ID: 525c03eb-cab9-44f8-8cc5-e5ec9035a938 :END: -This is just a welcome message for the script - #+begin_src bash #!/bin/bash set -euo pipefail @@ -64,268 +51,238 @@ echo "====================================================" echo "" #+end_src +* Constants and Configuration +:PROPERTIES: +:ID: new-constants-section +:END: + +#+begin_src bash +# Constants +readonly DEFAULT_INSTALL_DIR="/opt/yams" +readonly DEFAULT_MEDIA_DIR="/srv/media" +readonly SUPPORTED_MEDIA_SERVICES=("jellyfin" "emby" "plex") +readonly DEFAULT_MEDIA_SERVICE="jellyfin" +readonly DEFAULT_VPN_SERVICE="protonvpn" +readonly MEDIA_SUBDIRS=("tvshows" "movies" "music" "books" "downloads" "blackhole") + +# Color codes +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Dependencies +readonly REQUIRED_COMMANDS=("curl" "sed" "awk") +#+end_src + * Functions :PROPERTIES: :ID: 111a7df4-08f5-4e6c-a799-dd822c5d030e :END: -To make development easier, we declare some functions that are going to be used a lot later - ** Message formatting :PROPERTIES: :ID: 61387bd4-2ecf-44fe-ac69-dc6347c0d1b8 :END: -Both of these functions format the message in different colors, depending on what the message means -*** Success -:PROPERTIES: -:ID: ec8f113c-43f9-4585-a1b5-8c7ec4e84bb2 -:END: #+begin_src bash -send_success_message() { - echo -e $(printf "\e[32m$1\e[0m") +log_success() { + echo -e "${GREEN}$1${NC}" +} + +log_error() { + echo -e "${RED}$1${NC}" >&2 + exit 1 +} + +log_warning() { + echo -e "${YELLOW}$1${NC}" +} + +log_info() { + echo "$1" } #+end_src -*** Error +** Directory Handling :PROPERTIES: -:ID: 1a6cd951-c9ce-46fc-8953-f5e206f7cd23 +:ID: new-directory-section :END: -Error is basically the same as before, but it ~exit 255~ to finish the execution. - #+begin_src bash -send_error_message() { - echo -e $(printf "\e[31m$1\e[0m") - exit 255 +create_and_verify_directory() { + local dir="$1" + local dir_type="$2" + + if [ ! -d "$dir" ]; then + echo "The directory \"$dir\" does not exist. Attempting to create..." + if mkdir -p "$dir"; then + log_success "Directory $dir created ✅" + else + log_error "Failed to create $dir_type directory at \"$dir\". Check permissions ❌" + fi + fi + + if [ ! -w "$dir" ] || [ ! -r "$dir" ]; then + log_error "Directory \"$dir\" is not writable or readable. Check permissions ❌" + fi +} + +setup_directory_structure() { + local media_dir="$1" + + create_and_verify_directory "$media_dir" "media" + + for subdir in "${MEDIA_SUBDIRS[@]}"; do + create_and_verify_directory "$media_dir/$subdir" "media subdirectory" + done +} + +verify_user_permissions() { + local username="$1" + local directory="$2" + + if ! id -u "$username" &>/dev/null; then + log_error "User \"$username\" doesn't exist!" + fi + + if ! sudo -u "$username" test -w "$directory"; then + log_error "User \"$username\" doesn't have write permissions to \"$directory\"" + fi } #+end_src -** Check the dependencies +** Check Dependencies :PROPERTIES: :ID: e7d01eeb-c7ef-42ff-b60d-010be30bc6a8 :END: -This function verifies that the dependencies are installed. ~Docker~ and ~Docker Compose~ are required -for YAMS to work. - #+begin_src bash check_dependencies() { - if command -v docker &> /dev/null; then - send_success_message "docker exists ✅ " - if docker compose version &> /dev/null; then - send_success_message "docker compose exists ✅ " + local missing_packages=() + local install_cmd="" + + # Check for required commands and collect missing ones + for pkg in "${REQUIRED_COMMANDS[@]}"; do + if ! command -v "$pkg" &> /dev/null; then + missing_packages+=("$pkg") else - echo -e $(printf "\e[31m ⚠️ docker compose not found! ⚠️\e[0m") - read -p "Do you want YAMS to install Docker Compose? IT ONLY WORKS ON DEBIAN AND UBUNTU! [y/N]: " install_docker - install_docker=${install_docker:-"n"} - - if [ "$install_docker" == "y" ]; then - bash ./docker.sh - else - send_error_message "Install Docker Compose and come back later!" - fi + log_success "$pkg exists ✅" fi - else - echo -e $(printf "\e[31m ⚠️ docker not found! ⚠️\e[0m") - read -p "Do you want YAMS to install Docker and Docker Compose? IT ONLY WORKS ON DEBIAN AND UBUNTU! [y/N]: " install_docker - install_docker=${install_docker:-"n"} - - if [ "$install_docker" == "y" ]; then - bash ./docker.sh - else - send_error_message "Install Docker and Docker Compose and come back later!" - fi - fi -} -#+end_src - -** Running services location -:PROPERTIES: -:ID: 53213557-edfe-4da7-88c0-e0e202429116 -:END: - -This function just displays the locations for every container so the user can access to it when YAMS -finish installing. - -#+begin_src bash -running_services_location() { - host_ip=$(hostname -I | awk '{ print $1 }') - - services=( - "qBittorrent:8080" - "Radarr:7878" - "Sonarr:8989" - "Lidarr:8686" - "Readarr:8787" - "Prowlarr:9696" - "Bazarr:6767" - "$media_service:$media_service_port" - "Portainer:9000" - ) - - echo -e "Service URLs:" - for service in "${services[@]}"; do - service_name="${service%%:*}" - service_port="${service##*:}" - echo "$service_name: http://$host_ip:$service_port/" done + + # If there are missing packages, offer to install them + if [ ${#missing_packages[@]} -gt 0 ]; then + log_warning "Missing required packages: ${missing_packages[*]}" + read -p "Would you like to install the missing packages? (y/N) [Default = n]: " install_deps + install_deps=${install_deps:-"n"} + + if [ "${install_deps,,}" = "y" ]; then + echo "Installing missing packages..." + if ! sudo apt update && sudo apt install -y "${missing_packages[@]}"; then + log_error "Failed to install missing packages. Please install them manually: ${missing_packages[*]}" + fi + log_success "Successfully installed missing packages ✅" + else + log_error "Please install the required packages manually: ${missing_packages[*]}" + fi + fi + + # Check Docker and Docker Compose + if command -v docker &> /dev/null; then + log_success "docker exists ✅" + if docker compose version &> /dev/null; then + log_success "docker compose exists ✅" + return 0 + fi + fi + + log_warning "⚠️ Docker/Docker Compose not found! ⚠️" + read -p "Install Docker and Docker Compose? Only works on Debian/Ubuntu (y/N) [Default = n]: " install_docker + install_docker=${install_docker:-"n"} + + if [ "${install_docker,,}" = "y" ]; then + bash ./docker.sh + else + log_error "Please install Docker and Docker Compose first" + fi } #+end_src -* Verify all the dependencies +** Service Configuration :PROPERTIES: -:ID: e945d5a8-5142-41fe-8175-96de7aa84cf2 +:ID: new-service-section :END: #+begin_src bash -echo "Checking prerequisites..." +configure_media_service() { + echo + echo + echo + log_info "Time to choose your media service." + log_info "Your media service is responsible for serving your files to your network." + log_info "Supported media services:" + log_info "- jellyfin (recommended, easier)" + log_info "- emby" + log_info "- plex (advanced, always online)" + read -p "Choose your media service [$DEFAULT_MEDIA_SERVICE]: " media_service + media_service=${media_service:-$DEFAULT_MEDIA_SERVICE} + media_service=$(echo "$media_service" | awk '{print tolower($0)}') -check_dependencies - -if [[ "$EUID" = 0 ]]; then - send_error_message "YAMS has to run without sudo! Please, run it again with regular permissions" -fi -#+end_src - -* Gather all the required information -:PROPERTIES: -:ID: 438cecef-2bd6-4d7c-b429-6c674ae311d9 -:END: -** Checking install location -:PROPERTIES: -:ID: fff12355-9d79-40fe-a540-cfba2a176a3e -:END: - -#+begin_src bash -default_install_directory="/opt/yams" - -read -p "Where do you want to install the docker-compose file? [$default_install_directory]: " install_directory -install_directory=${install_directory:-$default_install_directory} - -if [ ! -d "$install_directory" ]; then - echo "The directory \"$install_directory\" does not exists. Attempting to create..." - if mkdir -p "$install_directory"; then - send_success_message "Directory $install_directory created ✅" - else - send_error_message "There was an error creating the installation directory at \"$install_directory\". Make sure you have the necessary permissions ❌" + if [[ ! " ${SUPPORTED_MEDIA_SERVICES[@]} " =~ " ${media_service} " ]]; then + log_error "\"$media_service\" is not supported by YAMS" fi -fi -if [ ! -w "$install_directory" ] || [ ! -r "$install_directory" ]; then - send_error_message "The directory \"$install_directory\" is not writable or readable by the current user. Set the correct permissions or try a different directory" ❌ -fi - -filename="$install_directory/docker-compose.yaml" -custom_file_filename="$install_directory/docker-compose.custom.yaml" -env_file="$install_directory/.env" -#+end_src - -** Setting the correct user -:PROPERTIES: -:ID: 7428d7b7-aec5-4638-b370-84e9055fb412 -:END: - -#+begin_src bash -read -p "What's the user that is going to own the media server files? [$USER]: " username -username=${username:-$USER} - -if id -u "$username" &>/dev/null; then - puid=$(id -u "$username"); - pgid=$(id -g "$username"); -else - send_error_message "The user \"$username\" doesn't exist!" -fi -#+end_src - -** Media directory -:PROPERTIES: -:ID: 9726dead-8833-4f23-98b8-2790d72605de -:END: - -#+begin_src bash -read -p "Please, input your media directory [/srv/media]: " media_directory -media_directory=${media_directory:-"/srv/media"} - -read -p "Are you sure your media directory is \"$media_directory\"? [y/N]: " media_directory_correct -media_directory_correct=${media_directory_correct:-"n"} - -if [ ! -d "$media_directory" ]; then - echo "The directory \"$media_directory\" does not exists. Attempting to create..." - if mkdir -p "$media_directory"; then - send_success_message "Directory $media_directory created ✅" + # Set media service port + if [ "$media_service" == "plex" ]; then + media_service_port=32400 else - send_error_message "There was an error creating the installation directory at \"$media_directory\". Make sure you have the necessary permissions ❌" + media_service_port=8096 fi -fi -if [ "$media_directory_correct" == "n" ]; then - send_error_message "Media directory is not correct. Please fix it and run the script again ❌" -fi -#+end_src + echo + log_success "YAMS will install \"$media_service\" on port \"$media_service_port\"" -** Setting perferred media service -:PROPERTIES: -:ID: 3af8dbed-3a88-4739-a721-6434993c0b67 -:END: + # Export for use in other functions + export media_service media_service_port +} -#+begin_src bash -echo -e "\n\n\nTime to choose your media service." -echo "Your media service is responsible for serving your files to your network." -echo "By default, YAMS supports 3 media services:" -echo "- jellyfin (recommended, easier)" -echo "- emby" -echo "- plex (advanced, always online)" +configure_vpn() { + echo + echo + echo + log_info "Time to set up the VPN." + log_info "Supported VPN providers: https://yams.media/advanced/vpn" -read -p "Choose your media service [jellyfin]: " media_service -media_service=${media_service:-"jellyfin"} -media_service=$(echo "$media_service" | awk '{print tolower($0)}') + read -p "Configure VPN? (Y/n) [Default = y]: " setup_vpn + setup_vpn=${setup_vpn:-"y"} -media_service_port=8096 -if [ "$media_service" == "plex" ]; then - media_service_port=32400 -fi + if [ "${setup_vpn,,}" != "y" ]; then + export setup_vpn="n" + return 0 + fi -if echo "emby plex jellyfin" | grep -qw "$media_service"; then - echo -e "\nYAMS is going to install \"$media_service\" on port \"$media_service_port\"" -else - send_error_message "\"$media_service\" is not supported by YAMS. Are you sure you chose the correct service?" -fi -#+end_src + read -p "VPN service? (with spaces) [$DEFAULT_VPN_SERVICE]: " vpn_service + vpn_service=${vpn_service:-$DEFAULT_VPN_SERVICE} -** Setting the VPN -:PROPERTIES: -:ID: 1da4fe67-ee20-4b70-8f36-4a9f7161b6ca -:END: + echo + log_info "Please check $vpn_service's documentation for specific configuration:" + log_info "https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" -#+begin_src bash -echo -e "\nTime to set up the VPN." -echo "You can check the supported VPN list here: https://yams.media/advanced/vpn." - -read -p "Do you want to configure a VPN? [Y/n]: " setup_vpn -setup_vpn=${setup_vpn:-"y"} - -if [ "$setup_vpn" == "y" ]; then - read -p "What's your VPN service? (with spaces) [mullvad]: " vpn_service - vpn_service=${vpn_service:-"mullvad"} - - echo -e "\nYou should read $vpn_service's documentation in case it has different configurations for username and password." - echo "The documentation for $vpn_service is here: https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" - - read -p "What's your VPN username? (without spaces): " vpn_user + read -p "VPN username (without spaces): " vpn_user + [ -z "$vpn_user" ] && log_error "VPN username cannot be empty" + # Use hidden input for password unset vpn_password charcount=0 - prompt="What's your VPN password? (if you are using mullvad, just enter your username again): " - while IFS= read -p "$prompt" -r -s -n 1 char - do - if [[ $char == $'\0' ]] - then + prompt="VPN password (if using mullvad, enter username again): " + while IFS= read -p "$prompt" -r -s -n 1 char; do + if [[ $char == $'\0' ]]; then break fi - if [[ $char == $'\177' ]] ; then - if [ $charcount -gt 0 ] ; then + if [[ $char == $'\177' ]]; then + if [ $charcount -gt 0 ]; then charcount=$((charcount-1)) prompt=$'\b \b' vpn_password="${vpn_password%?}" @@ -339,173 +296,253 @@ if [ "$setup_vpn" == "y" ]; then fi done echo -fi -echo "Configuring the docker-compose file for the user \"$username\" on \"$install_directory\"..." -#+end_src + [ -z "$vpn_password" ] && log_error "VPN password cannot be empty" -* Installing YAMS -:PROPERTIES: -:ID: 44e5f3f1-3ae7-4f88-ba96-8149c9980fb2 -:END: -** Copy the docker-compose file to the install location -:PROPERTIES: -:ID: 09018e25-ed48-46e9-85c3-586c37844c11 -:END: + # Export for use in other functions + export vpn_service vpn_user vpn_password setup_vpn +} -#+begin_src bash -copy_files=( - "docker-compose.example.yaml:$filename" - ".env.example:$env_file" - "docker-compose.custom.yaml:$custom_file_filename" -) +running_services_location() { + local host_ip + host_ip=$(hostname -I | awk '{ print $1 }') -for file_mapping in "${copy_files[@]}"; do - source_file="${file_mapping%%:*}" - destination_file="${file_mapping##*:}" + local -A services=( + ["qBittorrent"]="8081" + ["SABnzbd"]="8080" + ["Radarr"]="7878" + ["Sonarr"]="8989" + ["Lidarr"]="8686" + ["Readarr"]="8787" + ["Prowlarr"]="9696" + ["Bazarr"]="6767" + ["$media_service"]="$media_service_port" + ["Portainer"]="9000" + ) - echo -e "\nCopying $source_file to $destination_file..." - if cp "$source_file" "$destination_file"; then - send_success_message "$source_file was copied successfuly! ✅" + echo -e "Service URLs:" + for service in "${!services[@]}"; do + echo "$service: http://$host_ip:${services[$service]}/" + done +} + +get_user_info() { + read -p "User to own the media server files? [$USER]: " username + username=${username:-$USER} + + if id -u "$username" &>/dev/null; then + puid=$(id -u "$username") + pgid=$(id -g "$username") else - send_error_message "Failed to copy $source_file to $destination_file. Ensure your user ($USER) has the necessary permissions ❌" + log_error "User \"$username\" doesn't exist!" fi -done + + export username puid pgid +} + +get_installation_paths() { + read -p "Installation directory? [$DEFAULT_INSTALL_DIR]: " install_directory + install_directory=${install_directory:-$DEFAULT_INSTALL_DIR} + create_and_verify_directory "$install_directory" "installation" + + read -p "Media directory? [$DEFAULT_MEDIA_DIR]: " media_directory + media_directory=${media_directory:-$DEFAULT_MEDIA_DIR} + + read -p "Are you sure your media directory is \"$media_directory\"? (y/N) [Default = n]: " media_directory_correct + media_directory_correct=${media_directory_correct:-"n"} + + if [ "${media_directory_correct,,}" != "y" ]; then + log_error "Media directory is not correct. Please fix it and run the script again ❌" + fi + + setup_directory_structure "$media_directory" + verify_user_permissions "$username" "$media_directory" + + export install_directory media_directory +} #+end_src -#+RESULTS: - -** Set PUID, PGID, Media Folder, Media Service, Config folder and VPN on the YAMS scripts +** File Operations :PROPERTIES: -:ID: 3d169001-f0f7-477f-a954-0460484f4b43 -:END: - -This steps prepares all the files with the correct information that was collected on the "[[#gather-all-the-required-information][Gather all the -required information]]" step. - -#+begin_src bash -sed -i -e "s||$puid|g" "$env_file" \ - -e "s||$pgid|g" "$env_file" \ - -e "s||$media_directory|g" "$env_file" \ - -e "s||$media_service|g" "$env_file" \ - -e "s||$media_service|g" "$filename" - -if [ "$media_service" == "plex" ]; then - sed -i -e "s|#network_mode: host # plex|network_mode: host # plex|g" "$filename" \ - -e "s|ports: # plex|#ports: # plex|g" "$filename" \ - -e "s|- 8096:8096 # plex|#- 8096:8096 # plex|g" "$filename" -fi - -sed -i -e "s||$install_directory|g" "$env_file" \ - -e "s|vpn_enabled|$setup_vpn|g" "$env_file" \ - -if [ "$setup_vpn" == "y" ]; then - sed -i -e "s|vpn_service|$vpn_service|g" "$env_file" \ - -e "s|vpn_user|$vpn_user|g" "$env_file" \ - -e "s|vpn_password|$vpn_password|g" "$env_file" \ - -e "s|#network_mode: \"service:gluetun\"|network_mode: \"service:gluetun\"|g" "$filename" \ - -e "s|ports: # qbittorrent|#ports: # qbittorrent|g" "$filename" \ - -e "s|- 8080:8080 # qbittorrent|#- 8080:8080 # qbittorrent|g" "$filename" \ - -e "s|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g" "$filename" -fi -#+end_src - -** Set the configuration for the YAMS binary -:PROPERTIES: -:ID: b6a8732f-9dbe-4d93-b04d-27156eacdea2 +:ID: new-file-operations-section :END: #+begin_src bash -sed -i -e "s||$filename|g" yams \ - -e "s||$custom_file_filename|g" yams \ - -e "s||$install_directory|g" yams -#+end_src +copy_configuration_files() { + local -A files=( + ["docker-compose.example.yaml"]="docker-compose.yaml" + [".env.example"]=".env" + ["docker-compose.custom.yaml"]="docker-compose.custom.yaml" + ) -** Success message! -:PROPERTIES: -:ID: 7b0ed8f5-780b-4685-8123-8d5c4229eaba -:END: + for src in "${!files[@]}"; do + local dest="$install_directory/${files[$src]}" + echo + log_info "Copying $src to $dest..." -Finally, YAMS is installed 🔥. Show the success message + if cp "$src" "$dest"; then + log_success "$src copied successfully ✅" + else + log_error "Failed to copy $src to $dest. Check permissions ❌" + fi + done +} -#+begin_src bash -send_success_message "Everything installed correctly! 🎉" +update_configuration_files() { + local filename="$install_directory/docker-compose.yaml" + local env_file="$install_directory/.env" + local yams_script="yams" -echo "Running the server..." -echo "This is going to take a while..." + # Update .env file + log_info "Updating environment configuration..." + sed -i -e "s||$puid|g" \ + -e "s||$pgid|g" \ + -e "s||$media_directory|g" \ + -e "s||$media_service|g" \ + -e "s||$install_directory|g" \ + -e "s|vpn_enabled|$setup_vpn|g" "$env_file" || \ + log_error "Failed to update .env file" -docker compose -f "$filename" up -d -#+end_src -* Final steps -:PROPERTIES: -:ID: 65ce5828-b69a-4a0e-83f6-b029e19caea1 -:END: -** Install the YAMS CLI -:PROPERTIES: -:ID: f4f9d166-8a2b-4d79-bc7f-fe73ecf5fb77 -:END: - -This steps requires ~sudo~ because it's copying the main yams script to the ~/usr/local/bin/yams~ -directory. - -#+begin_src bash -echo -e "\nWe need your sudo password to install the YAMS CLI and configure permissions..." - -if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then - send_success_message "YAMS CLI installed successfully ✅" + # Update VPN configuration in .env file +if [ "${setup_vpn,,}" == "y" ]; then +sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=y|" \ + -e "s|^VPN_SERVICE=.*|VPN_SERVICE=$vpn_service|" \ + -e "s|^VPN_USER=.*|VPN_USER=$vpn_user|" \ + -e "s|^VPN_PASSWORD=.*|VPN_PASSWORD=$vpn_password|" "$env_file" || \ + log_error "Failed to update VPN configuration in .env" else - send_error_message "Failed to install YAMS CLI. Make sure you have the necessary permissions ❌" -fi -#+end_src - -** Set the correct permissions to the media and install directories -:PROPERTIES: -:ID: 4cfb9397-776d-46db-84cc-54b78395cba8 -:END: - -This adds the correct permissions to the media folder, in case they are not correct. - -#+begin_src bash -if sudo chown -R "$puid":"$pgid" "$media_directory"; then - send_success_message "Media directory ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the media directory. Check permissions ❌" +sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=n|" "$env_file" || \ + log_error "Failed to update VPN configuration in .env" fi -if sudo chown -R "$puid":"$pgid" "$install_directory"; then - send_success_message "Install directory ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the install directory. Check permissions ❌" -fi -#+end_src + # Update docker-compose.yaml + log_info "Updating docker-compose configuration..." + sed -i "s||$media_service|g" "$filename" || \ + log_error "Failed to update docker-compose.yaml" -** Create the config directory -:PROPERTIES: -:ID: 699f35fe-edde-406d-be0b-3ff2eaa6d7eb -:END: + # Configure Plex-specific settings + if [ "$media_service" == "plex" ]; then + log_info "Configuring Plex-specific settings..." + sed -i -e 's|#network_mode: host # plex|network_mode: host # plex|g' \ + -e 's|ports: # plex|#ports: # plex|g' \ + -e 's|- 8096:8096 # plex|#- 8096:8096 # plex|g' "$filename" || \ + log_error "Failed to configure Plex settings" + fi -This is where all the configurations are going to be saved. If it doesn't it will try and create it. If -it can't be created, we'll raise an error. + # Configure VPN settings if enabled + if [ "${setup_vpn,,}" == "y" ]; then + log_info "Configuring VPN settings..." + sed -i -e "s|vpn_service|$vpn_service|g" \ + -e "s|vpn_user|$vpn_user|g" \ + -e "s|vpn_password|$vpn_password|g" \ + -e 's|#network_mode: "service:gluetun"|network_mode: "service:gluetun"|g' \ + -e 's|ports: # qbittorrent|#ports: # qbittorrent|g' \ + -e 's|ports: # sabnzbd|#ports: # sabnzbd|g' \ + -e 's|- 8081:8081 # qbittorrent|#- 8081:8081 # qbittorrent|g' \ + -e 's|- 8080:8080 # sabnzbd|#- 8080:8080 # sabnzbd|g' \ + -e 's|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g' \ + -e 's|#- 8081:8081/tcp # gluetun|- 8081:8081/tcp # gluetun|g' "$filename" || \ + log_error "Failed to configure VPN settings" + fi -#+begin_src bash -if [[ -d "$install_directory/config" ]]; then - send_success_message "Configuration folder \"$install_directory/config\" exists ✅" -else - if sudo mkdir -p "$install_directory/config"; then - send_success_message "Configuration folder \"$install_directory/config\" created ✅" + # Update YAMS CLI script + log_info "Updating YAMS CLI configuration..." + sed -i -e "s||$filename|g" \ + -e "s||$install_directory/docker-compose.custom.yaml|g" \ + -e "s||$install_directory|g" "$yams_script" || \ + log_error "Failed to update YAMS CLI script" +} + +install_cli() { + echo + log_info "Installing YAMS CLI..." + if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then + log_success "YAMS CLI installed successfully ✅" else - send_error_message "Failed to create or access the configuration folder. Check permissions ❌" + log_error "Failed to install YAMS CLI. Check permissions ❌" fi -fi +} -if sudo chown -R "$puid":"$pgid" "$install_directory/config"; then - send_success_message "Configuration folder ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the configuration folder. Check permissions ❌" -fi +set_permissions() { + local dirs=("$media_directory" "$install_directory" "$install_directory/config") + + for dir in "${dirs[@]}"; do + log_info "Setting permissions for $dir..." + if [ ! -d "$dir" ]; then + mkdir -p "$dir" || log_error "Failed to create directory $dir" + fi + + if sudo chown -R "$puid:$pgid" "$dir"; then + log_success "Permissions set successfully for $dir ✅" + else + log_error "Failed to set permissions for $dir ❌" + fi + done +} #+end_src -* Display closing message +* Script Execution +:PROPERTIES: +:ID: new-script-execution +:END: + +** Verify Prerequisites +:PROPERTIES: +:ID: e945d5a8-5142-41fe-8175-96de7aa84cf2 +:END: + +#+begin_src bash +# Prevent running as root +if [[ "$EUID" = 0 ]]; then + log_error "YAMS must run without sudo! Please run with regular permissions" +fi + +# Check all dependencies +log_info "Checking prerequisites..." +check_dependencies +#+end_src + +** Installation Process +:PROPERTIES: +:ID: new-installation-process +:END: + +#+begin_src bash +# Get user information +get_user_info + +# Get installation paths +get_installation_paths + +# Configure services +configure_media_service +configure_vpn + +log_info "Configuring the docker-compose file for user \"$username\" in \"$install_directory\"..." + +# Copy and update configuration files +copy_configuration_files +update_configuration_files + +log_success "Everything installed correctly! 🎉" + +# Start services +log_info "Starting YAMS services..." +log_info "This may take a while..." + +if ! docker compose -f "$install_directory/docker-compose.yaml" up -d; then + log_error "Failed to start YAMS services" +fi + +# Install CLI and set permissions +echo +log_info "We need your sudo password to install the YAMS CLI and configure permissions..." +install_cli +set_permissions + +#+end_src + +* Display Closing Message :PROPERTIES: :ID: 238e3eae-9df7-4a7f-a460-7a61c07b5442 :END: @@ -513,36 +550,42 @@ fi #+begin_src bash printf "\033c" -echo "========================================================" -echo " _____ ___ ___ ___ " -echo " / /::\ / /\ /__/\ / /\ " -echo " / /:/\:\ / /::\ \ \:\ / /:/_ " -echo " / /:/ \:\ / /:/\:\ \ \:\ / /:/ /\ " -echo " /__/:/ \__\:| / /:/ \:\ _____\__\:\ / /:/ /:/_ " -echo " \ \:\ / /:/ /__/:/ \__\:\ /__/::::::::\ /__/:/ /:/ /\\" -echo " \ \:\ /:/ \ \:\ / /:/ \ \:\~~\~~\/ \ \:\/:/ /:/" -echo " \ \:\/:/ \ \:\ /:/ \ \:\ ~~~ \ \::/ /:/ " -echo " \ \::/ \ \:\/:/ \ \:\ \ \:\/:/ " -echo " \__\/ \ \::/ \ \:\ \ \::/ " -echo " \__\/ \__\/ \__\/ " -echo "========================================================" -send_success_message "All done!✅ Enjoy YAMS!" -echo "You can check the installation on $install_directory" -echo "========================================================" -echo "Everything should be running now! To check everything running, go to:" +cat << "EOF" +======================================================== + _____ ___ ___ ___ + / /::\ / /\ /__/\ / /\ + / /:/\:\ / /::\ \ \:\ / /:/_ + / /:/ \:\ / /:/\:\ \ \:\ / /:/ /\ + /__/:/ \__\:| / /:/ \:\ _____\__\:\ / /:/ /:/_ + \ \:\ / /:/ /__/:/ \__\:\ /__/::::::::\ /__/:/ /:/ /\\ + \ \:\ /:/ \ \:\ / /:/ \ \:\~~\~~\/ \ \:\/:/ /:/ + \ \:\/:/ \ \:\ /:/ \ \:\ ~~~ \ \::/ /:/ + \ \::/ \ \:\/:/ \ \:\ \ \:\/:/ + \__\/ \ \::/ \ \:\ \ \::/ + \__\/ \__\/ \__\/ +======================================================== +EOF + +log_success "All done!✅ Enjoy YAMS!" +log_info "You can check the installation in $install_directory" +log_info "========================================================" +log_info "Everything should be running now! To check everything running, go to:" echo + running_services_location + echo +log_info "You might need to wait for a couple of minutes while everything gets up and running" echo -echo "You might need to wait for a couple of minutes while everything gets up and running" -echo -echo "All the services location are also saved in ~/yams_services.txt" +log_info "All the service locations are also saved in ~/yams_services.txt" running_services_location > ~/yams_services.txt -echo "========================================================" + +log_info "========================================================" echo -echo "To configure YAMS, check the documentation at" -echo "https://yams.media/config" +log_info "To configure YAMS, check the documentation at" +log_info "https://yams.media/config" echo -echo "========================================================" +log_info "========================================================" + exit 0 #+end_src diff --git a/install.sh b/install.sh index 09e4968..609939f 100644 --- a/install.sh +++ b/install.sh @@ -23,175 +23,199 @@ echo "To finish the installation of the CLI" echo "====================================================" echo "" -send_success_message() { - echo -e $(printf "\e[32m$1\e[0m") +# Constants +readonly DEFAULT_INSTALL_DIR="/opt/yams" +readonly DEFAULT_MEDIA_DIR="/srv/media" +readonly SUPPORTED_MEDIA_SERVICES=("jellyfin" "emby" "plex") +readonly DEFAULT_MEDIA_SERVICE="jellyfin" +readonly DEFAULT_VPN_SERVICE="protonvpn" +readonly MEDIA_SUBDIRS=("tvshows" "movies" "music" "books" "downloads" "blackhole") + +# Color codes +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color + +# Dependencies +readonly REQUIRED_COMMANDS=("curl" "sed" "awk") + +log_success() { + echo -e "${GREEN}$1${NC}" } -send_error_message() { - echo -e $(printf "\e[31m$1\e[0m") - exit 255 +log_error() { + echo -e "${RED}$1${NC}" >&2 + exit 1 } -check_dependencies() { - if command -v docker &> /dev/null; then - send_success_message "docker exists ✅ " - if docker compose version &> /dev/null; then - send_success_message "docker compose exists ✅ " - else - echo -e $(printf "\e[31m ⚠️ docker compose not found! ⚠️\e[0m") - read -p "Do you want YAMS to install Docker Compose? IT ONLY WORKS ON DEBIAN AND UBUNTU! (y/N) [Default = n]: " install_docker - install_docker=${install_docker:-"n"} +log_warning() { + echo -e "${YELLOW}$1${NC}" +} - if [ "$install_docker" == "y" ]; then - bash ./docker.sh - else - send_error_message "Install Docker Compose and come back later!" - fi - fi - else - echo -e $(printf "\e[31m ⚠️ docker not found! ⚠️\e[0m") - read -p "Do you want YAMS to install Docker and Docker Compose? IT ONLY WORKS ON DEBIAN AND UBUNTU! (y/N) [Default = n]: " install_docker - install_docker=${install_docker:-"n"} +log_info() { + echo "$1" +} - if [ "$install_docker" == "y" ]; then - bash ./docker.sh +create_and_verify_directory() { + local dir="$1" + local dir_type="$2" + + if [ ! -d "$dir" ]; then + echo "The directory \"$dir\" does not exist. Attempting to create..." + if mkdir -p "$dir"; then + log_success "Directory $dir created ✅" else - send_error_message "Install Docker and Docker Compose and come back later!" + log_error "Failed to create $dir_type directory at \"$dir\". Check permissions ❌" fi fi + + if [ ! -w "$dir" ] || [ ! -r "$dir" ]; then + log_error "Directory \"$dir\" is not writable or readable. Check permissions ❌" + fi } -running_services_location() { - host_ip=$(hostname -I | awk '{ print $1 }') +setup_directory_structure() { + local media_dir="$1" - services=( - "qBittorrent:8080" - "Radarr:7878" - "Sonarr:8989" - "Lidarr:8686" - "Readarr:8787" - "Prowlarr:9696" - "Bazarr:6767" - "$media_service:$media_service_port" - "Portainer:9000" - ) + create_and_verify_directory "$media_dir" "media" - echo -e "Service URLs:" - for service in "${services[@]}"; do - service_name="${service%%:*}" - service_port="${service##*:}" - echo "$service_name: http://$host_ip:$service_port/" + for subdir in "${MEDIA_SUBDIRS[@]}"; do + create_and_verify_directory "$media_dir/$subdir" "media subdirectory" done } -echo "Checking prerequisites..." +verify_user_permissions() { + local username="$1" + local directory="$2" - -check_dependencies - -if [[ "$EUID" = 0 ]]; then - send_error_message "YAMS has to run without sudo! Please, run it again with regular permissions" -fi - -default_install_directory="/opt/yams" - -read -p "Where do you want to install the docker-compose file? [$default_install_directory]: " install_directory -install_directory=${install_directory:-$default_install_directory} - -if [ ! -d "$install_directory" ]; then - echo "The directory \"$install_directory\" does not exists. Attempting to create..." - if mkdir -p "$install_directory"; then - send_success_message "Directory $install_directory created ✅" - else - send_error_message "There was an error creating the installation directory at \"$install_directory\". Make sure you have the necessary permissions ❌" + if ! id -u "$username" &>/dev/null; then + log_error "User \"$username\" doesn't exist!" fi -fi -if [ ! -w "$install_directory" ] || [ ! -r "$install_directory" ]; then - send_error_message "The directory \"$install_directory\" is not writable or readable by the current user. Set the correct permissions or try a different directory" ❌ -fi - -filename="$install_directory/docker-compose.yaml" -custom_file_filename="$install_directory/docker-compose.custom.yaml" -env_file="$install_directory/.env" - -read -p "What's the user that is going to own the media server files? [$USER]: " username -username=${username:-$USER} - -if id -u "$username" &>/dev/null; then - puid=$(id -u "$username"); - pgid=$(id -g "$username"); -else - send_error_message "The user \"$username\" doesn't exist!" -fi - -read -p "Please, input your media directory [/srv/media]: " media_directory -media_directory=${media_directory:-"/srv/media"} - -read -p "Are you sure your media directory is \"$media_directory\"? (y/N) [Default = n]: " media_directory_correct -media_directory_correct=${media_directory_correct:-"n"} - -if [ ! -d "$media_directory" ]; then - echo "The directory \"$media_directory\" does not exists. Attempting to create..." - if mkdir -p "$media_directory"; then - send_success_message "Directory $media_directory created ✅" - else - send_error_message "There was an error creating the installation directory at \"$media_directory\". Make sure you have the necessary permissions ❌" + if ! sudo -u "$username" test -w "$directory"; then + log_error "User \"$username\" doesn't have write permissions to \"$directory\"" fi -fi +} -if [ "$media_directory_correct" == "n" ]; then - send_error_message "Media directory is not correct. Please fix it and run the script again ❌" -fi +check_dependencies() { + local missing_packages=() + local install_cmd="" -echo -e "\n\n\nTime to choose your media service." -echo "Your media service is responsible for serving your files to your network." -echo "By default, YAMS supports 3 media services:" -echo "- jellyfin (recommended, easier)" -echo "- emby" -echo "- plex (advanced, always online)" + # Check for required commands and collect missing ones + for pkg in "${REQUIRED_COMMANDS[@]}"; do + if ! command -v "$pkg" &> /dev/null; then + missing_packages+=("$pkg") + else + log_success "$pkg exists ✅" + fi + done -read -p "Choose your media service [jellyfin]: " media_service -media_service=${media_service:-"jellyfin"} -media_service=$(echo "$media_service" | awk '{print tolower($0)}') + # If there are missing packages, offer to install them + if [ ${#missing_packages[@]} -gt 0 ]; then + log_warning "Missing required packages: ${missing_packages[*]}" + read -p "Would you like to install the missing packages? (y/N) [Default = n]: " install_deps + install_deps=${install_deps:-"n"} -media_service_port=8096 -if [ "$media_service" == "plex" ]; then - media_service_port=32400 -fi + if [ "${install_deps,,}" = "y" ]; then + echo "Installing missing packages..." + if ! sudo apt update && sudo apt install -y "${missing_packages[@]}"; then + log_error "Failed to install missing packages. Please install them manually: ${missing_packages[*]}" + fi + log_success "Successfully installed missing packages ✅" + else + log_error "Please install the required packages manually: ${missing_packages[*]}" + fi + fi -if echo "emby plex jellyfin" | grep -qw "$media_service"; then - echo -e "\nYAMS is going to install \"$media_service\" on port \"$media_service_port\"" -else - send_error_message "\"$media_service\" is not supported by YAMS. Are you sure you chose the correct service?" -fi + # Check Docker and Docker Compose + if command -v docker &> /dev/null; then + log_success "docker exists ✅" + if docker compose version &> /dev/null; then + log_success "docker compose exists ✅" + return 0 + fi + fi -echo -e "\nTime to set up the VPN." -echo "You can check the supported VPN list here: https://yams.media/advanced/vpn." + log_warning "⚠️ Docker/Docker Compose not found! ⚠️" + read -p "Install Docker and Docker Compose? Only works on Debian/Ubuntu (y/N) [Default = n]: " install_docker + install_docker=${install_docker:-"n"} -read -p "Do you want to configure a VPN? (Y/n) [Default = y]: " setup_vpn -setup_vpn=${setup_vpn:-"y"} + if [ "${install_docker,,}" = "y" ]; then + bash ./docker.sh + else + log_error "Please install Docker and Docker Compose first" + fi +} -if [ "$setup_vpn" == "y" ]; then - read -p "What's your VPN service? (with spaces) [mullvad]: " vpn_service - vpn_service=${vpn_service:-"mullvad"} +configure_media_service() { + echo + echo + echo + log_info "Time to choose your media service." + log_info "Your media service is responsible for serving your files to your network." + log_info "Supported media services:" + log_info "- jellyfin (recommended, easier)" + log_info "- emby" + log_info "- plex (advanced, always online)" - echo -e "\nYou should read $vpn_service's documentation in case it has different configurations for username and password." - echo "The documentation for $vpn_service is here: https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" + read -p "Choose your media service [$DEFAULT_MEDIA_SERVICE]: " media_service + media_service=${media_service:-$DEFAULT_MEDIA_SERVICE} + media_service=$(echo "$media_service" | awk '{print tolower($0)}') - read -p "What's your VPN username? (without spaces): " vpn_user + if [[ ! " ${SUPPORTED_MEDIA_SERVICES[@]} " =~ " ${media_service} " ]]; then + log_error "\"$media_service\" is not supported by YAMS" + fi + # Set media service port + if [ "$media_service" == "plex" ]; then + media_service_port=32400 + else + media_service_port=8096 + fi + + echo + log_success "YAMS will install \"$media_service\" on port \"$media_service_port\"" + + # Export for use in other functions + export media_service media_service_port +} + +configure_vpn() { + echo + echo + echo + log_info "Time to set up the VPN." + log_info "Supported VPN providers: https://yams.media/advanced/vpn" + + read -p "Configure VPN? (Y/n) [Default = y]: " setup_vpn + setup_vpn=${setup_vpn:-"y"} + + if [ "${setup_vpn,,}" != "y" ]; then + export setup_vpn="n" + return 0 + fi + + read -p "VPN service? (with spaces) [$DEFAULT_VPN_SERVICE]: " vpn_service + vpn_service=${vpn_service:-$DEFAULT_VPN_SERVICE} + + echo + log_info "Please check $vpn_service's documentation for specific configuration:" + log_info "https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" + + read -p "VPN username (without spaces): " vpn_user + [ -z "$vpn_user" ] && log_error "VPN username cannot be empty" + + # Use hidden input for password unset vpn_password charcount=0 - prompt="What's your VPN password? (if you are using mullvad, just enter your username again): " - while IFS= read -p "$prompt" -r -s -n 1 char - do - if [[ $char == $'\0' ]] - then + prompt="VPN password (if using mullvad, enter username again): " + while IFS= read -p "$prompt" -r -s -n 1 char; do + if [[ $char == $'\0' ]]; then break fi - if [[ $char == $'\177' ]] ; then - if [ $charcount -gt 0 ] ; then + if [[ $char == $'\177' ]]; then + if [ $charcount -gt 0 ]; then charcount=$((charcount-1)) prompt=$'\b \b' vpn_password="${vpn_password%?}" @@ -205,131 +229,261 @@ if [ "$setup_vpn" == "y" ]; then fi done echo -fi -echo "Configuring the docker-compose file for the user \"$username\" on \"$install_directory\"..." + [ -z "$vpn_password" ] && log_error "VPN password cannot be empty" -copy_files=( - "docker-compose.example.yaml:$filename" - ".env.example:$env_file" - "docker-compose.custom.yaml:$custom_file_filename" -) + # Export for use in other functions + export vpn_service vpn_user vpn_password setup_vpn +} -for file_mapping in "${copy_files[@]}"; do - source_file="${file_mapping%%:*}" - destination_file="${file_mapping##*:}" +running_services_location() { + local host_ip + host_ip=$(hostname -I | awk '{ print $1 }') - echo -e "\nCopying $source_file to $destination_file..." - if cp "$source_file" "$destination_file"; then - send_success_message "$source_file was copied successfuly! ✅" + local -A services=( + ["qBittorrent"]="8081" + ["SABnzbd"]="8080" + ["Radarr"]="7878" + ["Sonarr"]="8989" + ["Lidarr"]="8686" + ["Readarr"]="8787" + ["Prowlarr"]="9696" + ["Bazarr"]="6767" + ["$media_service"]="$media_service_port" + ["Portainer"]="9000" + ) + + echo -e "Service URLs:" + for service in "${!services[@]}"; do + echo "$service: http://$host_ip:${services[$service]}/" + done +} + +get_user_info() { + read -p "User to own the media server files? [$USER]: " username + username=${username:-$USER} + + if id -u "$username" &>/dev/null; then + puid=$(id -u "$username") + pgid=$(id -g "$username") else - send_error_message "Failed to copy $source_file to $destination_file. Ensure your user ($USER) has the necessary permissions ❌" + log_error "User \"$username\" doesn't exist!" fi -done -sed -i -e "s||$puid|g" "$env_file" \ - -e "s||$pgid|g" "$env_file" \ - -e "s||$media_directory|g" "$env_file" \ - -e "s||$media_service|g" "$env_file" \ - -e "s||$media_service|g" "$filename" + export username puid pgid +} -if [ "$media_service" == "plex" ]; then - sed -i -e "s|#network_mode: host # plex|network_mode: host # plex|g" "$filename" \ - -e "s|ports: # plex|#ports: # plex|g" "$filename" \ - -e "s|- 8096:8096 # plex|#- 8096:8096 # plex|g" "$filename" -fi +get_installation_paths() { + read -p "Installation directory? [$DEFAULT_INSTALL_DIR]: " install_directory + install_directory=${install_directory:-$DEFAULT_INSTALL_DIR} + create_and_verify_directory "$install_directory" "installation" -sed -i -e "s||$install_directory|g" "$env_file" \ - -e "s|vpn_enabled|$setup_vpn|g" "$env_file" \ + read -p "Media directory? [$DEFAULT_MEDIA_DIR]: " media_directory + media_directory=${media_directory:-$DEFAULT_MEDIA_DIR} -if [ "$setup_vpn" == "y" ]; then - sed -i -e "s|vpn_service|$vpn_service|g" "$env_file" \ - -e "s|vpn_user|$vpn_user|g" "$env_file" \ - -e "s|vpn_password|$vpn_password|g" "$env_file" \ - -e "s|#network_mode: \"service:gluetun\"|network_mode: \"service:gluetun\"|g" "$filename" \ - -e "s|ports: # qbittorrent|#ports: # qbittorrent|g" "$filename" \ - -e "s|- 8080:8080 # qbittorrent|#- 8080:8080 # qbittorrent|g" "$filename" \ - -e "s|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g" "$filename" -fi + read -p "Are you sure your media directory is \"$media_directory\"? (y/N) [Default = n]: " media_directory_correct + media_directory_correct=${media_directory_correct:-"n"} -sed -i -e "s||$filename|g" yams \ - -e "s||$custom_file_filename|g" yams \ - -e "s||$install_directory|g" yams + if [ "${media_directory_correct,,}" != "y" ]; then + log_error "Media directory is not correct. Please fix it and run the script again ❌" + fi -send_success_message "Everything installed correctly! 🎉" + setup_directory_structure "$media_directory" + verify_user_permissions "$username" "$media_directory" -echo "Running the server..." -echo "This is going to take a while..." + export install_directory media_directory +} -docker compose -f "$filename" up -d +copy_configuration_files() { + local -A files=( + ["docker-compose.example.yaml"]="docker-compose.yaml" + [".env.example"]=".env" + ["docker-compose.custom.yaml"]="docker-compose.custom.yaml" + ) -echo -e "\nWe need your sudo password to install the YAMS CLI and configure permissions..." + for src in "${!files[@]}"; do + local dest="$install_directory/${files[$src]}" + echo + log_info "Copying $src to $dest..." -if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then - send_success_message "YAMS CLI installed successfully ✅" + if cp "$src" "$dest"; then + log_success "$src copied successfully ✅" + else + log_error "Failed to copy $src to $dest. Check permissions ❌" + fi + done +} + +update_configuration_files() { + local filename="$install_directory/docker-compose.yaml" + local env_file="$install_directory/.env" + local yams_script="yams" + + # Update .env file + log_info "Updating environment configuration..." + sed -i -e "s||$puid|g" \ + -e "s||$pgid|g" \ + -e "s||$media_directory|g" \ + -e "s||$media_service|g" \ + -e "s||$install_directory|g" \ + -e "s|vpn_enabled|$setup_vpn|g" "$env_file" || \ + log_error "Failed to update .env file" + + # Update VPN configuration in .env file +if [ "${setup_vpn,,}" == "y" ]; then +sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=y|" \ + -e "s|^VPN_SERVICE=.*|VPN_SERVICE=$vpn_service|" \ + -e "s|^VPN_USER=.*|VPN_USER=$vpn_user|" \ + -e "s|^VPN_PASSWORD=.*|VPN_PASSWORD=$vpn_password|" "$env_file" || \ + log_error "Failed to update VPN configuration in .env" else - send_error_message "Failed to install YAMS CLI. Make sure you have the necessary permissions ❌" +sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=n|" "$env_file" || \ + log_error "Failed to update VPN configuration in .env" fi -if sudo chown -R "$puid":"$pgid" "$media_directory"; then - send_success_message "Media directory ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the media directory. Check permissions ❌" -fi + # Update docker-compose.yaml + log_info "Updating docker-compose configuration..." + sed -i "s||$media_service|g" "$filename" || \ + log_error "Failed to update docker-compose.yaml" -if sudo chown -R "$puid":"$pgid" "$install_directory"; then - send_success_message "Install directory ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the install directory. Check permissions ❌" -fi + # Configure Plex-specific settings + if [ "$media_service" == "plex" ]; then + log_info "Configuring Plex-specific settings..." + sed -i -e 's|#network_mode: host # plex|network_mode: host # plex|g' \ + -e 's|ports: # plex|#ports: # plex|g' \ + -e 's|- 8096:8096 # plex|#- 8096:8096 # plex|g' "$filename" || \ + log_error "Failed to configure Plex settings" + fi -if [[ -d "$install_directory/config" ]]; then - send_success_message "Configuration folder \"$install_directory/config\" exists ✅" -else - if sudo mkdir -p "$install_directory/config"; then - send_success_message "Configuration folder \"$install_directory/config\" created ✅" + # Configure VPN settings if enabled + if [ "${setup_vpn,,}" == "y" ]; then + log_info "Configuring VPN settings..." + sed -i -e "s|vpn_service|$vpn_service|g" \ + -e "s|vpn_user|$vpn_user|g" \ + -e "s|vpn_password|$vpn_password|g" \ + -e 's|#network_mode: "service:gluetun"|network_mode: "service:gluetun"|g' \ + -e 's|ports: # qbittorrent|#ports: # qbittorrent|g' \ + -e 's|ports: # sabnzbd|#ports: # sabnzbd|g' \ + -e 's|- 8081:8081 # qbittorrent|#- 8081:8081 # qbittorrent|g' \ + -e 's|- 8080:8080 # sabnzbd|#- 8080:8080 # sabnzbd|g' \ + -e 's|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g' \ + -e 's|#- 8081:8081/tcp # gluetun|- 8081:8081/tcp # gluetun|g' "$filename" || \ + log_error "Failed to configure VPN settings" + fi + + # Update YAMS CLI script + log_info "Updating YAMS CLI configuration..." + sed -i -e "s||$filename|g" \ + -e "s||$install_directory/docker-compose.custom.yaml|g" \ + -e "s||$install_directory|g" "$yams_script" || \ + log_error "Failed to update YAMS CLI script" +} + +install_cli() { + echo + log_info "Installing YAMS CLI..." + if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then + log_success "YAMS CLI installed successfully ✅" else - send_error_message "Failed to create or access the configuration folder. Check permissions ❌" + log_error "Failed to install YAMS CLI. Check permissions ❌" fi +} + +set_permissions() { + local dirs=("$media_directory" "$install_directory" "$install_directory/config") + + for dir in "${dirs[@]}"; do + log_info "Setting permissions for $dir..." + if [ ! -d "$dir" ]; then + mkdir -p "$dir" || log_error "Failed to create directory $dir" + fi + + if sudo chown -R "$puid:$pgid" "$dir"; then + log_success "Permissions set successfully for $dir ✅" + else + log_error "Failed to set permissions for $dir ❌" + fi + done +} + +# Prevent running as root +if [[ "$EUID" = 0 ]]; then + log_error "YAMS must run without sudo! Please run with regular permissions" fi -if sudo chown -R "$puid":"$pgid" "$install_directory/config"; then - send_success_message "Configuration folder ownership and permissions set successfully ✅" -else - send_error_message "Failed to set ownership and permissions for the configuration folder. Check permissions ❌" +# Check all dependencies +log_info "Checking prerequisites..." +check_dependencies + +# Get user information +get_user_info + +# Get installation paths +get_installation_paths + +# Configure services +configure_media_service +configure_vpn + +log_info "Configuring the docker-compose file for user \"$username\" in \"$install_directory\"..." + +# Copy and update configuration files +copy_configuration_files +update_configuration_files + +log_success "Everything installed correctly! 🎉" + +# Start services +log_info "Starting YAMS services..." +log_info "This may take a while..." + +if ! docker compose -f "$install_directory/docker-compose.yaml" up -d; then + log_error "Failed to start YAMS services" fi +# Install CLI and set permissions +echo +log_info "We need your sudo password to install the YAMS CLI and configure permissions..." +install_cli +set_permissions + printf "\033c" -echo "========================================================" -echo " _____ ___ ___ ___ " -echo " / /::\ / /\ /__/\ / /\ " -echo " / /:/\:\ / /::\ \ \:\ / /:/_ " -echo " / /:/ \:\ / /:/\:\ \ \:\ / /:/ /\ " -echo " /__/:/ \__\:| / /:/ \:\ _____\__\:\ / /:/ /:/_ " -echo " \ \:\ / /:/ /__/:/ \__\:\ /__/::::::::\ /__/:/ /:/ /\\" -echo " \ \:\ /:/ \ \:\ / /:/ \ \:\~~\~~\/ \ \:\/:/ /:/" -echo " \ \:\/:/ \ \:\ /:/ \ \:\ ~~~ \ \::/ /:/ " -echo " \ \::/ \ \:\/:/ \ \:\ \ \:\/:/ " -echo " \__\/ \ \::/ \ \:\ \ \::/ " -echo " \__\/ \__\/ \__\/ " -echo "========================================================" -send_success_message "All done!✅ Enjoy YAMS!" -echo "You can check the installation on $install_directory" -echo "========================================================" -echo "Everything should be running now! To check everything running, go to:" +cat << "EOF" +======================================================== + _____ ___ ___ ___ + / /::\ / /\ /__/\ / /\ + / /:/\:\ / /::\ \ \:\ / /:/_ + / /:/ \:\ / /:/\:\ \ \:\ / /:/ /\ + /__/:/ \__\:| / /:/ \:\ _____\__\:\ / /:/ /:/_ + \ \:\ / /:/ /__/:/ \__\:\ /__/::::::::\ /__/:/ /:/ /\\ + \ \:\ /:/ \ \:\ / /:/ \ \:\~~\~~\/ \ \:\/:/ /:/ + \ \:\/:/ \ \:\ /:/ \ \:\ ~~~ \ \::/ /:/ + \ \::/ \ \:\/:/ \ \:\ \ \:\/:/ + \__\/ \ \::/ \ \:\ \ \::/ + \__\/ \__\/ \__\/ +======================================================== +EOF + +log_success "All done!✅ Enjoy YAMS!" +log_info "You can check the installation in $install_directory" +log_info "========================================================" +log_info "Everything should be running now! To check everything running, go to:" echo + running_services_location + echo +log_info "You might need to wait for a couple of minutes while everything gets up and running" echo -echo "You might need to wait for a couple of minutes while everything gets up and running" -echo -echo "All the services location are also saved in ~/yams_services.txt" +log_info "All the service locations are also saved in ~/yams_services.txt" running_services_location > ~/yams_services.txt -echo "========================================================" + +log_info "========================================================" echo -echo "To configure YAMS, check the documentation at" -echo "https://yams.media/config" +log_info "To configure YAMS, check the documentation at" +log_info "https://yams.media/config" echo -echo "========================================================" +log_info "========================================================" + exit 0 diff --git a/yams b/yams index 4cb5420..272ad24 100755 --- a/yams +++ b/yams @@ -1,142 +1,231 @@ #!/bin/bash set -euo pipefail -dc="docker compose -f -f " -install_directory="" +# Constants +readonly DC="docker compose -f -f " +readonly INSTALL_DIRECTORY="" +readonly TIMEOUT_SECONDS=60 +readonly IP_ENDPOINTS=( + "https://ipinfo.io/ip" + "https://api.ipify.org" + "https://checkip.amazonaws.com" + "https://tnedi.me" + "https://api.myip.la" + "https://wtfismyip.com/text" +) -option=${1:-"--help"} +# Color codes for better readability +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly NC='\033[0m' # No Color -help() { - echo "yams - Yet Another Media Server" - echo - echo "Usage: yams [--help|restart|stop|start|destroy|check-vpn|update]" - echo "options:" - echo "--help displays this help message" - echo "restart restarts yams services" - echo "stop stops all yams services" - echo "start starts yams services" - echo "destroy destroy yams services so you can start from scratch" - echo "check-vpn checks if the VPN is working as expected" - echo "update updates YAMS" +# Available commands +declare -A COMMANDS=( + ["--help"]="displays this help message" + ["restart"]="restarts yams services" + ["stop"]="stops all yams services" + ["start"]="starts yams services" + ["destroy"]="destroy yams services so you can start from scratch" + ["check-vpn"]="checks if the VPN is working as expected" + ["backup"]="backs up yams to the destination location" +) + +# Functions +log_success() { + echo -e "${GREEN}$1${NC}" } -send_success_message() { - echo -e "$(printf "\e[32m$1\e[0m")" +log_error() { + echo -e "${RED}$1${NC}" >&2 + exit 1 } -send_error_message() { - echo -e "$(printf "\e[31m$1\e[0m")" - exit 255 +log_warning() { + echo -e "${YELLOW}$1${NC}" +} + +show_help() { + echo "yams - Yet Another Media Server" + echo + echo "Usage: yams [command] [options]" + echo + echo "Commands:" + for cmd in "${!COMMANDS[@]}"; do + printf "%-25s %s\n" "$cmd" "${COMMANDS[$cmd]}" + done + echo + echo "Examples:" + echo " yams start # Start all YAMS services" + echo " yams backup /path/to/backup # Backup YAMS to specified directory" +} + +wait_for_services() { + local wait_time=0 + echo -n "Waiting for services to start" + + while [ $wait_time -lt $TIMEOUT_SECONDS ]; do + # Get the total number of services and number of running services + local total_services + local running_services + + total_services=$($DC ps --format '{{.Name}}' | wc -l) + running_services=$($DC ps --format '{{.Status}}' | grep -c "Up") + + if [ "$total_services" -eq "$running_services" ]; then + echo + log_success "All $total_services services are up and running!" + return 0 + fi + + # Show progress with count + echo -n "." + sleep 1 + ((wait_time++)) + + # Every 10 seconds, show status + if [ $((wait_time % 10)) -eq 0 ]; then + echo + echo -n "$running_services/$total_services services running" + fi + done + + echo + log_error "Not all services started within ${TIMEOUT_SECONDS} seconds ($running_services/$total_services running)" } find_available_ip_endpoint() { - ip_endpoints=( - "https://ipinfo.io/ip" - "https://api.ipify.org" - "https://checkip.amazonaws.com" - "https://tnedi.me" - "https://api.myip.la" - "https://wtfismyip.com/text" - ) - - for ip in ${ip_endpoints[@]}; do - endpoint=$(curl -s "$ip") - if [ "$endpoint" != "" ]; then - echo $ip - break + for endpoint in "${IP_ENDPOINTS[@]}"; do + if curl -s --connect-timeout 5 "$endpoint" > /dev/null; then + echo "$endpoint" + return 0 fi done + return 1 } -if [ "$option" == "--help" ]; then - help - exit 0 -fi +get_ip_with_retries() { + local context=$1 # "local" or "qbittorrent" + local cmd_prefix="" -if [ "$option" == "restart" ]; then - $dc stop && $dc up -d - echo "YAMS is starting. Wait 1 min until all the services are up and running..." - exit 0 -fi - -if [ "$option" == "stop" ]; then - $dc stop - exit 0 -fi - -if [ "$option" == "start" ]; then - $dc up -d - echo "YAMS is starting. Wait 1 min until all the services are up and running..." - exit 0 -fi - -if [ "$option" == "check-vpn" ]; then - echo "Getting your IP..." - ip_endpoint=$(find_available_ip_endpoint) - if [ "$ip_endpoint" == "" ]; then - send_error_message "No available endpoint to get IP address!" + if [ "$context" = "qbittorrent" ]; then + cmd_prefix="docker exec qbittorrent" fi - your_ip=$(curl -s $ip_endpoint) - echo "$your_ip" - echo "Your local IP country is $(curl -s https://am.i.mullvad.net/country)" - echo - echo - echo "Getting your qBittorrent IP..." - qbittorrent_ip=$(docker exec qbittorrent sh -c "curl -s $ip_endpoint"); - if [ -n "$qbittorrent_ip" ]; then - echo "$qbittorrent_ip" - echo "Your country in qBittorrent is $(docker exec -it qbittorrent sh -c 'curl -s https://am.i.mullvad.net/country')" - if [ "$qbittorrent_ip" == "$your_ip" ]; then - send_error_message "Your IPs are the same! qBittorrent is exposing your IP! ⚠️" + for endpoint in "${IP_ENDPOINTS[@]}"; do + local ip + if [ "$context" = "local" ]; then + ip=$(curl -s --connect-timeout 5 "$endpoint") else - send_success_message "Your IPs are different. qBittorrent is masking your IP! ✅ " + ip=$($cmd_prefix curl -s --connect-timeout 5 "$endpoint") fi + + if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "$ip" + return 0 + fi + done + return 1 +} + +check_vpn() { + echo "Getting your IP..." + local your_ip + your_ip=$(get_ip_with_retries "local") || log_error "Failed to get your IP address from any endpoint" + echo "Your IP: $your_ip" + + local country + country=$(curl -s --connect-timeout 5 "https://am.i.mullvad.net/country") || log_warning "Couldn't determine your country" + [ -n "$country" ] && echo "Your local IP country is $country" + + echo -e "\nGetting your qBittorrent IP..." + local qbit_ip + qbit_ip=$(get_ip_with_retries "qbittorrent") || log_error "Failed to get qBittorrent IP from any endpoint" + echo "qBittorrent IP: $qbit_ip" + + local qbit_country + qbit_country=$(docker exec qbittorrent curl -s --connect-timeout 5 "https://am.i.mullvad.net/country") || log_warning "Couldn't determine qBittorrent country" + [ -n "$qbit_country" ] && echo "qBittorrent country is $qbit_country" + + if [ "$qbit_ip" == "$your_ip" ]; then + log_error "⚠️ WARNING: Your IPs are the same! qBittorrent is exposing your IP!" else - send_error_message "Failed to retrieve qBittorrent IP. Please check your setup. ⚠️" + log_success "✅ Success: Your IPs are different. qBittorrent is masking your IP!" fi -fi +} -if [ "$option" == "destroy" ]; then - echo - echo - read -p "Are you sure you want to destroy all your yams services? THIS IS NOT RECOVERABLE! ⚠️ ️🚨 [y/N]: " destroy_now - destroy_now=${destroy_now:-"n"} - if [ "$destroy_now" == "y" ]; then - $dc down - echo - echo - echo "yams services were destroyed. To restart, run: " - echo "\$ yams start" +backup_yams() { + local destination=$1 + local backup_date + backup_date=$(date '+%Y-%m-%d-%s') + local backup_file="$destination/yams-backup-$backup_date.tar.gz" + + echo "Stopping YAMS services..." + $DC stop > /dev/null 2>&1 || log_error "Failed to stop services" + + echo -e "\nBacking up YAMS to $destination..." + echo "This may take a while depending on the size of your installation." + echo "Please wait... ⌛" + + # Copy current yams script and create backup + cp "$(which yams)" "$INSTALL_DIRECTORY" || log_warning "Failed to backup yams script" + tar --exclude='transcoding-temp' -czf "$backup_file" -C "$INSTALL_DIRECTORY" . || + log_error "Failed to create backup archive" + + echo -e "\nStarting YAMS services..." + $DC start > /dev/null 2>&1 || log_warning "Failed to restart services" + + log_success "Backup completed successfully! 🎉" + echo "Backup file: $backup_file" +} + +destroy_yams() { + echo -e "\nWARNING: This will destroy all your YAMS services!" + read -p "Are you sure you want to continue? This is not recoverable! ⚠️ 🚨 [y/N]: " -r + if [[ ${REPLY,,} =~ ^y$ ]]; then + $DC down || log_error "Failed to destroy services" + echo -e "\nYAMS services were destroyed. To restart, run: yams start" fi -fi +} -if [ "$option" == "update" ]; then - echo "Updating YAMS..." - $dc stop - rm -rf /tmp/yams && mkdir /tmp/yams - wget https://gitlab.com/rogs/yams/-/raw/master/docker-compose.example.yaml -O /tmp/yams/docker-compose.example.yml > /dev/null 2>&1 - source $install_directory/.env +main() { + local command=${1:-"--help"} + local destination=${2:-.} - filename="$install_directory/docker-compose.yaml" - - cp /tmp/yams/docker-compose.example.yml $filename - - - sed -i -e "s;;$MEDIA_SERVICE;g" "$filename" - if [ "$MEDIA_SERVICE" == "plex" ]; then - sed -i -e "s|#network_mode: host # plex|network_mode: host # plex|g" "$filename" \ - -e "s|ports: # plex|#ports: # plex|g" $filename \ - -e "s|- 8096:8096 # plex|#- 8096:8096 # plex|g" $filename + # Validate and normalize destination path if provided + if [ "$command" = "backup" ]; then + destination=$(realpath "$destination") || log_error "Invalid backup destination path" fi - if [ "$VPN_ENABLED" == "y" ]; then - sed -i -e "s;#network_mode: \"service:gluetun\";network_mode: \"service:gluetun\";g" "$filename" \ - -e "s;ports: # qbittorrent;#port: # qbittorrent;g" "$filename" \ - -e "s;- 8080:8080 # qbittorrent;#- 8080:8080 # qbittorrent;g" "$filename" \ - -e "s;#- 8080:8080/tcp # gluetun;- 8080:8080/tcp # gluetun;g" "$filename" - fi + case "$command" in + --help) + show_help + ;; + restart) + $DC stop && $DC up -d + wait_for_services + ;; + stop) + $DC stop || log_error "Failed to stop services" + log_success "Services stopped successfully" + ;; + start) + $DC up -d || log_error "Failed to start services" + wait_for_services + ;; + check-vpn) + check_vpn + ;; + destroy) + destroy_yams + ;; + backup) + backup_yams "$destination" + ;; + *) + log_error "Unknown command: $command\nRun 'yams --help' for usage information" + ;; + esac +} - $dc up -d - echo "YAMS was updated and it is starting. Wait 1 min until all the services are up and running..." -fi +main "$@"