diff --git a/ct/fileflows.sh b/ct/fileflows.sh new file mode 100644 index 000000000..27cdfd6fc --- /dev/null +++ b/ct/fileflows.sh @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/build.func) +# Copyright (c) 2021-2026 community-scripts ORG +# Author: kkroboth +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://fileflows.com/ + +APP="FileFlows" +var_tags="${var_tags:-media;automation}" +var_cpu="${var_cpu:-2}" +var_ram="${var_ram:-2048}" +var_disk="${var_disk:-8}" +var_os="${var_os:-debian}" +var_version="${var_version:-13}" +var_unprivileged="${var_unprivileged:-1}" +var_gpu="${var_gpu:-yes}" + +header_info "$APP" +variables +color +catch_errors + +function update_script() { +header_info + check_container_storage + check_container_resources + + if [[ ! -d /opt/fileflows ]]; then + msg_error "No ${APP} Installation Found!" + exit + fi + if ! [[ $(dpkg -s jq 2>/dev/null) ]]; then + $STD apt-get update + $STD apt-get install -y jq + fi + + update_available=$(curl -fsSL -X 'GET' "http://localhost:19200/api/status/update-available" -H 'accept: application/json' | jq .UpdateAvailable) + if [[ "${update_available}" == "true" ]]; then + msg_info "Stopping Service" + systemctl stop fileflows + msg_info "Stopped Service" + + msg_info "Creating Backup" + backup_filename="/opt/${APP}_backup_$(date +%F).tar.gz" + tar -czf "$backup_filename" -C /opt/fileflows Data + msg_ok "Backup Created" + + fetch_and_deploy_archive "https://fileflows.com/downloads/zip" "/opt/fileflows" + + msg_info "Starting Service" + systemctl start fileflows + msg_ok "Started Service" + msg_ok "Updated successfully!" + else + msg_ok "No update required. ${APP} is already at latest version" + fi + + exit +} + +start +build_container +description + +msg_ok "Completed successfully!\n" +echo -e "${CREATING}${GN}${APP} setup has been successfully initialized!${CL}" +echo -e "${INFO}${YW} Access it using the following URL:${CL}" +echo -e "${TAB}${GATEWAY}${BGN}http://${IP}:19200${CL}" diff --git a/install/fileflows-install.sh b/install/fileflows-install.sh new file mode 100644 index 000000000..a402560a5 --- /dev/null +++ b/install/fileflows-install.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Copyright (c) 2021-2026 community-scripts ORG +# Author: kkroboth +# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE +# Source: https://fileflows.com/ + +# Import Functions und Setup +source /dev/stdin <<<"$FUNCTIONS_FILE_PATH" +color +verb_ip6 +catch_errors +setting_up_container +network_check +update_os + +msg_info "Installing Dependencies" +$STD apt install -y \ + ffmpeg \ + imagemagick +msg_ok "Installed Dependencies" + +setup_hwaccel +setup_deb822_repo \ + "microsoft" \ + "https://packages.microsoft.com/keys/microsoft-2025.asc" \ + "https://packages.microsoft.com/debian/13/prod/" \ + "trixie" +fetch_and_deploy_archive "https://fileflows.com/downloads/zip" "/opt/fileflows" + +msg_info "Installing ASP.NET Core Runtime" +$STD apt install -y aspnetcore-runtime-8.0 +msg_ok "Installed ASP.NET Core Runtime" + +msg_info "Setting up FileFlows" +$STD ln -svf /usr/bin/ffmpeg /usr/local/bin/ffmpeg +$STD ln -svf /usr/bin/ffprobe /usr/local/bin/ffprobe +cd /opt/fileflows/Server +$STD dotnet FileFlows.Server.dll --systemd install --root true +systemctl enable -q --now fileflows +msg_ok "Setup FileFlows" + +motd_ssh +customize +cleanup_lxc diff --git a/install/jotty-install.sh b/install/jotty-install.sh index df98e70f9..a8ce9f634 100644 --- a/install/jotty-install.sh +++ b/install/jotty-install.sh @@ -15,28 +15,29 @@ update_os NODE_VERSION="22" NODE_MODULE="yarn" setup_nodejs #fetch_and_deploy_gh_release "jotty" "fccview/jotty" "tarball" "latest" "/opt/jotty" -mkdir -p /opt/jotty -wget -q https://github.com/fccview/jotty/releases/download/develop/jotty-prebuild-develop.tar.gz -O /tmp/jotty.tar.gz -tar -xzf /tmp/jotty.tar.gz -C /opt/jotty --strip-components=1 - msg_info "Setup jotty" +mkdir -p /opt/jotty +wget -q https://github.com/fccview/jotty/releases/download/develop/jotty-prebuild-develop.tar.gz -O /opt/jotty.tar.gz +cd /opt +tar -xzf jotty.tar.gz + cd /opt/jotty -unset NODE_OPTIONS -export NODE_OPTIONS="--max-old-space-size=3072" -# $STD yarn --frozen-lockfiled -# $STD yarn next telemetry disable -# $STD yarn build +# unset NODE_OPTIONS +# export NODE_OPTIONS="--max-old-space-size=3072" +# # $STD yarn --frozen-lockfiled +# # $STD yarn next telemetry disable +# # $STD yarn build -[ -d "public" ] && cp -r public .next/standalone/ -[ -d "howto" ] && cp -r howto .next/standalone/ -mkdir -p .next/standalone/.next -cp -r .next/static .next/standalone/.next/ +# [ -d "public" ] && cp -r public .next/standalone/ +# [ -d "howto" ] && cp -r howto .next/standalone/ +# mkdir -p .next/standalone/.next +# cp -r .next/static .next/standalone/.next/ -mv .next/standalone /tmp/jotty_standalone -rm -rf ./* .next .git .gitignore .yarn -mv /tmp/jotty_standalone/* . -mv /tmp/jotty_standalone/.[!.]* . 2>/dev/null || true -rm -rf /tmp/jotty_standalone +# mv .next/standalone /tmp/jotty_standalone +# rm -rf ./* .next .git .gitignore .yarn +# mv /tmp/jotty_standalone/* . +# mv /tmp/jotty_standalone/.[!.]* . 2>/dev/null || true +# rm -rf /tmp/jotty_standalone mkdir -p data/{users,checklists,notes} diff --git a/install/romm-install.sh b/install/romm-install.sh index 983619eed..73f2ada65 100644 --- a/install/romm-install.sh +++ b/install/romm-install.sh @@ -15,13 +15,11 @@ setting_up_container network_check update_os -msg_info "Installing dependencies" -$STD apt-get install -y \ +msg_info "Installing Dependencies" +$STD apt install -y \ acl \ + git \ build-essential \ - gcc \ - g++ \ - make \ libssl-dev \ libffi-dev \ libmagic-dev \ @@ -43,9 +41,9 @@ $STD apt-get install -y \ p7zip-full \ tzdata \ nginx -msg_ok "Installed dependencies" +msg_ok "Installed Dependencies" -UV_VERSION="0.7.19" PYTHON_VERSION="3.13" setup_uv +PYTHON_VERSION="3.13" setup_uv NODE_VERSION="22" setup_nodejs setup_mariadb MARIADB_DB_NAME="romm" MARIADB_DB_USER="romm" setup_mariadb_db @@ -60,7 +58,7 @@ mkdir -p /opt/romm \ msg_ok "Created directories" msg_info "Creating configuration file" -cat >/var/lib/romm/config/config.yml <<'CONFIGEOF' +cat <<'EOF' >/var/lib/romm/config/config.yml # RomM Configuration File # Documentation: https://docs.romm.app/latest/Getting-Started/Configuration-File/ # Only uncomment the lines you want to use/modify @@ -116,15 +114,13 @@ cat >/var/lib/romm/config/config.yml <<'CONFIGEOF' # emulatorjs: # debug: false # cache_limit: null -CONFIGEOF +EOF chmod 644 /var/lib/romm/config/config.yml msg_ok "Created configuration file" -msg_info "Installing RAHasher (RetroAchievements)" -fetch_and_deploy_gh_release "RetroAchievements" "RetroAchievements/RALibretro" "prebuild" "latest" "/opt/RALibretro" "RAHasher-x64-Linux-*.zip" +fetch_and_deploy_gh_release "RAHasher" "RetroAchievements/RALibretro" "prebuild" "latest" "/opt/RALibretro" "RAHasher-x64-Linux-*.zip" cp /opt/RALibretro/RAHasher /usr/bin/RAHasher chmod +x /usr/bin/RAHasher -msg_ok "Installed RAHasher" fetch_and_deploy_gh_release "romm" "rommapp/romm" @@ -134,7 +130,7 @@ systemctl restart redis-server systemctl enable -q --now redis-server AUTH_SECRET_KEY=$(openssl rand -hex 32) -cat >/opt/romm/.env </opt/romm/.env ROMM_BASE_PATH=/var/lib/romm ROMM_CONFIG_PATH=/var/lib/romm/config/config.yml WEB_CONCURRENCY=4 @@ -166,24 +162,25 @@ EOF chmod 600 /opt/romm/.env msg_ok "Created environment file" -msg_info "Setup Romm backend" +msg_info "Setting up RomM Backend" cd /opt/romm export UV_CONCURRENT_DOWNLOADS=1 $STD uv sync --all-extras cd /opt/romm/backend $STD uv run alembic upgrade head -msg_ok "Installed backend" +msg_ok "Set up RomM Backend" -msg_info "Setup Romm frontend" +msg_info "Setting up RomM Frontend" cd /opt/romm/frontend $STD npm install $STD npm run build mkdir -p /opt/romm/frontend/dist/assets/romm ln -sfn /var/lib/romm/resources /opt/romm/frontend/dist/assets/romm/resources ln -sfn /var/lib/romm/assets /opt/romm/frontend/dist/assets/romm/assets -msg_ok "Setup Romm frontend" -msg_info "Configuring nginx" -cat >/etc/nginx/sites-available/romm <<'EOF' +msg_ok "Set up RomM Frontend" + +msg_info "Configuring Nginx" +cat <<'EOF' >/etc/nginx/sites-available/romm upstream romm_backend { server 127.0.0.1:5000; } @@ -204,6 +201,14 @@ server { try_files $uri $uri/ /index.html; } + # Static assets + location /assets { + alias /opt/romm/frontend/dist/assets; + try_files $uri $uri/ =404; + expires 1y; + add_header Cache-Control "public, immutable"; + } + # EmulatorJS player - requires COOP/COEP headers for SharedArrayBuffer location ~ ^/rom/.*/ejs$ { add_header Cross-Origin-Embedder-Policy "require-corp"; @@ -247,13 +252,12 @@ EOF rm -f /etc/nginx/sites-enabled/default ln -sf /etc/nginx/sites-available/romm /etc/nginx/sites-enabled/romm -$STD nginx -t systemctl restart nginx -systemctl enable -q nginx -msg_ok "Configured nginx" +systemctl enable -q --now nginx +msg_ok "Configured Nginx" -msg_info "Creating services" -cat >/etc/systemd/system/romm-backend.service </etc/systemd/system/romm-backend.service [Unit] Description=RomM Backend After=network.target mariadb.service redis-server.service @@ -272,7 +276,7 @@ RestartSec=5 WantedBy=multi-user.target EOF -cat >/etc/systemd/system/romm-worker.service </etc/systemd/system/romm-worker.service [Unit] Description=RomM RQ Worker After=network.target mariadb.service redis-server.service romm-backend.service @@ -291,7 +295,7 @@ RestartSec=5 WantedBy=multi-user.target EOF -cat >/etc/systemd/system/romm-scheduler.service </etc/systemd/system/romm-scheduler.service [Unit] Description=RomM RQ Scheduler After=network.target mariadb.service redis-server.service romm-backend.service @@ -312,7 +316,7 @@ RestartSec=5 WantedBy=multi-user.target EOF -cat >/etc/systemd/system/romm-watcher.service </etc/systemd/system/romm-watcher.service [Unit] Description=RomM Filesystem Watcher After=network.target romm-backend.service @@ -331,9 +335,8 @@ RestartSec=5 WantedBy=multi-user.target EOF -systemctl daemon-reload systemctl enable -q --now romm-backend romm-worker romm-scheduler romm-watcher -msg_ok "Created services" +msg_ok "Created Services" motd_ssh customize diff --git a/misc/tools.func b/misc/tools.func index 260fb9a03..a86ff9fc6 100644 --- a/misc/tools.func +++ b/misc/tools.func @@ -5922,3 +5922,116 @@ EOF msg_ok "Docker setup completed" } + +# ------------------------------------------------------------------------------ +# Fetch and deploy archive from URL +# Downloads an archive (zip or tar.gz) from a URL and extracts it to a directory +# +# Usage: fetch_and_deploy_archive "url" "directory" +# url - URL to the archive (zip or tar.gz) +# directory - Destination path where the archive will be extracted +# +# Examples: +# fetch_and_deploy_archive "https://example.com/app.tar.gz" "/opt/myapp" +# fetch_and_deploy_archive "https://example.com/app.zip" "/opt/myapp" +# ------------------------------------------------------------------------------ +function fetch_and_deploy_archive() { + local url="$1" + local directory="$2" + + if [[ -z "$url" ]]; then + msg_error "URL parameter is required" + return 1 + fi + + if [[ -z "$directory" ]]; then + msg_error "Directory parameter is required" + return 1 + fi + + local filename="${url##*/}" + + local archive_type="zip" + if [[ "$filename" == *.tar.gz || "$filename" == *.tgz ]]; then + archive_type="tar" + fi + + msg_info "Downloading archive from $url" + + local tmpdir + tmpdir=$(mktemp -d) || { + msg_error "Failed to create temporary directory" + return 1 + } + + curl -fsSL -o "$tmpdir/$filename" "$url" || { + msg_error "Download failed: $url" + rm -rf "$tmpdir" + return 1 + } + + msg_info "Extracting archive to $directory" + + mkdir -p "$directory" + + if [[ "${CLEAN_INSTALL:-0}" == "1" ]]; then + rm -rf "${directory:?}/"* + fi + + local unpack_tmp + unpack_tmp=$(mktemp -d) + + if [[ "$archive_type" == "zip" ]]; then + ensure_dependencies unzip + unzip -q "$tmpdir/$filename" -d "$unpack_tmp" || { + msg_error "Failed to extract ZIP archive" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + } + elif [[ "$archive_type" == "tar" ]]; then + tar --no-same-owner -xf "$tmpdir/$filename" -C "$unpack_tmp" || { + msg_error "Failed to extract TAR archive" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + } + fi + + local top_entries + top_entries=$(find "$unpack_tmp" -mindepth 1 -maxdepth 1) + + if [[ "$(echo "$top_entries" | wc -l)" -eq 1 && -d "$top_entries" ]]; then + local inner_dir="$top_entries" + shopt -s dotglob nullglob + if compgen -G "$inner_dir/*" >/dev/null; then + cp -r "$inner_dir"/* "$directory/" || { + msg_error "Failed to copy contents from $inner_dir to $directory" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + } + else + msg_error "Inner directory is empty: $inner_dir" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + fi + shopt -u dotglob nullglob + else + shopt -s dotglob nullglob + if compgen -G "$unpack_tmp/*" >/dev/null; then + cp -r "$unpack_tmp"/* "$directory/" || { + msg_error "Failed to copy contents to $directory" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + } + else + msg_error "Unpacked archive is empty" + rm -rf "$tmpdir" "$unpack_tmp" + return 1 + fi + shopt -u dotglob nullglob + fi + + rm -rf "$tmpdir" "$unpack_tmp" + msg_ok "Successfully deployed archive to $directory" + return 0 +} +