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: # services:
# Add your custom services here! # Add your custom services here!

View File

@ -1,5 +1,3 @@
version: "3"
services: services:
# <media_service> is used to serve your media to the client devices # <media_service> is used to serve your media to the client devices
<media_service>: <media_service>:
@ -11,8 +9,8 @@ services:
- PGID=${PGID} - PGID=${PGID}
- VERSION=docker - VERSION=docker
volumes: volumes:
- ${MEDIA_DIRECTORY}/movies:/data/movies - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/tvshows:/data/tvshows - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/${MEDIA_SERVICE}:/config - ${INSTALL_DIRECTORY}/config/${MEDIA_SERVICE}:/config
ports: # plex ports: # plex
- 8096:8096 # plex - 8096:8096 # plex
@ -20,18 +18,36 @@ services:
# qBitorrent is used to download torrents # qBitorrent is used to download torrents
qbittorrent: qbittorrent:
image: lscr.io/linuxserver/qbittorrent:4.6.0 image: lscr.io/linuxserver/qbittorrent
container_name: qbittorrent container_name: qbittorrent
environment: environment:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
- WEBUI_PORT=8080 - WEBUI_PORT=8081
volumes: volumes:
- ${MEDIA_DIRECTORY}/downloads:/downloads - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/qbittorrent:/config - ${INSTALL_DIRECTORY}/config/qbittorrent:/config
restart: unless-stopped restart: unless-stopped
ports: # qbittorrent 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" #network_mode: "service:gluetun"
# Sonarr is used to query, add downloads to the download queue and index TV shows # Sonarr is used to query, add downloads to the download queue and index TV shows
@ -43,8 +59,8 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- ${MEDIA_DIRECTORY}/tvshows:/tv - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/downloads:/downloads - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/sonarr:/config - ${INSTALL_DIRECTORY}/config/sonarr:/config
ports: ports:
- 8989:8989 - 8989:8989
@ -59,8 +75,8 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- ${MEDIA_DIRECTORY}/movies:/movies - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/downloads:/downloads - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/radarr:/config - ${INSTALL_DIRECTORY}/config/radarr:/config
ports: ports:
- 7878:7878 - 7878:7878
@ -75,8 +91,8 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- ${MEDIA_DIRECTORY}/music:/music - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/downloads:/downloads - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/lidarr:/config - ${INSTALL_DIRECTORY}/config/lidarr:/config
ports: ports:
- 8686:8686 - 8686:8686
@ -91,8 +107,8 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- ${MEDIA_DIRECTORY}/books:/books - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/downloads:/downloads - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/readarr:/config - ${INSTALL_DIRECTORY}/config/readarr:/config
ports: ports:
- 8787:8787 - 8787:8787
@ -107,8 +123,8 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- ${MEDIA_DIRECTORY}/movies:/movies - /etc/localtime:/etc/localtime:ro
- ${MEDIA_DIRECTORY}/tvshows:/tv - ${MEDIA_DIRECTORY}:/data
- ${INSTALL_DIRECTORY}/config/bazarr:/config - ${INSTALL_DIRECTORY}/config/bazarr:/config
ports: ports:
- 6767:6767 - 6767:6767
@ -123,6 +139,7 @@ services:
- PUID=${PUID} - PUID=${PUID}
- PGID=${PGID} - PGID=${PGID}
volumes: volumes:
- /etc/localtime:/etc/localtime:ro
- ${INSTALL_DIRECTORY}/config/prowlarr:/config - ${INSTALL_DIRECTORY}/config/prowlarr:/config
ports: ports:
- 9696:9696 - 9696:9696
@ -140,15 +157,17 @@ services:
- 8888:8888/tcp # HTTP proxy - 8888:8888/tcp # HTTP proxy
- 8388:8388/tcp # Shadowsocks - 8388:8388/tcp # Shadowsocks
- 8388:8388/udp # Shadowsocks - 8388:8388/udp # Shadowsocks
- 8003:8000/tcp # Admin
#- 8080:8080/tcp # gluetun #- 8080:8080/tcp # gluetun
volumes: #- 8081:8081/tcp # gluetun
- ${INSTALL_DIRECTORY}/config/gluetun:/config
environment: environment:
- VPN_SERVICE_PROVIDER=${VPN_SERVICE} - VPN_SERVICE_PROVIDER=${VPN_SERVICE}
- VPN_TYPE=openvpn - VPN_TYPE=openvpn
- OPENVPN_USER=${VPN_USER} - OPENVPN_USER=${VPN_USER}
- OPENVPN_PASSWORD=${VPN_PASSWORD} - OPENVPN_PASSWORD=${VPN_PASSWORD}
- OPENVPN_CIPHERS=AES-256-GCM - OPENVPN_CIPHERS=AES-256-GCM
- PORT_FORWARD_ONLY=on
- VPN_PORT_FORWARDING=on
restart: unless-stopped restart: unless-stopped
# Portainer helps debugging and monitors the containers # Portainer helps debugging and monitors the containers

805
docs.org
View File

@ -6,37 +6,24 @@
:PROPERTIES: :PROPERTIES:
:ID: faf95c8a-9133-4072-8544-0ef456a67611 :ID: faf95c8a-9133-4072-8544-0ef456a67611
:END: :END:
- [[#welcome-message][Welcome message]] - [[#welcome-message][Welcome message]]
- [[#constants-and-configuration][Constants and Configuration]]
- [[#functions][Functions]] - [[#functions][Functions]]
- [[#message-formatting][Message formatting]] - [[#message-formatting][Message formatting]]
- [[#check-the-dependencies][Check the dependencies]] - [[#directory-handling][Directory Handling]]
- [[#running-services-location][Running services location]] - [[#check-dependencies][Check Dependencies]]
- [[#verify-all-the-dependencies][Verify all the dependencies]] - [[#service-configuration][Service Configuration]]
- [[#gather-all-the-required-information][Gather all the required information]] - [[#file-operations][File Operations]]
- [[#checking-install-location][Checking install location]] - [[#script-execution][Script Execution]]
- [[#setting-the-correct-user][Setting the correct user]] - [[#verify-prerequisites][Verify Prerequisites]]
- [[#media-directory][Media directory]] - [[#installation-process][Installation Process]]
- [[#setting-perferred-media-service][Setting perferred media service]] - [[#display-closing-message][Display Closing Message]]
- [[#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]]
* Welcome message * Welcome message
:PROPERTIES: :PROPERTIES:
:ID: 525c03eb-cab9-44f8-8cc5-e5ec9035a938 :ID: 525c03eb-cab9-44f8-8cc5-e5ec9035a938
:END: :END:
This is just a welcome message for the script
#+begin_src bash #+begin_src bash
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
@ -64,264 +51,234 @@ echo "===================================================="
echo "" echo ""
#+end_src #+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 * Functions
:PROPERTIES: :PROPERTIES:
:ID: 111a7df4-08f5-4e6c-a799-dd822c5d030e :ID: 111a7df4-08f5-4e6c-a799-dd822c5d030e
:END: :END:
To make development easier, we declare some functions that are going to be used a lot later
** Message formatting ** Message formatting
:PROPERTIES: :PROPERTIES:
:ID: 61387bd4-2ecf-44fe-ac69-dc6347c0d1b8 :ID: 61387bd4-2ecf-44fe-ac69-dc6347c0d1b8
:END: :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 #+begin_src bash
send_success_message() { log_success() {
echo -e $(printf "\e[32m$1\e[0m") 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 #+end_src
*** Error ** Directory Handling
:PROPERTIES: :PROPERTIES:
:ID: 1a6cd951-c9ce-46fc-8953-f5e206f7cd23 :ID: new-directory-section
:END: :END:
Error is basically the same as before, but it ~exit 255~ to finish the execution.
#+begin_src bash #+begin_src bash
send_error_message() { create_and_verify_directory() {
echo -e $(printf "\e[31m$1\e[0m") local dir="$1"
exit 255 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 #+end_src
** Check the dependencies ** Check Dependencies
:PROPERTIES: :PROPERTIES:
:ID: e7d01eeb-c7ef-42ff-b60d-010be30bc6a8 :ID: e7d01eeb-c7ef-42ff-b60d-010be30bc6a8
:END: :END:
This function verifies that the dependencies are installed. ~Docker~ and ~Docker Compose~ are required
for YAMS to work.
#+begin_src bash #+begin_src bash
check_dependencies() { check_dependencies() {
if command -v docker &> /dev/null; then local missing_packages=()
send_success_message "docker exists ✅ " local install_cmd=""
if docker compose version &> /dev/null; then
send_success_message "docker compose exists ✅ " # 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 else
echo -e $(printf "\e[31m ⚠️ docker compose not found! ⚠️\e[0m") log_success "$pkg exists ✅"
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 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]: " 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 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 #+end_src
* Verify all the dependencies ** Service Configuration
:PROPERTIES: :PROPERTIES:
:ID: e945d5a8-5142-41fe-8175-96de7aa84cf2 :ID: new-service-section
:END: :END:
#+begin_src bash #+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
check_dependencies media_service=${media_service:-$DEFAULT_MEDIA_SERVICE}
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 ❌"
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 ✅"
else
send_error_message "There was an error creating the installation directory at \"$media_directory\". Make sure you have the necessary permissions ❌"
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
** Setting perferred media service
:PROPERTIES:
:ID: 3af8dbed-3a88-4739-a721-6434993c0b67
:END:
#+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)"
read -p "Choose your media service [jellyfin]: " media_service
media_service=${media_service:-"jellyfin"}
media_service=$(echo "$media_service" | awk '{print tolower($0)}') media_service=$(echo "$media_service" | awk '{print tolower($0)}')
media_service_port=8096 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 if [ "$media_service" == "plex" ]; then
media_service_port=32400 media_service_port=32400
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 else
send_error_message "\"$media_service\" is not supported by YAMS. Are you sure you chose the correct service?" media_service_port=8096
fi fi
#+end_src
** Setting the VPN echo
:PROPERTIES: log_success "YAMS will install \"$media_service\" on port \"$media_service_port\""
:ID: 1da4fe67-ee20-4b70-8f36-4a9f7161b6ca
:END:
#+begin_src bash # Export for use in other functions
echo -e "\nTime to set up the VPN." export media_service media_service_port
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 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"} setup_vpn=${setup_vpn:-"y"}
if [ "$setup_vpn" == "y" ]; then if [ "${setup_vpn,,}" != "y" ]; then
read -p "What's your VPN service? (with spaces) [mullvad]: " vpn_service export setup_vpn="n"
vpn_service=${vpn_service:-"mullvad"} return 0
fi
echo -e "\nYou should read $vpn_service's documentation in case it has different configurations for username and password." read -p "VPN service? (with spaces) [$DEFAULT_VPN_SERVICE]: " vpn_service
echo "The documentation for $vpn_service is here: https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" vpn_service=${vpn_service:-$DEFAULT_VPN_SERVICE}
read -p "What's your VPN username? (without spaces): " vpn_user 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 unset vpn_password
charcount=0 charcount=0
prompt="What's your VPN password? (if you are using mullvad, just enter your username again): " prompt="VPN password (if using mullvad, enter username again): "
while IFS= read -p "$prompt" -r -s -n 1 char while IFS= read -p "$prompt" -r -s -n 1 char; do
do if [[ $char == $'\0' ]]; then
if [[ $char == $'\0' ]]
then
break break
fi fi
if [[ $char == $'\177' ]]; then if [[ $char == $'\177' ]]; then
@ -339,173 +296,253 @@ if [ "$setup_vpn" == "y" ]; then
fi fi
done done
echo 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"
#+end_src
* Installing YAMS # Export for use in other functions
:PROPERTIES: export vpn_service vpn_user vpn_password setup_vpn
:ID: 44e5f3f1-3ae7-4f88-ba96-8149c9980fb2 }
:END:
** Copy the docker-compose file to the install location
:PROPERTIES:
:ID: 09018e25-ed48-46e9-85c3-586c37844c11
:END:
#+begin_src bash running_services_location() {
copy_files=( local host_ip
"docker-compose.example.yaml:$filename" host_ip=$(hostname -I | awk '{ print $1 }')
".env.example:$env_file"
"docker-compose.custom.yaml:$custom_file_filename" 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"
) )
for file_mapping in "${copy_files[@]}"; do echo -e "Service URLs:"
source_file="${file_mapping%%:*}" for service in "${!services[@]}"; do
destination_file="${file_mapping##*:}" echo "$service: http://$host_ip:${services[$service]}/"
done
}
echo -e "\nCopying $source_file to $destination_file..." get_user_info() {
if cp "$source_file" "$destination_file"; then read -p "User to own the media server files? [$USER]: " username
send_success_message "$source_file was copied successfuly! ✅" username=${username:-$USER}
if id -u "$username" &>/dev/null; then
puid=$(id -u "$username")
pgid=$(id -g "$username")
else 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
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
** File Operations
:PROPERTIES:
:ID: new-file-operations-section
:END:
#+begin_src bash
copy_configuration_files() {
local -A files=(
["docker-compose.example.yaml"]="docker-compose.yaml"
[".env.example"]=".env"
["docker-compose.custom.yaml"]="docker-compose.custom.yaml"
)
for src in "${!files[@]}"; do
local dest="$install_directory/${files[$src]}"
echo
log_info "Copying $src to $dest..."
if cp "$src" "$dest"; then
log_success "$src copied successfully ✅"
else
log_error "Failed to copy $src to $dest. Check permissions ❌"
fi fi
done done
#+end_src }
#+RESULTS: update_configuration_files() {
local filename="$install_directory/docker-compose.yaml"
local env_file="$install_directory/.env"
local yams_script="yams"
** Set PUID, PGID, Media Folder, Media Service, Config folder and VPN on the YAMS scripts # Update .env file
:PROPERTIES: log_info "Updating environment configuration..."
:ID: 3d169001-f0f7-477f-a954-0460484f4b43 sed -i -e "s|<your_PUID>|$puid|g" \
:END: -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"
This steps prepares all the files with the correct information that was collected on the "[[#gather-all-the-required-information][Gather all the # Update VPN configuration in .env file
required information]]" step. 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
sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=n|" "$env_file" || \
log_error "Failed to update VPN configuration in .env"
fi
#+begin_src bash # Update docker-compose.yaml
sed -i -e "s|<your_PUID>|$puid|g" "$env_file" \ log_info "Updating docker-compose configuration..."
-e "s|<your_PGID>|$pgid|g" "$env_file" \ sed -i "s|<media_service>|$media_service|g" "$filename" || \
-e "s|<media_directory>|$media_directory|g" "$env_file" \ log_error "Failed to update docker-compose.yaml"
-e "s|<media_service>|$media_service|g" "$env_file" \
-e "s|<media_service>|$media_service|g" "$filename"
# Configure Plex-specific settings
if [ "$media_service" == "plex" ]; then if [ "$media_service" == "plex" ]; then
sed -i -e "s|#network_mode: host # plex|network_mode: host # plex|g" "$filename" \ log_info "Configuring Plex-specific settings..."
-e "s|ports: # plex|#ports: # plex|g" "$filename" \ sed -i -e 's|#network_mode: host # plex|network_mode: host # plex|g' \
-e "s|- 8096:8096 # plex|#- 8096:8096 # plex|g" "$filename" -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 fi
sed -i -e "s|<install_directory>|$install_directory|g" "$env_file" \ # Configure VPN settings if enabled
-e "s|vpn_enabled|$setup_vpn|g" "$env_file" \ if [ "${setup_vpn,,}" == "y" ]; then
log_info "Configuring VPN settings..."
if [ "$setup_vpn" == "y" ]; then sed -i -e "s|vpn_service|$vpn_service|g" \
sed -i -e "s|vpn_service|$vpn_service|g" "$env_file" \ -e "s|vpn_user|$vpn_user|g" \
-e "s|vpn_user|$vpn_user|g" "$env_file" \ -e "s|vpn_password|$vpn_password|g" \
-e "s|vpn_password|$vpn_password|g" "$env_file" \ -e 's|#network_mode: "service:gluetun"|network_mode: "service:gluetun"|g' \
-e "s|#network_mode: \"service:gluetun\"|network_mode: \"service:gluetun\"|g" "$filename" \ -e 's|ports: # qbittorrent|#ports: # qbittorrent|g' \
-e "s|ports: # qbittorrent|#ports: # qbittorrent|g" "$filename" \ -e 's|ports: # sabnzbd|#ports: # sabnzbd|g' \
-e "s|- 8080:8080 # qbittorrent|#- 8080:8080 # qbittorrent|g" "$filename" \ -e 's|- 8081:8081 # qbittorrent|#- 8081:8081 # qbittorrent|g' \
-e "s|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g" "$filename" -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 fi
#+end_src
** Set the configuration for the YAMS binary # Update YAMS CLI script
:PROPERTIES: log_info "Updating YAMS CLI configuration..."
:ID: b6a8732f-9dbe-4d93-b04d-27156eacdea2 sed -i -e "s|<filename>|$filename|g" \
:END: -e "s|<custom_file_filename>|$install_directory/docker-compose.custom.yaml|g" \
-e "s|<install_directory>|$install_directory|g" "$yams_script" || \
#+begin_src bash log_error "Failed to update YAMS CLI script"
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
** Success message!
:PROPERTIES:
:ID: 7b0ed8f5-780b-4685-8123-8d5c4229eaba
:END:
Finally, YAMS is installed 🔥. Show the success message
#+begin_src bash
send_success_message "Everything installed correctly! 🎉"
echo "Running the server..."
echo "This is going to take a while..."
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..."
install_cli() {
echo
log_info "Installing YAMS CLI..."
if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then
send_success_message "YAMS CLI installed successfully ✅" log_success "YAMS CLI installed successfully ✅"
else else
send_error_message "Failed to install YAMS CLI. Make sure you have the necessary permissions ❌" log_error "Failed to install YAMS CLI. Check permissions ❌"
fi 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 #+end_src
** Set the correct permissions to the media and install directories * Script Execution
:PROPERTIES: :PROPERTIES:
:ID: 4cfb9397-776d-46db-84cc-54b78395cba8 :ID: new-script-execution
:END: :END:
This adds the correct permissions to the media folder, in case they are not correct. ** Verify Prerequisites
#+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 ❌"
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
** Create the config directory
:PROPERTIES: :PROPERTIES:
:ID: 699f35fe-edde-406d-be0b-3ff2eaa6d7eb :ID: e945d5a8-5142-41fe-8175-96de7aa84cf2
:END: :END:
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.
#+begin_src bash #+begin_src bash
if [[ -d "$install_directory/config" ]]; then # Prevent running as root
send_success_message "Configuration folder \"$install_directory/config\" exists ✅" if [[ "$EUID" = 0 ]]; then
else log_error "YAMS must run without sudo! Please run with regular permissions"
if sudo mkdir -p "$install_directory/config"; then
send_success_message "Configuration folder \"$install_directory/config\" created ✅"
else
send_error_message "Failed to create or access the configuration folder. Check permissions ❌"
fi
fi fi
if sudo chown -R "$puid":"$pgid" "$install_directory/config"; then # Check all dependencies
send_success_message "Configuration folder ownership and permissions set successfully ✅" log_info "Checking prerequisites..."
else check_dependencies
send_error_message "Failed to set ownership and permissions for the configuration folder. Check permissions ❌"
fi
#+end_src #+end_src
* Display closing message ** 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: :PROPERTIES:
:ID: 238e3eae-9df7-4a7f-a460-7a61c07b5442 :ID: 238e3eae-9df7-4a7f-a460-7a61c07b5442
:END: :END:
@ -513,36 +550,42 @@ fi
#+begin_src bash #+begin_src bash
printf "\033c" printf "\033c"
echo "========================================================" cat << "EOF"
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" EOF
echo "========================================================"
echo "Everything should be running now! To check everything running, go to:" 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 echo
running_services_location running_services_location
echo echo
log_info "You might need to wait for a couple of minutes while everything gets up and running"
echo echo
echo "You might need to wait for a couple of minutes while everything gets up and running" log_info "All the service locations are also saved in ~/yams_services.txt"
echo
echo "All the services location are also saved in ~/yams_services.txt"
running_services_location > ~/yams_services.txt running_services_location > ~/yams_services.txt
echo "========================================================"
log_info "========================================================"
echo echo
echo "To configure YAMS, check the documentation at" log_info "To configure YAMS, check the documentation at"
echo "https://yams.media/config" log_info "https://yams.media/config"
echo echo
echo "========================================================" log_info "========================================================"
exit 0 exit 0
#+end_src #+end_src

View File

@ -23,171 +23,195 @@ echo "To finish the installation of the CLI"
echo "====================================================" echo "===================================================="
echo "" echo ""
send_success_message() { # Constants
echo -e $(printf "\e[32m$1\e[0m") 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() { log_error() {
echo -e $(printf "\e[31m$1\e[0m") echo -e "${RED}$1${NC}" >&2
exit 255 exit 1
} }
check_dependencies() { log_warning() {
if command -v docker &> /dev/null; then echo -e "${YELLOW}$1${NC}"
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"}
if [ "$install_docker" == "y" ]; then log_info() {
bash ./docker.sh echo "$1"
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"}
if [ "$install_docker" == "y" ]; then create_and_verify_directory() {
bash ./docker.sh 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 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
fi fi
if [ ! -w "$dir" ] || [ ! -r "$dir" ]; then
log_error "Directory \"$dir\" is not writable or readable. Check permissions ❌"
fi
} }
running_services_location() { setup_directory_structure() {
host_ip=$(hostname -I | awk '{ print $1 }') local media_dir="$1"
services=( create_and_verify_directory "$media_dir" "media"
"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 subdir in "${MEDIA_SUBDIRS[@]}"; do
for service in "${services[@]}"; do create_and_verify_directory "$media_dir/$subdir" "media subdirectory"
service_name="${service%%:*}"
service_port="${service##*:}"
echo "$service_name: http://$host_ip:$service_port/"
done done
} }
echo "Checking prerequisites..." verify_user_permissions() {
local username="$1"
local directory="$2"
if ! id -u "$username" &>/dev/null; then
check_dependencies log_error "User \"$username\" doesn't exist!"
if [[ "$EUID" = 0 ]]; then
send_error_message "YAMS has to run without sudo! Please, run it again with regular permissions"
fi fi
default_install_directory="/opt/yams" if ! sudo -u "$username" test -w "$directory"; then
log_error "User \"$username\" doesn't have write permissions to \"$directory\""
fi
}
read -p "Where do you want to install the docker-compose file? [$default_install_directory]: " install_directory check_dependencies() {
install_directory=${install_directory:-$default_install_directory} local missing_packages=()
local install_cmd=""
if [ ! -d "$install_directory" ]; then # Check for required commands and collect missing ones
echo "The directory \"$install_directory\" does not exists. Attempting to create..." for pkg in "${REQUIRED_COMMANDS[@]}"; do
if mkdir -p "$install_directory"; then if ! command -v "$pkg" &> /dev/null; then
send_success_message "Directory $install_directory created ✅" missing_packages+=("$pkg")
else else
send_error_message "There was an error creating the installation directory at \"$install_directory\". Make sure you have the necessary permissions ❌" log_success "$pkg exists ✅"
fi fi
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 fi
log_success "Successfully installed missing packages ✅"
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 else
send_error_message "The user \"$username\" doesn't exist!" log_error "Please install the required packages manually: ${missing_packages[*]}"
fi
fi fi
read -p "Please, input your media directory [/srv/media]: " media_directory # Check Docker and Docker Compose
media_directory=${media_directory:-"/srv/media"} 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
read -p "Are you sure your media directory is \"$media_directory\"? (y/N) [Default = n]: " media_directory_correct log_warning "⚠️ Docker/Docker Compose not found! ⚠️"
media_directory_correct=${media_directory_correct:-"n"} read -p "Install Docker and Docker Compose? Only works on Debian/Ubuntu (y/N) [Default = n]: " install_docker
install_docker=${install_docker:-"n"}
if [ ! -d "$media_directory" ]; then if [ "${install_docker,,}" = "y" ]; then
echo "The directory \"$media_directory\" does not exists. Attempting to create..." bash ./docker.sh
if mkdir -p "$media_directory"; then
send_success_message "Directory $media_directory created ✅"
else else
send_error_message "There was an error creating the installation directory at \"$media_directory\". Make sure you have the necessary permissions ❌" log_error "Please install Docker and Docker Compose first"
fi
fi fi
}
if [ "$media_directory_correct" == "n" ]; then configure_media_service() {
send_error_message "Media directory is not correct. Please fix it and run the script again ❌" echo
fi 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 "\n\n\nTime to choose your media service." read -p "Choose your media service [$DEFAULT_MEDIA_SERVICE]: " media_service
echo "Your media service is responsible for serving your files to your network." media_service=${media_service:-$DEFAULT_MEDIA_SERVICE}
echo "By default, YAMS supports 3 media services:"
echo "- jellyfin (recommended, easier)"
echo "- emby"
echo "- plex (advanced, always online)"
read -p "Choose your media service [jellyfin]: " media_service
media_service=${media_service:-"jellyfin"}
media_service=$(echo "$media_service" | awk '{print tolower($0)}') media_service=$(echo "$media_service" | awk '{print tolower($0)}')
media_service_port=8096 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 if [ "$media_service" == "plex" ]; then
media_service_port=32400 media_service_port=32400
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 else
send_error_message "\"$media_service\" is not supported by YAMS. Are you sure you chose the correct service?" media_service_port=8096
fi fi
echo -e "\nTime to set up the VPN." echo
echo "You can check the supported VPN list here: https://yams.media/advanced/vpn." log_success "YAMS will install \"$media_service\" on port \"$media_service_port\""
read -p "Do you want to configure a VPN? (Y/n) [Default = y]: " setup_vpn # 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"} setup_vpn=${setup_vpn:-"y"}
if [ "$setup_vpn" == "y" ]; then if [ "${setup_vpn,,}" != "y" ]; then
read -p "What's your VPN service? (with spaces) [mullvad]: " vpn_service export setup_vpn="n"
vpn_service=${vpn_service:-"mullvad"} return 0
fi
echo -e "\nYou should read $vpn_service's documentation in case it has different configurations for username and password." read -p "VPN service? (with spaces) [$DEFAULT_VPN_SERVICE]: " vpn_service
echo "The documentation for $vpn_service is here: https://github.com/qdm12/gluetun-wiki/blob/main/setup/providers/${vpn_service// /-}.md" vpn_service=${vpn_service:-$DEFAULT_VPN_SERVICE}
read -p "What's your VPN username? (without spaces): " vpn_user 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 unset vpn_password
charcount=0 charcount=0
prompt="What's your VPN password? (if you are using mullvad, just enter your username again): " prompt="VPN password (if using mullvad, enter username again): "
while IFS= read -p "$prompt" -r -s -n 1 char while IFS= read -p "$prompt" -r -s -n 1 char; do
do if [[ $char == $'\0' ]]; then
if [[ $char == $'\0' ]]
then
break break
fi fi
if [[ $char == $'\177' ]]; then if [[ $char == $'\177' ]]; then
@ -205,131 +229,261 @@ if [ "$setup_vpn" == "y" ]; then
fi fi
done done
echo 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=( # Export for use in other functions
"docker-compose.example.yaml:$filename" export vpn_service vpn_user vpn_password setup_vpn
".env.example:$env_file" }
"docker-compose.custom.yaml:$custom_file_filename"
running_services_location() {
local host_ip
host_ip=$(hostname -I | awk '{ print $1 }')
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"
) )
for file_mapping in "${copy_files[@]}"; do echo -e "Service URLs:"
source_file="${file_mapping%%:*}" for service in "${!services[@]}"; do
destination_file="${file_mapping##*:}" echo "$service: http://$host_ip:${services[$service]}/"
done
}
echo -e "\nCopying $source_file to $destination_file..." get_user_info() {
if cp "$source_file" "$destination_file"; then read -p "User to own the media server files? [$USER]: " username
send_success_message "$source_file was copied successfuly! ✅" username=${username:-$USER}
if id -u "$username" &>/dev/null; then
puid=$(id -u "$username")
pgid=$(id -g "$username")
else 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
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
}
copy_configuration_files() {
local -A files=(
["docker-compose.example.yaml"]="docker-compose.yaml"
[".env.example"]=".env"
["docker-compose.custom.yaml"]="docker-compose.custom.yaml"
)
for src in "${!files[@]}"; do
local dest="$install_directory/${files[$src]}"
echo
log_info "Copying $src to $dest..."
if cp "$src" "$dest"; then
log_success "$src copied successfully ✅"
else
log_error "Failed to copy $src to $dest. Check permissions ❌"
fi fi
done done
}
sed -i -e "s|<your_PUID>|$puid|g" "$env_file" \ update_configuration_files() {
-e "s|<your_PGID>|$pgid|g" "$env_file" \ local filename="$install_directory/docker-compose.yaml"
-e "s|<media_directory>|$media_directory|g" "$env_file" \ local env_file="$install_directory/.env"
-e "s|<media_service>|$media_service|g" "$env_file" \ local yams_script="yams"
-e "s|<media_service>|$media_service|g" "$filename"
# 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
sed -i -e "s|^VPN_ENABLED=.*|VPN_ENABLED=n|" "$env_file" || \
log_error "Failed to update VPN configuration in .env"
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"
# Configure Plex-specific settings
if [ "$media_service" == "plex" ]; then if [ "$media_service" == "plex" ]; then
sed -i -e "s|#network_mode: host # plex|network_mode: host # plex|g" "$filename" \ log_info "Configuring Plex-specific settings..."
-e "s|ports: # plex|#ports: # plex|g" "$filename" \ sed -i -e 's|#network_mode: host # plex|network_mode: host # plex|g' \
-e "s|- 8096:8096 # plex|#- 8096:8096 # plex|g" "$filename" -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 fi
sed -i -e "s|<install_directory>|$install_directory|g" "$env_file" \ # Configure VPN settings if enabled
-e "s|vpn_enabled|$setup_vpn|g" "$env_file" \ if [ "${setup_vpn,,}" == "y" ]; then
log_info "Configuring VPN settings..."
if [ "$setup_vpn" == "y" ]; then sed -i -e "s|vpn_service|$vpn_service|g" \
sed -i -e "s|vpn_service|$vpn_service|g" "$env_file" \ -e "s|vpn_user|$vpn_user|g" \
-e "s|vpn_user|$vpn_user|g" "$env_file" \ -e "s|vpn_password|$vpn_password|g" \
-e "s|vpn_password|$vpn_password|g" "$env_file" \ -e 's|#network_mode: "service:gluetun"|network_mode: "service:gluetun"|g' \
-e "s|#network_mode: \"service:gluetun\"|network_mode: \"service:gluetun\"|g" "$filename" \ -e 's|ports: # qbittorrent|#ports: # qbittorrent|g' \
-e "s|ports: # qbittorrent|#ports: # qbittorrent|g" "$filename" \ -e 's|ports: # sabnzbd|#ports: # sabnzbd|g' \
-e "s|- 8080:8080 # qbittorrent|#- 8080:8080 # qbittorrent|g" "$filename" \ -e 's|- 8081:8081 # qbittorrent|#- 8081:8081 # qbittorrent|g' \
-e "s|#- 8080:8080/tcp # gluetun|- 8080:8080/tcp # gluetun|g" "$filename" -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 fi
sed -i -e "s|<filename>|$filename|g" yams \ # Update YAMS CLI script
-e "s|<custom_file_filename>|$custom_file_filename|g" yams \ log_info "Updating YAMS CLI configuration..."
-e "s|<install_directory>|$install_directory|g" yams sed -i -e "s|<filename>|$filename|g" \
-e "s|<custom_file_filename>|$install_directory/docker-compose.custom.yaml|g" \
send_success_message "Everything installed correctly! 🎉" -e "s|<install_directory>|$install_directory|g" "$yams_script" || \
log_error "Failed to update YAMS CLI script"
echo "Running the server..." }
echo "This is going to take a while..."
docker compose -f "$filename" up -d
echo -e "\nWe need your sudo password to install the YAMS CLI and configure permissions..."
install_cli() {
echo
log_info "Installing YAMS CLI..."
if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then if sudo cp yams /usr/local/bin/yams && sudo chmod +x /usr/local/bin/yams; then
send_success_message "YAMS CLI installed successfully ✅" log_success "YAMS CLI installed successfully ✅"
else else
send_error_message "Failed to install YAMS CLI. Make sure you have the necessary 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 fi
if sudo chown -R "$puid":"$pgid" "$media_directory"; then if sudo chown -R "$puid:$pgid" "$dir"; then
send_success_message "Media directory ownership and permissions set successfully ✅" log_success "Permissions set successfully for $dir"
else else
send_error_message "Failed to set ownership and permissions for the media directory. Check permissions ❌" 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 fi
if sudo chown -R "$puid":"$pgid" "$install_directory"; then # Check all dependencies
send_success_message "Install directory ownership and permissions set successfully ✅" log_info "Checking prerequisites..."
else check_dependencies
send_error_message "Failed to set ownership and permissions for the install directory. Check permissions ❌"
# 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 fi
if [[ -d "$install_directory/config" ]]; then # Install CLI and set permissions
send_success_message "Configuration folder \"$install_directory/config\" exists ✅" echo
else log_info "We need your sudo password to install the YAMS CLI and configure permissions..."
if sudo mkdir -p "$install_directory/config"; then install_cli
send_success_message "Configuration folder \"$install_directory/config\" created ✅" set_permissions
else
send_error_message "Failed to create or access the configuration folder. 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
printf "\033c" printf "\033c"
echo "========================================================" cat << "EOF"
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" EOF
echo "========================================================"
echo "Everything should be running now! To check everything running, go to:" 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 echo
running_services_location running_services_location
echo echo
log_info "You might need to wait for a couple of minutes while everything gets up and running"
echo echo
echo "You might need to wait for a couple of minutes while everything gets up and running" log_info "All the service locations are also saved in ~/yams_services.txt"
echo
echo "All the services location are also saved in ~/yams_services.txt"
running_services_location > ~/yams_services.txt running_services_location > ~/yams_services.txt
echo "========================================================"
log_info "========================================================"
echo echo
echo "To configure YAMS, check the documentation at" log_info "To configure YAMS, check the documentation at"
echo "https://yams.media/config" log_info "https://yams.media/config"
echo echo
echo "========================================================" log_info "========================================================"
exit 0 exit 0

315
yams
View File

@ -1,36 +1,11 @@
#!/bin/bash #!/bin/bash
set -euo pipefail set -euo pipefail
dc="docker compose -f <filename> -f <custom_file_filename>" # Constants
install_directory="<install_directory>" readonly DC="docker compose -f <filename> -f <custom_file_filename>"
readonly INSTALL_DIRECTORY="<install_directory>"
option=${1:-"--help"} readonly TIMEOUT_SECONDS=60
readonly IP_ENDPOINTS=(
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"
}
send_success_message() {
echo -e "$(printf "\e[32m$1\e[0m")"
}
send_error_message() {
echo -e "$(printf "\e[31m$1\e[0m")"
exit 255
}
find_available_ip_endpoint() {
ip_endpoints=(
"https://ipinfo.io/ip" "https://ipinfo.io/ip"
"https://api.ipify.org" "https://api.ipify.org"
"https://checkip.amazonaws.com" "https://checkip.amazonaws.com"
@ -39,104 +14,218 @@ find_available_ip_endpoint() {
"https://wtfismyip.com/text" "https://wtfismyip.com/text"
) )
for ip in ${ip_endpoints[@]}; do # Color codes for better readability
endpoint=$(curl -s "$ip") readonly RED='\033[0;31m'
if [ "$endpoint" != "" ]; then readonly GREEN='\033[0;32m'
echo $ip readonly YELLOW='\033[1;33m'
break readonly NC='\033[0m' # No Color
fi
done # 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}"
} }
if [ "$option" == "--help" ]; then log_error() {
help echo -e "${RED}$1${NC}" >&2
exit 0 exit 1
}
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 fi
if [ "$option" == "restart" ]; then # Show progress with count
$dc stop && $dc up -d echo -n "."
echo "YAMS is starting. Wait 1 min until all the services are up and running..." sleep 1
exit 0 ((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() {
for endpoint in "${IP_ENDPOINTS[@]}"; do
if curl -s --connect-timeout 5 "$endpoint" > /dev/null; then
echo "$endpoint"
return 0
fi
done
return 1
}
get_ip_with_retries() {
local context=$1 # "local" or "qbittorrent"
local cmd_prefix=""
if [ "$context" = "qbittorrent" ]; then
cmd_prefix="docker exec qbittorrent"
fi fi
if [ "$option" == "stop" ]; then for endpoint in "${IP_ENDPOINTS[@]}"; do
$dc stop local ip
exit 0 if [ "$context" = "local" ]; then
ip=$(curl -s --connect-timeout 5 "$endpoint")
else
ip=$($cmd_prefix curl -s --connect-timeout 5 "$endpoint")
fi fi
if [ "$option" == "start" ]; then if [ -n "$ip" ] && [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
$dc up -d echo "$ip"
echo "YAMS is starting. Wait 1 min until all the services are up and running..." return 0
exit 0
fi fi
done
return 1
}
if [ "$option" == "check-vpn" ]; then check_vpn() {
echo "Getting your IP..." echo "Getting your IP..."
ip_endpoint=$(find_available_ip_endpoint) local your_ip
if [ "$ip_endpoint" == "" ]; then your_ip=$(get_ip_with_retries "local") || log_error "Failed to get your IP address from any endpoint"
send_error_message "No available endpoint to get IP address!" echo "Your IP: $your_ip"
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"); local country
if [ -n "$qbittorrent_ip" ]; then country=$(curl -s --connect-timeout 5 "https://am.i.mullvad.net/country") || log_warning "Couldn't determine your country"
echo "$qbittorrent_ip" [ -n "$country" ] && echo "Your local IP country is $country"
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 echo -e "\nGetting your qBittorrent IP..."
send_error_message "Your IPs are the same! qBittorrent is exposing your 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 else
send_success_message "Your IPs are different. qBittorrent is masking your IP! ✅ " log_success "✅ Success: Your IPs are different. qBittorrent is masking your IP!"
fi fi
else }
send_error_message "Failed to retrieve qBittorrent IP. Please check your setup. ⚠️"
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
}
main() {
local command=${1:-"--help"}
local destination=${2:-.}
# Validate and normalize destination path if provided
if [ "$command" = "backup" ]; then
destination=$(realpath "$destination") || log_error "Invalid backup destination path"
fi fi
if [ "$option" == "destroy" ]; then case "$command" in
echo --help)
echo show_help
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"} restart)
if [ "$destroy_now" == "y" ]; then $DC stop && $DC up -d
$dc down wait_for_services
echo ;;
echo stop)
echo "yams services were destroyed. To restart, run: " $DC stop || log_error "Failed to stop services"
echo "\$ yams start" log_success "Services stopped successfully"
fi ;;
fi 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
}
if [ "$option" == "update" ]; then main "$@"
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
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
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
$dc up -d
echo "YAMS was updated and it is starting. Wait 1 min until all the services are up and running..."
fi