#!/bin/bash # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # GitHub repository information REPO_URL="https://raw.githubusercontent.com/yourusername/jellyfin-docker/main" echo -e "${GREEN}Jellyfin Docker Setup Script${NC}" echo "--------------------------------" # Function to detect GPU detect_gpu() { # Check for NVIDIA if command -v nvidia-smi &> /dev/null; then echo "nvidia" return fi # Check for AMD GPU if lspci | grep -i "vga.*amd" &> /dev/null; then if lspci | grep -i "vga.*radeon" &> /dev/null; then echo "amd-gpu" else echo "amd-apu" fi return fi # Check for Intel if lspci | grep -i "vga.*intel" &> /dev/null; then if [ -d "/sys/class/drm/card0/device/driver/module/drivers/pci:intel_arc" ]; then echo "intel-arc" else echo "intel-igpu" fi return fi echo "none" } # Function to download file download_file() { local file=$1 echo -e "${YELLOW}Downloading ${file}...${NC}" curl -sSL "${REPO_URL}/${file}" -o "${INSTALL_DIR}/${file}" } # Set installation directory SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DEFAULT_INSTALL_DIR="$SCRIPT_DIR" # Ask for installation directory with better validation setup_install_directory() { echo -e "${YELLOW}Where would you like to install Jellyfin?${NC}" echo -e "Default: ${GREEN}${DEFAULT_INSTALL_DIR}${NC}" read -p "Install directory [$DEFAULT_INSTALL_DIR]: " INSTALL_DIR INSTALL_DIR=${INSTALL_DIR:-$DEFAULT_INSTALL_DIR} # Check if directory exists and has existing configuration if [ -f "${INSTALL_DIR}/docker-compose.yml" ] || \ [ -f "${INSTALL_DIR}/docker-compose.override.yml" ] || \ [ -f "${INSTALL_DIR}/.env" ]; then echo -e "${RED}Warning: Jellyfin files already exist in ${INSTALL_DIR}${NC}" read -p "Do you want to proceed and potentially overwrite? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Aborting installation" exit 1 fi fi # Create install directory if it doesn't exist mkdir -p "$INSTALL_DIR" # Check if directory is writable if [ ! -w "$INSTALL_DIR" ]; then echo -e "${RED}Error: Directory ${INSTALL_DIR} is not writable${NC}" exit 1 fi } setup_install_directory # Check for existing docker-compose.yml if [ -f "${INSTALL_DIR}/docker-compose.yml" ]; then echo -e "${RED}Warning: docker-compose.yml already exists in ${INSTALL_DIR}${NC}" read -p "Do you want to overwrite it? (y/N) " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "Aborting installation" exit 1 fi fi # Set up transcode cache echo -e "${YELLOW}Where would you like to store the transcode cache?${NC}" read -p "Transcode cache directory [/mnt/transcode]: " TRANSCODE_DIR TRANSCODE_DIR=${TRANSCODE_DIR:-/mnt/transcode} # Create transcode directory sudo mkdir -p "$TRANSCODE_DIR" sudo chown -R $USER:$USER "$TRANSCODE_DIR" # Detect GPU echo -e "${YELLOW}Detecting GPU...${NC}" GPU_TYPE=$(detect_gpu) case $GPU_TYPE in "nvidia") echo -e "${GREEN}NVIDIA GPU detected${NC}" TRANSCODE_FILE="nvidia-transcoding.yml" ;; "amd-gpu") echo -e "${GREEN}AMD dedicated GPU detected${NC}" TRANSCODE_FILE="amd-gpu.transcoding.yml" ;; "amd-apu") echo -e "${GREEN}AMD APU detected${NC}" TRANSCODE_FILE="amd-apu.transcoding.yml" ;; "intel-arc") echo -e "${GREEN}Intel ARC detected${NC}" TRANSCODE_FILE="intel-arc.transcoding.yml" ;; "intel-igpu") echo -e "${GREEN}Intel integrated GPU detected${NC}" TRANSCODE_FILE="intel-igpu.transcoding.yml" ;; *) echo -e "${RED}No supported GPU detected${NC}" echo "CPU transcoding will be used" TRANSCODE_FILE="intel-igpu.transcoding.yml" # Default fallback ;; esac # Download required files download_file "docker-compose.yml" download_file "sample.env" download_file "$TRANSCODE_FILE" download_file "tonemapping.md" # Create .env file from sample cp "${INSTALL_DIR}/sample.env" "${INSTALL_DIR}/.env" # Update .env file with transcode path sed -i "s|TRANSCODE_CACHE=.*|TRANSCODE_CACHE=${TRANSCODE_DIR}|g" "${INSTALL_DIR}/.env" # Get render group ID RENDER_GID=$(getent group render | cut -d: -f3) if [ ! -z "$RENDER_GID" ]; then sed -i "s|RENDER_GID=.*|RENDER_GID=${RENDER_GID}|g" "${INSTALL_DIR}/.env" fi # Check for Docker and Docker Compose check_prerequisites() { echo -e "${YELLOW}Checking prerequisites...${NC}" if ! command -v docker &> /dev/null; then echo -e "${RED}Docker is not installed${NC}" exit 1 fi if ! docker compose version &> /dev/null; then echo -e "${RED}Docker Compose is not installed${NC}" exit 1 fi } # Run prerequisite checks check_prerequisites # Network configuration function configure_network() { echo -e "${YELLOW}Configuring network...${NC}" # Ask about host network mode read -p "Use host network mode? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then USE_HOST_NETWORK=true else # Check for port conflicts check_port_conflict 8096 check_port_conflict 8920 check_port_conflict 1900 "DLNA" fi # List available networks echo -e "${YELLOW}Available Docker networks:${NC}" docker network ls read -p "Use specific Docker network? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then select_docker_network fi } # Function to list available volumes list_volumes() { echo "Available volumes:" docker volume ls | grep -v "^local.*[0-9a-f]\{64\}$" } # Function to select media volume select_media_volume() { local volumes=$(docker volume ls --format "{{.Name}}" | grep -v "^[0-9a-f]\{64\}$") if [ -z "$volumes" ]; then echo -e "${RED}No named volumes found${NC}" return 1 fi echo "Available volumes:" select volume in $volumes "Create new" "Skip"; do case $volume in "Create new") configure_new_volume break ;; "Skip") break ;; *) if [ -n "$volume" ]; then echo "Selected volume: $volume" add_volume_to_override "$volume" break fi ;; esac done } # Function to add volume to override file add_volume_to_override() { local volume=$1 if [ ! -f "${INSTALL_DIR}/docker-compose.override.yml" ]; then cp "${INSTALL_DIR}/docker-compose.override.yml.sample" "${INSTALL_DIR}/docker-compose.override.yml" fi # Add volume if not already present if ! grep -q " $volume:" "${INSTALL_DIR}/docker-compose.override.yml"; then sed -i "/volumes:/a\ $volume:\n external: true" "${INSTALL_DIR}/docker-compose.override.yml" fi } # Configure volumes configure_volumes() { echo -e "${YELLOW}Checking available volumes...${NC}" list_volumes read -p "Would you like to use existing volumes? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then select_media_volume fi } # Run volume configuration configure_volumes # Collect required environment variables collect_env_variables() { echo -e "${YELLOW}Configuring environment variables...${NC}" # Only ask if not already set in .env if [ ! -f "${INSTALL_DIR}/.env" ] || ! grep -q "DOMAIN=" "${INSTALL_DIR}/.env"; then read -p "Domain name for Jellyfin: " DOMAIN fi if [ ! -f "${INSTALL_DIR}/.env" ] || ! grep -q "JELLYFIN_ADMIN_USER=" "${INSTALL_DIR}/.env"; then read -p "Jellyfin admin username: " ADMIN_USER fi # Add password collection with masking if [ ! -f "${INSTALL_DIR}/.env" ] || ! grep -q "JELLYFIN_ADMIN_PASSWORD=" "${INSTALL_DIR}/.env"; then read -s -p "Jellyfin admin password: " ADMIN_PASSWORD echo fi } echo -e "${GREEN}Installation complete!${NC}" echo "--------------------------------" echo -e "Files installed in: ${YELLOW}${INSTALL_DIR}${NC}" echo -e "Transcode cache: ${YELLOW}${TRANSCODE_DIR}${NC}" echo -e "GPU detected: ${YELLOW}${GPU_TYPE}${NC}" echo echo "Next steps:" echo "1. Edit ${INSTALL_DIR}/.env to configure your settings" echo "2. Start Jellyfin with:" echo -e "${YELLOW} cd ${INSTALL_DIR}${NC}" echo -e "${YELLOW} docker compose -f docker-compose.yml -f ${TRANSCODE_FILE} up -d${NC}"