V3 - The big one #71

Merged
rogs merged 31 commits from v3 into master 2024-12-30 11:01:29 -03:00
6 changed files with 1052 additions and 749 deletions

Binary file not shown.

View File

@ -1,4 +1,2 @@
version: "3"
# services:
# Add your custom services here!

View File

@ -1,5 +1,3 @@
version: "3"
services:
# <media_service> is used to serve your media to the client devices
<media_service>:
@ -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

823
docs.org
View File

@ -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|<your_PUID>|$puid|g" "$env_file" \
-e "s|<your_PGID>|$pgid|g" "$env_file" \
-e "s|<media_directory>|$media_directory|g" "$env_file" \
-e "s|<media_service>|$media_service|g" "$env_file" \
-e "s|<media_service>|$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>|$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>|$filename|g" yams \
-e "s|<custom_file_filename>|$custom_file_filename|g" yams \
-e "s|<install_directory>|$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|<your_PUID>|$puid|g" \
-e "s|<your_PGID>|$pgid|g" \
-e "s|<media_directory>|$media_directory|g" \
-e "s|<media_service>|$media_service|g" \
-e "s|<install_directory>|$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>|$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>|$filename|g" \
-e "s|<custom_file_filename>|$install_directory/docker-compose.custom.yaml|g" \
-e "s|<install_directory>|$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

View File

@ -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|<your_PUID>|$puid|g" "$env_file" \
-e "s|<your_PGID>|$pgid|g" "$env_file" \
-e "s|<media_directory>|$media_directory|g" "$env_file" \
-e "s|<media_service>|$media_service|g" "$env_file" \
-e "s|<media_service>|$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>|$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>|$filename|g" yams \
-e "s|<custom_file_filename>|$custom_file_filename|g" yams \
-e "s|<install_directory>|$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|<your_PUID>|$puid|g" \
-e "s|<your_PGID>|$pgid|g" \
-e "s|<media_directory>|$media_directory|g" \
-e "s|<media_service>|$media_service|g" \
-e "s|<install_directory>|$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>|$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>|$filename|g" \
-e "s|<custom_file_filename>|$install_directory/docker-compose.custom.yaml|g" \
-e "s|<install_directory>|$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

313
yams
View File

@ -1,142 +1,231 @@
#!/bin/bash
set -euo pipefail
dc="docker compose -f <filename> -f <custom_file_filename>"
install_directory="<install_directory>"
# Constants
readonly DC="docker compose -f <filename> -f <custom_file_filename>"
readonly INSTALL_DIRECTORY="<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>;$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 "$@"