#!/usr/bin/env bash # MeTube installation script with offline Deno installation # Place this script and deno-x86_64-unknown-linux-gnu.zip in the same directory set -e APP="MeTube" APP_DIR="/opt/metube" DENO_INSTALL_DIR="/usr/local" DENO_ZIP="deno-x86_64-unknown-linux-gnu.zip" GITHUB_REPO="alexta69/metube" SERVICE_USER="root" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; } step() { echo -e "${BLUE}[STEP]${NC} $1"; } # Check if running as root if [[ $EUID -ne 0 ]]; then error "This script must be run as root" fi # Check for local Deno archive SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" DENO_ARCHIVE_PATH="${SCRIPT_DIR}/${DENO_ZIP}" if [[ ! -f "$DENO_ARCHIVE_PATH" ]]; then error "Deno archive not found at $DENO_ARCHIVE_PATH" fi info "Found Deno archive: $DENO_ARCHIVE_PATH" # Install dependencies step "Installing system dependencies" apt-get update apt-get install -y curl wget unzip git build-essential python3 python3-pip python3-venv # Install FFmpeg step "Installing FFmpeg" apt-get install -y ffmpeg if command -v ffmpeg >/dev/null 2>&1; then info "FFmpeg installed successfully: $(ffmpeg -version | head -n1)" else error "FFmpeg installation failed" fi step "Installing NODEJS" curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - apt install -y nodejs npm install -g pm2 # Install Deno from local archive step "Installing Deno from local archive" if [[ -d "${DENO_INSTALL_DIR}/deno" ]]; then rm -rf "${DENO_INSTALL_DIR}/deno" fi unzip -o "$DENO_ARCHIVE_PATH" -d /tmp/deno_extract chmod +x /tmp/deno_extract/deno mv /tmp/deno_extract/deno "${DENO_INSTALL_DIR}/bin/deno" rm -rf /tmp/deno_extract if command -v deno >/dev/null 2>&1; then info "Deno installed successfully: $(deno --version)" else error "Deno installation failed" fi # Install pnpm step "Installing pnpm" curl -fsSL https://get.pnpm.io/install.sh | sh - # Download and setup MeTube step "Downloading MeTube from GitHub" LATEST_URL=$(curl -s "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" | grep "tarball_url" | cut -d '"' -f 4) if [[ -z "$LATEST_URL" ]]; then error "Failed to get latest release URL" fi if [[ -d "$APP_DIR" ]]; then warn "Existing installation found, backing up..." mv "$APP_DIR" "${APP_DIR}_bak_$(date +%Y%m%d_%H%M%S)" fi mkdir -p "$APP_DIR" cd "$APP_DIR" curl -L "$LATEST_URL" -o metube.tar.gz tar -xzf metube.tar.gz --strip-components=1 rm metube.tar.gz # Build frontend step "Building frontend" if [[ -d "$APP_DIR/ui" ]]; then cd "$APP_DIR/ui" /root/.local/share/pnpm/pnpm install --frozen-lockfile /root/.local/share/pnpm/pnpm run build else error "UI directory not found" fi # Setup Python backend step "Setting up Python backend" cd "$APP_DIR" python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip # Install required Python packages step "Installing Python packages" pip install yt-dlp aiohttp python-dotenv python-socketio watchfiles # Check for requirements.txt and install if exists if [[ -f "$APP_DIR/requirements.txt" ]]; then pip install -r requirements.txt fi # Configure yt-dlp to use Deno for JS challenges step "Configuring yt-dlp for JavaScript challenges" mkdir -p /root/.config/yt-dlp # Create yt-dlp config to enable remote components cat > /root/.config/yt-dlp/config < "$APP_DIR/.env" <<'EOF' # MeTube Configuration DOWNLOAD_DIR=/downloads STATE_DIR=/opt/metube/state URL_PREFIX= HTTP_USERNAME= HTTP_PASSWORD= YTDL_OPTIONS={"extractor_args":{"youtube":{"skip":[["hls","dash","live"]],"player_client":["android","web"]}},"remote_components":"ejs:github"} EOF else # Check if YTDL_OPTIONS already exists in .env if ! grep -q "YTDL_OPTIONS" "$APP_DIR/.env"; then echo "" >> "$APP_DIR/.env" echo "# yt-dlp options for JS challenge solving" >> "$APP_DIR/.env" echo 'YTDL_OPTIONS={"extractor_args":{"youtube":{"skip":[["hls","dash","live"]],"player_client":["android","web"]}},"remote_components":"ejs:github"}' >> "$APP_DIR/.env" fi fi # Create download and state directories mkdir -p /downloads mkdir -p "$APP_DIR/state" chown -R root:root /downloads chown -R root:root "$APP_DIR" # Fix potential missing app/main.py structure step "Checking MeTube application structure" if [[ ! -f "$APP_DIR/app/main.py" ]]; then warn "app/main.py not found, checking alternative locations..." if [[ -f "$APP_DIR/main.py" ]]; then warn "Found main.py in root, creating app directory structure" mkdir -p "$APP_DIR/app" mv "$APP_DIR/main.py" "$APP_DIR/app/" else error "Cannot find main.py. MeTube structure may be different than expected" fi fi # Create systemd service step "Creating systemd service" cat > /etc/systemd/system/metube.service <