├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── bug_report.yml ├── renovate.json ├── workflows │ ├── send_files.yaml │ ├── deploy.yml │ ├── ci-auto-rerun-failed-jobs-action.yml │ ├── ci-checks.yml │ ├── qi-bash.yml │ ├── ci-main-reusable-caller.yml │ ├── ci-alpine-release.yml │ ├── ci-alpine-build.yml │ └── ci-debian-build.yml └── copilot-instructions.md ├── docs ├── src │ ├── content │ │ └── docs │ │ │ ├── test.mdx │ │ │ ├── glossary │ │ │ ├── github-releases.md │ │ │ ├── github.md │ │ │ ├── docker-desktop.md │ │ │ ├── powershell.md │ │ │ ├── muslc.md │ │ │ ├── buildjet.md │ │ │ ├── glibc.md │ │ │ ├── wsl2.md │ │ │ ├── docker.md │ │ │ ├── github-actions.md │ │ │ ├── crossbuild-essentials.md │ │ │ ├── qemu.md │ │ │ ├── musl-cross-make.md │ │ │ ├── bash.md │ │ │ └── github-workflows.md │ │ │ ├── artifact-attestations.mdx │ │ │ ├── credits.mdx │ │ │ ├── nginx-proxypass.mdx │ │ │ ├── debugging.mdx │ │ │ ├── rules-of-engagement.mdx │ │ │ ├── systemd.mdx │ │ │ ├── script-usage.mdx │ │ │ ├── github-actions.mdx │ │ │ ├── prerequisites.mdx │ │ │ ├── index.mdx │ │ │ ├── script-installation.mdx │ │ │ ├── install-qbittorrent.mdx │ │ │ └── introduction.mdx │ ├── components │ │ ├── AdvancedMarkdown.astro │ │ ├── Important.astro │ │ ├── Charts.astro │ │ ├── GithubActions.astro │ │ ├── Details.astro │ │ ├── BuildinfoIntroduction.astro │ │ ├── global.jsx │ │ ├── Patchinfo.astro │ │ ├── ScriptVersions.astro │ │ ├── Header.astro │ │ ├── CalloutProcessor.astro │ │ └── Scriptinfo.astro │ ├── content.config.ts │ ├── pages │ │ ├── changelog.astro │ │ └── glossary.astro │ ├── utils │ │ └── modal-utils.ts │ └── assets │ │ ├── stage1.html │ │ └── stage3.html ├── public │ ├── icons │ │ ├── png │ │ │ ├── idea.png │ │ │ ├── info.png │ │ │ ├── star.png │ │ │ ├── tips.png │ │ │ ├── notes.png │ │ │ ├── post-it.png │ │ │ ├── warning.png │ │ │ ├── sticky-note.png │ │ │ └── sticky-notes.png │ │ └── note-circle.svg │ ├── docs_images │ │ ├── script_usage │ │ │ ├── 1.png │ │ │ ├── help.png │ │ │ ├── first-run.png │ │ │ └── bootstrapped.png │ │ ├── reusable_workflow_inputs.png │ │ ├── reusable_workflow_inputs-debug.png │ │ └── github_settings_actions_options.png │ ├── logo-github.svg │ ├── logo-large-qbittorrent.svg │ ├── logo-qbittorrent.svg │ ├── logo-alpine.svg │ ├── favicon.ico │ ├── favicon.svg │ ├── logo-musl - Copy.svg │ └── logo-musl.svg ├── .vscode │ ├── extensions.json │ └── launch.json ├── astro-start.cmd ├── tsconfig.json ├── astro-upgrade.cmd ├── .gitignore ├── upgrade.ps1 ├── package.json ├── ec.config.mjs ├── README.md └── astro.config.mjs ├── patches ├── qbittorrent │ ├── 5.1.1 │ │ └── url │ ├── 5.1.2 │ │ └── url │ ├── 4.6.7 │ │ └── url │ ├── 4.4.4 │ │ └── patch │ ├── 5.0.4 │ │ └── patch │ ├── 4.4.3.1 │ │ └── patch │ └── 4.5.1 │ │ └── patch ├── qttools │ └── 6.7.2 │ │ ├── url │ │ └── patch ├── qtbase │ ├── 6.7.2 │ │ ├── url │ │ └── patch │ └── 6.7.0-beta1 │ │ └── url ├── openssl │ └── 3.4.0 │ │ └── patch ├── double_conversion │ └── 3.3.1 │ │ └── patch └── libtorrent │ ├── 2.0.5 │ └── patch │ └── 2.0.4 │ └── patch ├── SECURITY.md ├── .gitignore ├── .editorconfig ├── .pre-commit-config.yaml ├── .claude └── agents │ └── bash-expert.md └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * -text 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /docs/src/content/docs/test.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: test 3 | hide_title: true 4 | --- 5 | -------------------------------------------------------------------------------- /patches/qbittorrent/5.1.1/url: -------------------------------------------------------------------------------- 1 | https://patch-diff.githubusercontent.com/raw/qbittorrent/qBittorrent/pull/22910.patch 2 | -------------------------------------------------------------------------------- /patches/qbittorrent/5.1.2/url: -------------------------------------------------------------------------------- 1 | https://patch-diff.githubusercontent.com/raw/qbittorrent/qBittorrent/pull/22988.patch 2 | -------------------------------------------------------------------------------- /docs/public/icons/png/idea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/idea.png -------------------------------------------------------------------------------- /docs/public/icons/png/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/info.png -------------------------------------------------------------------------------- /docs/public/icons/png/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/star.png -------------------------------------------------------------------------------- /docs/public/icons/png/tips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/tips.png -------------------------------------------------------------------------------- /patches/qbittorrent/4.6.7/url: -------------------------------------------------------------------------------- 1 | https://github.com/qbittorrent/qBittorrent/commit/91943e4815ae40a273b39432340357a4ce879f3b.patch -------------------------------------------------------------------------------- /docs/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["astro-build.astro-vscode"], 3 | "unwantedRecommendations": [] 4 | } 5 | -------------------------------------------------------------------------------- /docs/public/icons/png/notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/notes.png -------------------------------------------------------------------------------- /docs/public/icons/png/post-it.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/post-it.png -------------------------------------------------------------------------------- /docs/public/icons/png/warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/warning.png -------------------------------------------------------------------------------- /patches/qttools/6.7.2/url: -------------------------------------------------------------------------------- 1 | https://codereview.qt-project.org/gitweb?p=qt/qttools.git;a=patch;h=8bb2a0c02b305f8ae8611e501fe7dd3d2b4468a6 -------------------------------------------------------------------------------- /patches/qtbase/6.7.2/url: -------------------------------------------------------------------------------- 1 | https://codereview.qt-project.org/gitweb?p=qt/qttools.git;a=patch;h=8bb2a0c02b305f8ae8611e501fe7dd3d2b4468a6 2 | -------------------------------------------------------------------------------- /docs/astro-start.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell.exe -noexit -Command "& {Set-Location -literalPath '%~dp0.'; Invoke-Expression 'npm start'}" 3 | -------------------------------------------------------------------------------- /docs/public/icons/png/sticky-note.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/sticky-note.png -------------------------------------------------------------------------------- /docs/public/icons/png/sticky-notes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/icons/png/sticky-notes.png -------------------------------------------------------------------------------- /patches/qtbase/6.7.0-beta1/url: -------------------------------------------------------------------------------- 1 | https://codereview.qt-project.org/gitweb?p=qt/qtbase.git;a=patch;h=72ee1df260d728a1e699bd4c6e03bf202c929cbd 2 | -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "astro/tsconfigs/strict", 3 | "include": [".astro/types.d.ts", "**/*"], 4 | "exclude": ["dist"] 5 | } 6 | -------------------------------------------------------------------------------- /docs/public/docs_images/script_usage/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/script_usage/1.png -------------------------------------------------------------------------------- /docs/astro-upgrade.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | powershell.exe -noexit -Command "& {Set-Location -literalPath '%~dp0.'; Invoke-Expression 'npx @astrojs/upgrade'}" 3 | -------------------------------------------------------------------------------- /docs/public/docs_images/script_usage/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/script_usage/help.png -------------------------------------------------------------------------------- /docs/public/docs_images/script_usage/first-run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/script_usage/first-run.png -------------------------------------------------------------------------------- /docs/public/docs_images/reusable_workflow_inputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/reusable_workflow_inputs.png -------------------------------------------------------------------------------- /docs/public/docs_images/script_usage/bootstrapped.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/script_usage/bootstrapped.png -------------------------------------------------------------------------------- /docs/src/components/AdvancedMarkdown.astro: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | --- 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /docs/public/docs_images/reusable_workflow_inputs-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/reusable_workflow_inputs-debug.png -------------------------------------------------------------------------------- /docs/public/docs_images/github_settings_actions_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/HEAD/docs/public/docs_images/github_settings_actions_options.png -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | // https://docs.renovatebot.com/config-presets/#github-hosted-presets 2 | // https://docs.renovatebot.com/config-presets/#github 3 | { 4 | "extends": [ 5 | "github>userdocs/renovate:default.json" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/github-releases.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github Releases 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Some tooltip info Lorem Ipsum is simply dummy text of the printing and typesetting industry. 7 | 8 | --- 9 | 10 | further reading 11 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/github.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github website 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Custom musl crossbuild toolchains based on musl.cc, click to know more. 7 | 8 | --- 9 | 10 | https://github.com/userdocs/qbt-musl-cross-make 11 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | Find bug? 4 | 5 | [Open issue](https://github.com/userdocs/qbittorrent-nox-static/issues/new/choose) 6 | 7 | Got question? 8 | 9 | [Start discussion](https://github.com/userdocs/qbittorrent-nox-static/discussions/new/choose) 10 | -------------------------------------------------------------------------------- /docs/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "command": "./node_modules/.bin/astro dev", 6 | "name": "Development server", 7 | "request": "launch", 8 | "type": "node-terminal" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/content.config.ts: -------------------------------------------------------------------------------- 1 | import { defineCollection } from 'astro:content'; 2 | import { docsLoader } from '@astrojs/starlight/loaders'; 3 | import { docsSchema } from '@astrojs/starlight/schema'; 4 | 5 | export const collections = { 6 | docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }), 7 | }; 8 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist/ 3 | # generated types 4 | .astro/ 5 | 6 | # dependencies 7 | node_modules/ 8 | 9 | # logs 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | 16 | # environment variables 17 | .env 18 | .env.production 19 | 20 | # macOS-specific files 21 | .DS_Store 22 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/docker-desktop.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Docker Desktop 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Docker Desktop is secure, out-of-the-box containerization software offering developers and teams a robust, hybrid toolkit to build, share, and run applications anywhere. 7 | 8 | --- 9 | 10 | https://www.docker.com/products/docker-desktop/ 11 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/powershell.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Powershell 3 | hide_title: true 4 | --- 5 | 6 | 🟦 PowerShell is a cross-platform task automation solution made up of a command-line shell, a scripting language, and a configuration management framework. PowerShell runs on Windows, Linux, and macOS. 7 | 8 | --- 9 | 10 | https://learn.microsoft.com/en-us/powershell/scripting/overview 11 | -------------------------------------------------------------------------------- /docs/src/components/Important.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { id, alt } = Astro.props; 3 | const basePath = "/" + Astro.url.pathname.split("/")[1]; 4 | --- 5 | 6 |
7 |
8 | {alt} 13 |
14 |
15 | 16 |
17 |
18 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/muslc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Musl libc 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Musl (pronounced Mussel) is an implementation of the C standard library built on top of the Linux system call API, including interfaces defined in the base language standard, POSIX, and widely agreed-upon extensions. musl is lightweight, fast, simple, free, and strives to be correct in the sense of standards-conformance and safety. 7 | 8 | --- 9 | 10 | [musl](https://wiki.musl-libc.org/) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /package-lock.json 3 | /package.json 4 | 5 | # Dependencies 6 | docs/node_modules 7 | 8 | # Production 9 | docs/build 10 | 11 | # Generated files 12 | docs/.docs 13 | docs/.docusaurus 14 | docs/.cache-loader 15 | 16 | # Misc 17 | docs/.DS_Store 18 | docs/.env.local 19 | docs/.env.development.local 20 | docs/.env.test.local 21 | docs/.env.production.local 22 | 23 | docs/npm-debug.log* 24 | docs/yarn-debug.log* 25 | docs/yarn-error.log* 26 | .claude/settings.local.json 27 | -------------------------------------------------------------------------------- /patches/openssl/3.4.0/patch: -------------------------------------------------------------------------------- 1 | diff --git a/include/crypto/riscv_arch.h b/include/crypto/riscv_arch.h 2 | index 4b3573f5a3..c0b94d1ca5 100644 3 | --- a/include/crypto/riscv_arch.h 4 | +++ b/include/crypto/riscv_arch.h 5 | @@ -15,7 +15,10 @@ 6 | 7 | # if defined(OPENSSL_SYS_LINUX) && !defined(FIPS_MODULE) 8 | # if __has_include() 9 | -# define OSSL_RISCV_HWPROBE 10 | +# include 11 | +# ifdef __NR_riscv_hwprobe 12 | +# define OSSL_RISCV_HWPROBE 13 | +# endif 14 | # endif 15 | # endif 16 | -------------------------------------------------------------------------------- /docs/src/components/Charts.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { class: className, id, summary } = Astro.props; 3 | 4 | import Example from "/src/charts/example.html?raw"; 5 | --- 6 | 7 |
8 |
9 | {summary} 10 |
11 |
15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/buildjet.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: BuildJet for Github Actions 3 | hide_title: true 4 | --- 5 | 6 | 🟦 A paid for alternative to self hosted runners that allow for native arm runners as well as increased cores for faster build times. 7 | 8 | --- 9 | 10 | If you really need a faster way to build you should consider this integration for your Github workflows. Self hosted runners are a complicated option where this is not. 11 | 12 | [https://buildjet.com/for-github-actions](https://buildjet.com/for-github-actions) 13 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/glibc.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Glibc 3 | hide_title: true 4 | --- 5 | 6 | The GNU C Library - The project provides the core libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. These libraries provide critical APIs including ISO C11, POSIX.1-2008, BSD, OS-specific APIs and more. These APIs include such foundational facilities as open, read, write, malloc, printf, getaddrinfo, dlopen, pthread_create, crypt, login, exit and more. 7 | 8 | --- 9 | 10 | [libc](https://www.gnu.org/software/libc/) 11 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/wsl2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: WSL2 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Developers can access the power of both Windows and Linux at the same time on a Windows machine. The Windows Subsystem for Linux (WSL) lets developers install a Linux distribution (such as Ubuntu, OpenSUSE, Kali, Debian, Arch Linux, etc) and use Linux applications, utilities, and Bash command-line tools directly on Windows, unmodified, without the overhead of a traditional virtual machine or dualboot setup. 7 | 8 | --- 9 | 10 | https://learn.microsoft.com/en-us/windows/wsl/install 11 | -------------------------------------------------------------------------------- /.github/workflows/send_files.yaml: -------------------------------------------------------------------------------- 1 | name: send_to_usrdx_s 2 | 3 | on: 4 | push: 5 | branches: [main, master] 6 | paths: 7 | - "qbittorrent-nox-static.sh" 8 | - "qbt-nox-static.bash" 9 | - "qi.bash" 10 | workflow_dispatch: 11 | 12 | permissions: {} 13 | 14 | jobs: 15 | send_to_usrdx_s: 16 | runs-on: ubuntu-24.04-arm 17 | 18 | steps: 19 | - name: Trigger grab_files workflow in usrdx/s 20 | env: 21 | GH_TOKEN: ${{ secrets.USRDX_S }} 22 | GH_HOST: github.com 23 | run: gh workflow run grab_files.yaml --repo usrdx/s 24 | -------------------------------------------------------------------------------- /docs/src/pages/changelog.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; 3 | import CalloutProcessor from "../components/CalloutProcessor.astro"; 4 | import * as myPost from "../../../changelog.md"; 5 | 6 | const headings = myPost.getHeadings().map((heading) => ({ 7 | depth: heading.depth, 8 | slug: heading.slug, 9 | text: heading.text, 10 | })); 11 | 12 | const content = await myPost.compiledContent(); 13 | --- 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /patches/double_conversion/3.3.1/patch: -------------------------------------------------------------------------------- 1 | --- double-conversion/CMakeLists.txt 2025-05-18 09:22:22.672636721 +0100 2 | +++ /home/username/CMakeLists.txt 2025-05-18 09:19:40.099991800 +0100 3 | @@ -1,4 +1,7 @@ 4 | -cmake_minimum_required(VERSION 3.0) 5 | +# This project likely works with older versions, such as 3.5, but that 6 | +# configuration is not tested. 7 | +# When changing the minimum required versions make sure to update the CI. 8 | +cmake_minimum_required(VERSION 3.15...4.0.1) 9 | project(double-conversion VERSION 3.3.0) 10 | 11 | option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF) 12 | -------------------------------------------------------------------------------- /docs/upgrade.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Upgrades Astro dependencies using npx. 4 | .DESCRIPTION 5 | This script runs the Astro upgrade tool to update project dependencies. 6 | .NOTES 7 | Requires Node.js and NPM to be installed. 8 | #> 9 | 10 | # Error handling preference 11 | $ErrorActionPreference = 'Stop' 12 | 13 | # Check if npm is installed 14 | if (!(Get-Command npm -ErrorAction SilentlyContinue)) { 15 | Write-Error "Node.js/NPM is not installed. Please install it first." 16 | exit 1 17 | } 18 | 19 | try { 20 | npx @astrojs/upgrade 21 | } catch { 22 | Write-Error "Failed to upgrade Astro: $_" 23 | exit 1 24 | } 25 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/docker.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Docker Cli 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker's methodologies for shipping, testing, and deploying code, you can significantly reduce the delay between writing code and running it in production. 7 | 8 | --- 9 | 10 | [Installation Docs](https://docs.docker.com/engine/install/) 11 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/github-actions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github Actions 3 | hide_title: true 4 | --- 5 | 6 | 🟦 GitHub Actions makes it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want. 7 | 8 | --- 9 | 10 | Automate, customize, and execute your software development workflows right in your repository with GitHub Actions. You can discover, create, and share actions to perform any job you'd like, including CI/CD, and combine actions in a completely customized workflow. 11 | 12 | https://docs.github.com/en/actions 13 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wandering-wavelength", 3 | "type": "module", 4 | "version": "0.0.1", 5 | "scripts": { 6 | "dev": "astro dev", 7 | "start": "astro dev", 8 | "build": "astro build", 9 | "preview": "astro preview", 10 | "astro": "astro" 11 | }, 12 | "dependencies": { 13 | "@astrojs/check": "^0.9.6", 14 | "@astrojs/starlight": "^0.37.1", 15 | "@expressive-code/plugin-collapsible-sections": "^0.41.3", 16 | "astro": "^5.16.5", 17 | "sharp": "^0.34.2", 18 | "starlight-github-alerts": "^0.1.0", 19 | "starlight-image-zoom": "^0.13.0", 20 | "typescript": "^5.9.2" 21 | }, 22 | "devDependencies": { 23 | "sass-embedded": "^1.90.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/src/components/GithubActions.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { id } = Astro.props; 3 | import { Code } from "@astrojs/starlight/components"; 4 | 5 | import ci_main_reusable_caller from "../../../.github/workflows/ci-main-reusable-caller.yml?raw"; 6 | import ci_debian_build from "../../../.github/workflows/ci-debian-build.yml?raw"; 7 | import ci_alpine_build from "../../../.github/workflows/ci-alpine-build.yml?raw"; 8 | import ci_alpine_release from "../../../.github/workflows/ci-alpine-release.yml?raw"; 9 | import ci_auto_rerun_failed_jobs_action from "../../../.github/workflows/ci-auto-rerun-failed-jobs-action.yml?raw"; 10 | 11 | const imports = { 12 | ci_main_reusable_caller, 13 | ci_debian_build, 14 | ci_alpine_build, 15 | ci_alpine_release, 16 | ci_auto_rerun_failed_jobs_action, 17 | }; 18 | const code = imports[id]; 19 | --- 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/crossbuild-essentials.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debian Crossbuild-Essentials 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Native Debian and Ubuntu cross build toolchains for cross compiling, used when a supported Debian based OS is the Host. 7 | 8 | --- 9 | 10 | When building on supported Debian based hosts we use the official `crossbuild-essential` tool chains that are made specifically for cross compiling on these host operating systems. 11 | 12 | On the modern distros like Trixie and Noble there is a wide range of supported cross build targets available. 13 | 14 | Please look a the links below to see which options are available for which platform and release. 15 | 16 | [Debian cross build essential toolchains](https://packages.debian.org/search?suite=trixie&searchon=names&keywords=crossbuild-essential) 17 | 18 | [Ubuntu cross build essential toolchains](https://packages.ubuntu.com/search?suite=noble&searchon=names&keywords=crossbuild-essential) 19 | -------------------------------------------------------------------------------- /docs/src/components/Details.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { class: className, summary } = Astro.props; 3 | --- 4 | 5 |
6 |
7 | {summary} 8 |
9 | 10 |
11 |
12 |
13 | 14 | 49 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/qemu.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Qemu emulation 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Qemu is a generic and open source machine emulator and virtualize. It's used when cross building so that created binaries and libs can be automatically loaded and used without host arch versions. 7 | 8 | --- 9 | 10 | We use [qemu-user-static](https://packages.ubuntu.com/noble/qemu-user-static) and [binfmt-support](https://packages.ubuntu.com/noble/binfmt-support) on the Github `ubuntu-latest` runners 11 | 12 | For example, when cross compiling Qt6 you they want you to have a have a host version built first and then use loads of special cmake settings. 13 | 14 | The few binaries that are actually needed are not part of the final build so they are emulated as and when needed and it works fine. 15 | 16 | So by having emulation at hand when needed we can easily handle certain cross compilation issues easily. 17 | 18 | Qt5 does not need to do this as `qmake` build the tools for the host first. Apparently it's a cmake limitation. 19 | -------------------------------------------------------------------------------- /docs/src/content/docs/artifact-attestations.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: artifact attestations 3 | description: artifact attestations 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | From releases after the 03/10/2024 you can use the `artifact_attestations` to verify the provenance of the build. 31 | 32 | https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds 33 | 34 | Using `gh` cli you can use this command to verify the provenance of the build: 35 | 36 | For example, using the `x86_64-qbittorrent-nox` build: 37 | 38 | ```bash 39 | gh attestation verify x86_64-qbittorrent-nox -o userdocs 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/src/components/BuildinfoIntroduction.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Code } from "@astrojs/starlight/components"; 3 | const response = await fetch( 4 | "https://github.com/userdocs/qbt-workflow-files/releases/latest/download/dependency-version.json", 5 | ); 6 | 7 | const data = await response.json(); 8 | 9 | const codeblock = `qBittorrent ${data.qbittorrent || "5.1.2"} was built with the following libraries: 10 | Qt: ${data.qt6 || "6.9.1"} 11 | Libtorrent: ${data.libtorrent_2_0 || "2.0.11"} 12 | Boost: ${data.boost || "1.89.0"} 13 | OpenSSL: ${data.openssl || "3.5.2"} 14 | zlib: ${data.zlib || "1.3.1.1"}-motley`; 15 | 16 | // { 17 | // "glibc_2_31": "2.31", 18 | // "glibc_2_38": "2.38", 19 | // "zlib": "1.3.1", 20 | // "iconv": "1.17", 21 | // "icu": "74-2", 22 | // "openssl": "3.2.1", 23 | // "boost": "1.84.0", 24 | // "libtorrent_1_2": "1.2.19", 25 | // "libtorrent_2_0": "2.0.10", 26 | // "double_conversion": "3.3.0", 27 | // "qt5": "5.15.13", 28 | // "qt6": "6.6.2", 29 | // "qbittorrent": "4.6.3" 30 | // } 31 | --- 32 | 33 | 34 | -------------------------------------------------------------------------------- /docs/src/content/docs/credits.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Credits 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | 35 | 36 | 37 | 42 | -------------------------------------------------------------------------------- /patches/qbittorrent/4.4.4/patch: -------------------------------------------------------------------------------- 1 | From 034fc8aca914f073e5478a46ce9025c862902e72 Mon Sep 17 00:00:00 2001 2 | From: "Vladimir Golovnev (Glassez)" 3 | Date: Wed, 24 Aug 2022 15:28:30 +0300 4 | Subject: [PATCH] Fix missing trackers from magnet link 5 | 6 | --- 7 | src/base/bittorrent/session.cpp | 7 +++++++ 8 | 1 file changed, 7 insertions(+) 9 | 10 | diff --git a/src/base/bittorrent/session.cpp b/src/base/bittorrent/session.cpp 11 | index ece6f6ee8c1..c19d68348c9 100644 12 | --- a/src/base/bittorrent/session.cpp 13 | +++ b/src/base/bittorrent/session.cpp 14 | @@ -4915,7 +4915,14 @@ void Session::handleMetadataReceivedAlert(const lt::metadata_received_alert *p) 15 | 16 | if (downloadedMetadataIter != m_downloadedMetadata.end()) 17 | { 18 | +#if LIBTORRENT_VERSION_NUM >= 20007 19 | + lt::torrent_info nativeInfo = *p->handle.torrent_file(); 20 | + for (const lt::announce_entry &announceEntry : p->handle.trackers()) 21 | + nativeInfo.add_tracker(announceEntry.url, announceEntry.tier); 22 | + const TorrentInfo metadata {nativeInfo}; 23 | +#else 24 | const TorrentInfo metadata {*p->handle.torrent_file()}; 25 | +#endif 26 | 27 | m_downloadedMetadata.erase(downloadedMetadataIter); 28 | --m_extraLimit; 29 | -------------------------------------------------------------------------------- /docs/ec.config.mjs: -------------------------------------------------------------------------------- 1 | import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections"; 2 | import { ExpressiveCodeTheme } from "@astrojs/starlight/expressive-code"; 3 | import { readFileSync } from "node:fs"; 4 | 5 | // Load theme files as raw strings (supports JSON with comments/trailing commas) 6 | const jsoncStringLight = readFileSync( 7 | "./src/themes/expressive-code/Snazzy-Light-color-theme.json", 8 | "utf-8" 9 | ); 10 | const jsoncStringDark = readFileSync( 11 | "./src/themes/expressive-code/aura-soft-dark-soft-text-color-theme.json", 12 | "utf-8" 13 | ); 14 | 15 | // Create themes from raw JSONC strings 16 | const darkMode = ExpressiveCodeTheme.fromJSONString(jsoncStringDark); 17 | const lightMode = ExpressiveCodeTheme.fromJSONString(jsoncStringLight); 18 | 19 | /** @type {import('@astrojs/starlight/expressive-code').StarlightExpressiveCodeOptions} */ 20 | export default { 21 | // Example: Using a custom plugin (which makes this `ec.config.mjs` file necessary) 22 | plugins: [pluginCollapsibleSections()], 23 | defaultProps: { 24 | collapseStyle: "collapsible-start", 25 | frame: "none", 26 | }, 27 | themes: [darkMode, lightMode], 28 | tabWidth: 0, 29 | styleOverrides: { 30 | borderRadius: "0.1rem", 31 | frames: { 32 | shadowColor: "none", 33 | }, 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: An issue with the build script. 3 | body: 4 | - type: markdown 5 | attributes: 6 | value: | 7 | ### When to open an issue. 8 | 9 | If you had an issue with the build script i.e. It failed to build or exited with an error. 10 | 11 | Then please make sure you provide the following information: 12 | 13 | - What Host are you building on? It should be Alpine but Debian based for script bugs is ok. 14 | - What method to Build? If it's not Docker it should be. 15 | - What build options you used? The relevant part of the log file from `qbt-build/logs` 16 | 17 | ### When NOT to open an issue. 18 | 19 | If you are having a problem with `qBittorrent` that is nothing to do with the build script. 20 | 21 | - Read the docs https://userdocs.github.io/qbittorrent-nox-static/ for basic configuration and usage post build. 22 | - If that does not help then open a discussion on the [GitHub Discussions](https://github.com/userdocs/qbittorrent-nox-static/discussions/new/choose) instead of an issue. 23 | - Don't open an issue for generic application issues, only for build script issues. 24 | 25 | - type: textarea 26 | attributes: 27 | label: "What's wrong?" 28 | -------------------------------------------------------------------------------- /docs/public/logo-github.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /docs/src/components/global.jsx: -------------------------------------------------------------------------------- 1 | import AdvancedMarkdown from "/src/components/AdvancedMarkdown.astro"; 2 | import Charts from "/src/components/Charts.astro"; 3 | import Details from "/src/components/Details.astro"; 4 | import GithubActions from "/src/components/GithubActions.astro"; 5 | import Modal from "/src/components/Modal.astro"; 6 | import BuildConfigTool from "/src/components/BuildConfigTool.astro"; 7 | import BuildinfoIntroduction from "/src/components/BuildinfoIntroduction.astro"; 8 | import BuildinfoBuildHelp from "/src/components/BuildinfoBuildHelp.astro"; 9 | import Patchinfo from "/src/components/Patchinfo.astro"; 10 | import Scriptinfo from "/src/components/Scriptinfo.astro"; 11 | import ScriptVersions from "/src/components/ScriptVersions.astro"; 12 | 13 | import { 14 | Aside, 15 | Badge, 16 | Card, 17 | CardGrid, 18 | FileTree, 19 | Icon, 20 | LinkCard, 21 | Steps, 22 | TabItem, 23 | Tabs 24 | } from "@astrojs/starlight/components"; 25 | 26 | export { 27 | AdvancedMarkdown, 28 | Aside, 29 | BuildConfigTool, 30 | Badge, 31 | BuildinfoIntroduction, 32 | BuildinfoBuildHelp, 33 | Card, 34 | CardGrid, 35 | Charts, 36 | Details, 37 | FileTree, 38 | GithubActions, 39 | Icon, 40 | LinkCard, 41 | Modal, 42 | Patchinfo, 43 | Scriptinfo, 44 | ScriptVersions, 45 | Steps, 46 | TabItem, 47 | Tabs 48 | }; 49 | -------------------------------------------------------------------------------- /docs/src/components/Patchinfo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import { Code } from "@astrojs/starlight/components"; 3 | const response = await fetch( 4 | "https://github.com/userdocs/qbt-workflow-files/releases/latest/download/dependency-version.json" 5 | ); 6 | 7 | const data = await response.json(); 8 | 9 | const codeblock = ` 10 | qbt-build/patches/zlib/${data.zlib || "1.3.1"} 11 | qbt-build/patches/iconv/${data.iconv || "1.18"} 12 | qbt-build/patches/icu/${data.icu || "76-1"} 13 | qbt-build/patches/openssl/${data.openssl || "3.2.1"} 14 | qbt-build/patches/boost/${data.boost || "1.87.0"} 15 | qbt-build/patches/libtorrent/${data.libtorrent_2_0 || "2.0.10"} 16 | qbt-build/patches/double_conversion/${data.double_conversion || "3.3.0"} 17 | qbt-build/patches/qtbase/${data.qt6 || "6.8.1"} 18 | qbt-build/patches/qttools/${data.qt6 || "6.8.1"} 19 | qbt-build/patches/qbittorrent/${data.qbittorrent || "5.0.3"} 20 | `; 21 | 22 | // { 23 | // "glibc_2_31": "2.31", 24 | // "glibc_2_38": "2.38", 25 | // "zlib": "1.3.1", 26 | // "iconv": "1.18", 27 | // "icu": "76-1", 28 | // "openssl": "3.4.0", 29 | // "boost": "1.87.0", 30 | // "libtorrent_1_2": "1.2.19", 31 | // "libtorrent_2_0": "2.0.10", 32 | // "double_conversion": "3.3.0", 33 | // "qt5": "5.15.16", 34 | // "qt6": "6.8.1", 35 | // "qbittorrent": "5.0.3" 36 | // } 37 | --- 38 | 39 | 40 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/musl-cross-make.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Musl Cross Make 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Custom musl cross build toolchains based on [musl-cross-make](https://github.com/richfelker/musl-cross-make) 7 | 8 | --- 9 | 10 | The main musl cross make is located here https://github.com/richfelker/musl-cross-make and the tools used here are derived from this. 11 | 12 | This project uses [qbt-musl-cross-make](https://github.com/userdocs/qbt-musl-cross-make) 13 | 14 | Summary: 15 | 16 | - It uses current build dependencies of `gcc` and `binutils`, 17 | - It is optimized by build flags for toolchain and target 18 | - focused on only `cc` and `c++` making for smaller toolchains 19 | - Stays in sync with upstream Alpine target architecture profiles. 20 | - Builds `static-pie` binaries. 21 | - Provides prebuilt releases and docker images 22 | 23 | The build process is fully automated via [Github Actions](https://github.com/userdocs/qbt-musl-cross-make/actions/workflows/ci-main-reusable-caller.yml). 24 | 25 | Release and docker images can be found here: 26 | 27 | Releases: https://github.com/userdocs/qbt-musl-cross-make/releases 28 | 29 | Docker images: https://github.com/userdocs/qbt-musl-cross-make/pkgs/container/qbt-musl-cross-make 30 | 31 | :::note 32 | These are the tool chains used by this project to build static binaries on the Alpine Host, which is the default setup for the github releases. 33 | ::: 34 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy to GitHub Pages 2 | 3 | on: 4 | # Trigger the workflow every time you push to the `main` or `master` branch 5 | # but only if changes occur in the docs/ folder. 6 | push: 7 | branches: [master, main] 8 | paths: 9 | - "docs/**" 10 | - "changelog.md" 11 | # Allows you to run this workflow manually from the Actions tab on GitHub. 12 | workflow_dispatch: 13 | 14 | # Allow this job to clone the repo and create a page deployment 15 | 16 | jobs: 17 | build: 18 | runs-on: ubuntu-24.04-arm 19 | permissions: 20 | contents: read 21 | steps: 22 | - name: Checkout your repository using git 23 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 24 | with: 25 | persist-credentials: false 26 | 27 | - name: Install, build, and upload your site 28 | uses: withastro/action@fd83e9d976da29fe29a0cc268443b7203c18f9ba # v5.0.2 29 | with: 30 | path: ./docs 31 | 32 | deploy: 33 | needs: build 34 | runs-on: ubuntu-24.04-arm 35 | permissions: 36 | pages: write 37 | id-token: write 38 | environment: 39 | name: github-pages 40 | url: ${{ steps.deployment.outputs.page_url }} 41 | steps: 42 | - name: Deploy to GitHub Pages 43 | id: deployment 44 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 45 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = tab 9 | indent_size = 4 10 | 11 | [{**.*sh,test/run,**.bats}] 12 | indent_size = 4 13 | indent_style = tab 14 | 15 | shell_variant = bash 16 | binary_next_line = true # like -bn 17 | switch_case_indent = true # like -ci 18 | space_redirects = true # like -sr 19 | keep_padding = false # like -kp 20 | end_of_line = lf 21 | charset = utf-8 22 | trim_trailing_whitespace = true 23 | insert_final_newline = true 24 | 25 | [**.md] 26 | indent_size = 4 27 | indent_style = space 28 | 29 | [**.bats] 30 | indent_style = tab 31 | shell_variant = bats 32 | 33 | [*.{yml,yaml,html}] 34 | indent_style = space 35 | indent_size = 2 36 | 37 | [*.json] 38 | insert_final_newline = false 39 | indent_style = space 40 | indent_size = 2 41 | 42 | [**.astro] 43 | indent_size = 2 44 | indent_style = tab 45 | end_of_line = lf 46 | 47 | [**.css] 48 | indent_size = 4 49 | indent_style = space 50 | end_of_line = lf 51 | 52 | [LICENSE.txt] 53 | indent_style = space 54 | indent_size = 2 55 | 56 | [**.txt] 57 | 58 | [patch] 59 | indent_style = space 60 | indent_size = 0 61 | trim_trailing_whitespace = false 62 | 63 | [url] 64 | insert_final_newline = false 65 | 66 | [patch] 67 | indent_style = space 68 | indent_size = 0 69 | 70 | [Jamfile] 71 | indent_style = tab 72 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: pre-commit-autoupdate 5 | name: Update pre-commit hooks 6 | entry: pwsh -c "pre-commit autoupdate; git add .pre-commit-config.yaml" 7 | language: system 8 | pass_filenames: false 9 | 10 | - repo: local 11 | hooks: 12 | - id: make-scripts-executable 13 | name: Make script files executable 14 | entry: bash -c 'git add --chmod=+x qi.bash qbt-nox-static.bash qbittorrent-nox-static.sh' 15 | language: system 16 | files: '(qi\.bash|qbt-nox-static\.bash|qbittorrent-nox-static\.sh)$' 17 | pass_filenames: false 18 | 19 | - repo: https://github.com/pre-commit/pre-commit-hooks 20 | rev: v6.0.0 21 | hooks: 22 | - id: check-yaml 23 | - id: end-of-file-fixer 24 | exclude: ^(docs/|patch/) 25 | - id: trailing-whitespace 26 | - id: check-shebang-scripts-are-executable 27 | 28 | - repo: https://github.com/woodruffw/zizmor-pre-commit 29 | rev: v1.18.0 30 | hooks: 31 | - id: zizmor 32 | 33 | - repo: https://github.com/koalaman/shellcheck-precommit 34 | rev: v0.11.0 35 | hooks: 36 | - id: shellcheck 37 | args: ["--severity=warning"] # Optionally only show errors and warnings 38 | 39 | - repo: https://github.com/pecigonzalo/pre-commit-shfmt 40 | rev: v2.2.0 41 | hooks: 42 | - id: shell-fmt 43 | args: ["-ci", "-sr", "-i", "0"] 44 | -------------------------------------------------------------------------------- /docs/src/content/docs/nginx-proxypass.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Nginx proxy 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | ```nginx 31 | location /qbittorrent/ { 32 | proxy_pass http://127.0.0.1:8080/; 33 | proxy_http_version 1.1; 34 | proxy_set_header X-Forwarded-Host $http_host; 35 | http2_push_preload on; # Enable http2 push 36 | 37 | # The following directives effectively nullify Cross-site request forgery (CSRF) 38 | # protection mechanism in qBittorrent, only use them when you encountered connection problems. 39 | # You should consider disable "Enable Cross-site request forgery (CSRF) protection" 40 | # setting in qBittorrent instead of using these directives to tamper the headers. 41 | # The setting is located under "Options -> WebUI tab" in qBittorrent since v4.1.2. 42 | #proxy_hide_header Referer; 43 | #proxy_hide_header Origin; 44 | #proxy_set_header Referer ''; 45 | #proxy_set_header Origin ''; 46 | 47 | # Not needed since qBittorrent v4.1.0 48 | #add_header X-Frame-Options "SAMEORIGIN"; 49 | } 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/public/logo-large-qbittorrent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | qbittorrent-new-light 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /patches/libtorrent/2.0.5/patch: -------------------------------------------------------------------------------- 1 | From dace24541cd35fe139c023be5bbc6eef98b4d229 Mon Sep 17 00:00:00 2001 2 | From: arvidn 3 | Date: Sun, 12 Dec 2021 21:52:15 +0100 4 | Subject: [PATCH] update allocator sizes for boost-1.78 5 | 6 | --- 7 | include/libtorrent/aux_/allocating_handler.hpp | 6 +++--- 8 | 1 file changed, 3 insertions(+), 3 deletions(-) 9 | 10 | diff --git a/include/libtorrent/aux_/allocating_handler.hpp b/include/libtorrent/aux_/allocating_handler.hpp 11 | index 726032e085c..560d738fa8b 100644 12 | --- a/include/libtorrent/aux_/allocating_handler.hpp 13 | +++ b/include/libtorrent/aux_/allocating_handler.hpp 14 | @@ -124,12 +124,12 @@ namespace libtorrent { namespace aux { 15 | #endif 16 | constexpr std::size_t write_handler_max_size = tracking + debug_write_iter + openssl_write_cost + fuzzer_write_cost + 168; 17 | constexpr std::size_t read_handler_max_size = tracking + debug_read_iter + openssl_read_cost + fuzzer_read_cost + 168; 18 | - constexpr std::size_t udp_handler_max_size = tracking + 160; 19 | - constexpr std::size_t utp_handler_max_size = tracking + 184; 20 | + constexpr std::size_t udp_handler_max_size = tracking + 168; 21 | + constexpr std::size_t utp_handler_max_size = tracking + 192; 22 | constexpr std::size_t abort_handler_max_size = tracking + 72; 23 | constexpr std::size_t submit_handler_max_size = tracking + 72; 24 | constexpr std::size_t deferred_handler_max_size = tracking + 80; 25 | - constexpr std::size_t tick_handler_max_size = tracking + 128; 26 | + constexpr std::size_t tick_handler_max_size = tracking + 136; 27 | #endif 28 | 29 | enum HandlerName -------------------------------------------------------------------------------- /docs/public/logo-qbittorrent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | qbittorrent-new-light 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /patches/qbittorrent/5.0.4/patch: -------------------------------------------------------------------------------- 1 | --- qBittorrent/src/base/http/types.h 2025-04-02 12:18:36.006314368 +0100 2 | +++ types.h 2025-03-03 09:24:36.686864000 +0000 3 | @@ -29,9 +29,12 @@ 4 | 5 | #pragma once 6 | 7 | +#include 8 | +#include 9 | #include 10 | +#include 11 | +#include 12 | #include 13 | -#include 14 | 15 | #include "base/global.h" 16 | 17 | @@ -57,6 +60,7 @@ 18 | inline const QString HEADER_X_CONTENT_TYPE_OPTIONS = u"x-content-type-options"_s; 19 | inline const QString HEADER_X_FORWARDED_FOR = u"x-forwarded-for"_s; 20 | inline const QString HEADER_X_FORWARDED_HOST = u"x-forwarded-host"_s; 21 | + inline const QString HEADER_X_FORWARDED_PROTO = u"X-forwarded-proto"_s; 22 | inline const QString HEADER_X_FRAME_OPTIONS = u"x-frame-options"_s; 23 | inline const QString HEADER_X_XSS_PROTECTION = u"x-xss-protection"_s; 24 | 25 | @@ -75,7 +79,7 @@ 26 | inline const QString CONTENT_TYPE_FORM_DATA = u"multipart/form-data"_s; 27 | 28 | // portability: "\r\n" doesn't guarantee mapping to the correct symbol 29 | - inline const char CRLF[] = {0x0D, 0x0A, '\0'}; 30 | + inline const QByteArray CRLF = QByteArrayLiteral("\x0D\x0A"); 31 | 32 | struct Environment 33 | { 34 | @@ -109,7 +113,7 @@ 35 | HeaderMap headers; 36 | QHash query; 37 | QHash posts; 38 | - QVector files; 39 | + QList files; 40 | }; 41 | 42 | struct ResponseStatus 43 | @@ -129,4 +133,4 @@ 44 | { 45 | } 46 | }; 47 | -} 48 | +} 49 | \ No newline at end of file 50 | -------------------------------------------------------------------------------- /.github/workflows/ci-auto-rerun-failed-jobs-action.yml: -------------------------------------------------------------------------------- 1 | name: ci - auto rerun failed jobs 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | run_id: 7 | description: "The run id of the workflow to rerun" 8 | required: true 9 | attempts: 10 | description: "The number of attempts to rerun the workflow" 11 | required: true 12 | retries: 13 | description: "The number of retries to rerun the workflow" 14 | required: true 15 | github_repo: 16 | description: "The repository to rerun the workflow" 17 | required: false 18 | distinct_id: 19 | description: "The distinct id of the workflow to rerun" 20 | required: false 21 | 22 | run-name: ci auto rerun failed jobs - attempt ${{ inputs.attempts }} 23 | 24 | jobs: 25 | gh-cli-rerun: 26 | name: rerun - attempt ${{ inputs.attempts }} 27 | permissions: 28 | actions: write 29 | runs-on: ubuntu-24.04-arm 30 | env: 31 | GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" 32 | steps: 33 | - name: Host - Checkout action ${{ inputs.distinct_id }} 34 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 35 | with: 36 | persist-credentials: false 37 | 38 | - uses: userdocs/gh-cli-workflow-reruns/actions/auto-rerun-failed@95ab77b1c4a1a8667e2f153ffc9a17048a961122 # v1.0.1 39 | with: 40 | run_id: ${{ inputs.run_id }} 41 | attempts: ${{ inputs.attempts }} 42 | retries: ${{ inputs.retries }} 43 | github_repo: ${{ inputs.github_repo || github.repository }} 44 | distinct_id: ${{ inputs.distinct_id || github.run_id }} 45 | -------------------------------------------------------------------------------- /docs/src/content/docs/debugging.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Debugging 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | :::note 31 | By default the static builds are built with the debug symbols stripped out to reduce the file size. 32 | ::: 33 | 34 | To properly debug a segfault we need to use a build with libtorrent and qBittorrent debug symbols included. 35 | 36 | Some reasons I don't release them here: 37 | - static builds using `b2` the libtorrent debug symbols can add 100MB to the file size. 38 | - static builds using `cmake` are about 15MB larger and potentially slower. 39 | - It doubles the build time. 40 | - It's not needed for most users. 41 | 42 | The easiest way to get a debug build is to build it yourself by 43 | 44 | - [forking the repo](https://github.com/userdocs/qbittorrent-nox-static/fork) the repo and running the `ci-main-reusable-caller.yml` workflow with the debug flag enabled. 45 | 46 | ![](/qbittorrent-nox-static/docs_images/reusable_workflow_inputs-debug.png) 47 | 48 | :::tip 49 | The builds will be uploaded as artifacts to the workflow run and can be downloaded from there. 50 | ::: 51 | 52 | - Build it yourself locally 53 | 54 | This can be done when building locally by using the `-d` flag or `export qbt_build_debug=on` 55 | 56 | Then you will have a debug build with the debug symbols included to get a stack traces using [gdb](https://www.gnu.org/software/gdb/). 57 | -------------------------------------------------------------------------------- /docs/public/logo-alpine.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/src/pages/glossary.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro"; 3 | 4 | interface GlossaryEntry { 5 | file: string; 6 | frontmatter: { 7 | title: string; 8 | }; 9 | } 10 | 11 | interface File { 12 | fileBase: string; 13 | title: string; 14 | } 15 | 16 | const basePath = `/${Astro.url.pathname.split("/")[1]}`; 17 | 18 | // Get all markdown files 19 | const posts = import.meta.glob( 20 | "/src/content/docs/glossary/*.md", 21 | { 22 | eager: true, 23 | } 24 | ); 25 | 26 | // Convert posts object to array and map to File[] 27 | const files: File[] = Object.entries(posts).map(([path, post]) => { 28 | const fileBase = path.split("/").pop()?.split(".").shift() ?? ""; 29 | return { 30 | fileBase, 31 | title: post.frontmatter.title, 32 | }; 33 | }); 34 | 35 | // Group files by first letter 36 | const sections = files.reduce((acc: { [key: string]: File[] }, file) => { 37 | const firstLetter = file.title.charAt(0).toUpperCase(); 38 | if (!acc[firstLetter]) { 39 | acc[firstLetter] = []; 40 | } 41 | acc[firstLetter].push(file); 42 | return acc; 43 | }, {}); 44 | 45 | // Generate headings for each section 46 | const headings = Object.entries(sections) 47 | .sort(([a], [b]) => a.localeCompare(b)) 48 | .map(([slug]) => ({ 49 | depth: 2, 50 | slug, 51 | text: slug, 52 | })); 53 | --- 54 | 55 | 56 | { 57 | Object.entries(sections).map(([sectionTitle, files]: [string, File[]]) => ( 58 | <> 59 |

{sectionTitle}

60 |
    61 | {files.map(({ fileBase, title }: File) => ( 62 |
  • 63 | {title} 64 |
  • 65 | ))} 66 |
67 | 68 | )) 69 | } 70 |
71 | -------------------------------------------------------------------------------- /patches/qbittorrent/4.4.3.1/patch: -------------------------------------------------------------------------------- 1 | --- qBittorrent/src/base/net/downloadhandlerimpl.cpp 2 | +++ /home/username/downloadhandlerimpl.cpp 3 | @@ -34,10 +34,13 @@ 4 | 5 | #include "base/3rdparty/expected.hpp" 6 | #include "base/utils/fs.h" 7 | -#include "base/utils/gzip.h" 8 | #include "base/utils/io.h" 9 | #include "base/utils/misc.h" 10 | 11 | +#ifdef QT_NO_COMPRESS 12 | +#include "base/utils/gzip.h" 13 | +#endif 14 | + 15 | const int MAX_REDIRECTIONS = 20; // the common value for web browsers 16 | 17 | namespace 18 | @@ -121,9 +124,13 @@ 19 | } 20 | 21 | // Success 22 | +#ifdef QT_NO_COMPRESS 23 | m_result.data = (m_reply->rawHeader("Content-Encoding") == "gzip") 24 | ? Utils::Gzip::decompress(m_reply->readAll()) 25 | : m_reply->readAll(); 26 | +#else 27 | + m_result.data = m_reply->readAll(); 28 | +#endif 29 | 30 | if (m_downloadRequest.saveToFile()) 31 | { 32 | --- qBittorrent/src/base/net/downloadmanager.cpp 33 | +++ /home/username/downloadmanager.cpp 34 | @@ -123,8 +123,12 @@ 35 | 36 | // Spoof HTTP Referer to allow adding torrent link from Torcache/KickAssTorrents 37 | request.setRawHeader("Referer", request.url().toEncoded().data()); 38 | - // Accept gzip 39 | +#ifdef QT_NO_COMPRESS 40 | + // The macro "QT_NO_COMPRESS" defined in QT will disable the zlib releated features 41 | + // and reply data auto-decompression in QT will also be disabled. But we can support 42 | + // gzip encoding and manually decompress the reply data. 43 | request.setRawHeader("Accept-Encoding", "gzip"); 44 | +#endif 45 | // Qt doesn't support Magnet protocol so we need to handle redirections manually 46 | request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy); 47 | 48 | -------------------------------------------------------------------------------- /docs/public/icons/note-circle.svg: -------------------------------------------------------------------------------- 1 | 2 | 46 | 47 | 48 | 54 | -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- 1 | 2 | 52 | -------------------------------------------------------------------------------- /docs/public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 52 | -------------------------------------------------------------------------------- /patches/libtorrent/2.0.4/patch: -------------------------------------------------------------------------------- 1 | From c7281a6d2fc2cbe34a567bdbe1f08a1fe89bd28a Mon Sep 17 00:00:00 2001 2 | From: arvidn 3 | Date: Thu, 19 Aug 2021 11:54:13 +0200 4 | Subject: [PATCH] bump handler allocation sizes for boost-1.77 (linux) 5 | 6 | --- 7 | include/libtorrent/aux_/allocating_handler.hpp | 10 +++++----- 8 | 1 file changed, 5 insertions(+), 5 deletions(-) 9 | 10 | diff --git a/include/libtorrent/aux_/allocating_handler.hpp b/include/libtorrent/aux_/allocating_handler.hpp 11 | index 9d826d11a1..b24349850e 100644 12 | --- a/include/libtorrent/aux_/allocating_handler.hpp 13 | +++ b/include/libtorrent/aux_/allocating_handler.hpp 14 | @@ -122,14 +122,14 @@ namespace libtorrent { namespace aux { 15 | constexpr std::size_t fuzzer_write_cost = 0; 16 | constexpr std::size_t fuzzer_read_cost = 0; 17 | #endif 18 | - constexpr std::size_t write_handler_max_size = tracking + debug_write_iter + openssl_write_cost + fuzzer_write_cost + 152; 19 | - constexpr std::size_t read_handler_max_size = tracking + debug_read_iter + openssl_read_cost + fuzzer_read_cost + 152; 20 | - constexpr std::size_t udp_handler_max_size = tracking + 144; 21 | - constexpr std::size_t utp_handler_max_size = tracking + 168; 22 | + constexpr std::size_t write_handler_max_size = tracking + debug_write_iter + openssl_write_cost + fuzzer_write_cost + 168; 23 | + constexpr std::size_t read_handler_max_size = tracking + debug_read_iter + openssl_read_cost + fuzzer_read_cost + 168; 24 | + constexpr std::size_t udp_handler_max_size = tracking + 160; 25 | + constexpr std::size_t utp_handler_max_size = tracking + 184; 26 | constexpr std::size_t abort_handler_max_size = tracking + 72; 27 | constexpr std::size_t submit_handler_max_size = tracking + 72; 28 | constexpr std::size_t deferred_handler_max_size = tracking + 80; 29 | - constexpr std::size_t tick_handler_max_size = tracking + 112; 30 | + constexpr std::size_t tick_handler_max_size = tracking + 128; 31 | #endif 32 | 33 | enum HandlerName -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Starlight Starter Kit: Basics 2 | 3 | [![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build) 4 | 5 | ``` 6 | npm create astro@latest -- --template starlight 7 | ``` 8 | 9 | > 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun! 10 | 11 | ## 🚀 Project Structure 12 | 13 | Inside of your Astro + Starlight project, you'll see the following folders and files: 14 | 15 | ``` 16 | . 17 | ├── public/ 18 | ├── src/ 19 | │ ├── assets/ 20 | │ ├── content/ 21 | │ │ └── docs/ 22 | │ └── content.config.ts 23 | ├── astro.config.mjs 24 | ├── package.json 25 | └── tsconfig.json 26 | ``` 27 | 28 | Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name. 29 | 30 | Images can be added to `src/assets/` and embedded in Markdown with a relative link. 31 | 32 | Static assets, like favicons, can be placed in the `public/` directory. 33 | 34 | ## 🧞 Commands 35 | 36 | All commands are run from the root of the project, from a terminal: 37 | 38 | | Command | Action | 39 | | :------------------------ | :----------------------------------------------- | 40 | | `npm install` | Installs dependencies | 41 | | `npm run dev` | Starts local dev server at `localhost:4321` | 42 | | `npm run build` | Build your production site to `./dist/` | 43 | | `npm run preview` | Preview your build locally, before deploying | 44 | | `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | 45 | | `npm run astro -- --help` | Get help using the Astro CLI | 46 | 47 | ## 👀 Want to learn more? 48 | 49 | Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat). 50 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/bash.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Bash Shell 3 | hide_title: true 4 | --- 5 | 6 | 🟦 Bash is the GNU Project's shell—the Bourne Again SHell. This is an sh-compatible shell that incorporates useful features from the Korn shell (ksh) and the C shell (csh). It is intended to conform to the IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools standard. It offers functional improvements over sh for both programming and interactive use. In addition, most sh scripts can be run by Bash without modification. 7 | 8 | --- 9 | 10 | Shells are command interpreters. They are applications that provide users with the ability to give commands to their operating system interactively, or to execute batches of commands quickly. In no way are they required for the execution of programs; they are merely a layer between system function calls and the user. 11 | 12 | Think of a shell as a way for you to speak to your system. Your system doesn't need it for most of its work, but it is an excellent interface between you and what your system can offer. It allows you to perform basic math, run basic tests and execute applications. More importantly, it allows you to combine these operations and connect applications to each other to perform complex and automated tasks. 13 | 14 | BASH is not your operating system. It is not your window manager. It is not your terminal (but it often runs inside your terminal). It does not control your mouse or keyboard. It does not configure your system, activate your screensaver, or open your files when you double-click them. It is generally not involved in launching applications from your window manager or desktop environment. It's important to understand that BASH is only an interface for you to execute statements (using BASH syntax), either at the interactive BASH prompt or via BASH scripts. 15 | 16 | Website: 17 | 18 | - https://www.gnu.org/software/bash/ 19 | 20 | Guides: 21 | 22 | - https://mywiki.wooledge.org/BashGuide 23 | - https://www.gnu.org/software/bash/manual/bash.html 24 | -------------------------------------------------------------------------------- /docs/src/content/docs/glossary/github-workflows.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github Workflows 3 | hide_title: true 4 | --- 5 | 6 | 🟦 A workflow is a configurable automated process that will run one or more jobs. Workflows are defined by a YAML file checked in to your repository and will run when triggered by an event in your repository, or they can be triggered manually, or at a defined schedule. 7 | 8 | --- 9 | 10 | Workflows are defined in the `.github/workflows directory` in a repository, and a repository can have multiple workflows, each of which can perform a different set of tasks. For example, you can have one workflow to build and test pull requests, another workflow to deploy your application every time a release is created, and still another workflow that adds a label every time someone opens a new issue. 11 | 12 | Github workflows are typically stored in the Github as `.github/workflows/workflow-name.yml` in the project repo. 13 | 14 | In a nutshell a workflow is a special syntax to define some tasks you want done on what are called runners like `ubuntu-latest`. 15 | 16 | You use a combination of `yaml` and scripting/shell languages to define the some criteria and then create steps towards completion of a job. 17 | 18 | This project uses them to build and release static binaries and here is an example of on of the files that build releases using the workflow files. 19 | 20 | Action overview for this workflows: [matrix_multi_build_and_release_qbt_workflow_files.yml](https://github.com/userdocs/qbittorrent-nox-static/actions/workflows/matrix_multi_build_and_release_qbt_workflow_files.yml) 21 | 22 | The workflow file itself: [matrix_multi_build_and_release_qbt_workflow_files.yml](https://github.com/userdocs/qbittorrent-nox-static/blob/master/.github/workflows/matrix_multi_build_and_release_qbt_workflow_files.yml) 23 | 24 | If you would like to know more about creating workflows you should read the excellent Github docs. 25 | 26 | https://docs.github.com/en/actions/learn-github-actions/understanding-github-actions 27 | 28 | https://docs.github.com/en/actions/using-workflows/about-workflows 29 | -------------------------------------------------------------------------------- /.claude/agents/bash-expert.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: bash-expert 3 | description: Specialized bash scripting expert for writing, debugging, and optimizing shell scripts. Invoked for bash/shell scripting tasks, script analysis, debugging, and Unix/Linux automation. 4 | tools: [Read, Write, Edit, MultiEdit, Bash, Glob, Grep] 5 | --- 6 | 7 | You are a bash scripting expert with 15+ years of Unix/Linux experience. Follow all the bash scripting guidelines defined in the project CLAUDE.md file exactly. Always use shellcheck and shfmt formatting with `shfmt -s -bn -ci -sr -i 0`. 8 | 9 | ## Core Expertise 10 | - Advanced bash scripting with proper error handling and quoting 11 | - Shell script optimization and security best practices 12 | - Command-line tools and Unix philosophy: "do one thing well" 13 | - Text processing with sed, awk, grep, and bash built-ins 14 | - System automation and maintenance scripts 15 | 16 | ## Key Requirements 17 | - **Never use `echo`** - always use `printf '%s'` for plain strings and `printf '%b'` for escape sequences 18 | - Use `#!/bin/bash` shebang and `.bash` extensions for Bash scripts 19 | - Quote variables properly (`"$var"` not `$var`) 20 | - Prefer bash built-ins over external commands when possible 21 | - Keep solutions minimal and focused on the exact prompt 22 | - Always run shellcheck on scripts and format with shfmt 23 | - Use Google's Shell Style Guide standards 24 | - Reference mywiki.wooledge.org for best practices (provide real links only) 25 | 26 | ## Response Pattern 27 | 1. Provide working code solution with proper error handling 28 | 2. Explain the approach and key bash concepts 29 | 3. Highlight best practices and common pitfalls 30 | 4. Run shellcheck and shfmt validation 31 | 5. Suggest alternatives when relevant 32 | 33 | ## Conservative Approach 34 | - Implement only what the prompt requests 35 | - Keep changes simple, modular, and scoped 36 | - Preserve existing behavior unless explicitly asked to change 37 | - Avoid over-engineering and speculative changes 38 | 39 | Focus on writing secure, robust, and efficient bash scripts that follow the Unix philosophy and modern bash best practices. 40 | -------------------------------------------------------------------------------- /docs/src/components/ScriptVersions.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import fs from "node:fs/promises"; 3 | import { Badge } from "@astrojs/starlight/components"; 4 | 5 | type Props = { 6 | // Render mode: 7 | // - "sentence": badge + human-friendly text 8 | // - "values": just the version string 9 | mode?: "sentence" | "values"; 10 | // Optional script filename at repo root (e.g., "qbt-nox-static.bash", "qi.bash"). 11 | file?: string; 12 | // Optional label for the badge in "sentence" mode. 13 | label?: string; 14 | // Optional prefix before the version (default: "v"). Use "" to disable. 15 | prefix?: string; 16 | }; 17 | 18 | const { 19 | mode = "sentence", 20 | file = "qbt-nox-static.bash", 21 | label = "Latest version", 22 | prefix = "v", 23 | } = Astro.props as Props; 24 | 25 | async function readVersion(relPath: string): Promise { 26 | try { 27 | // Build a file URL relative to this component's location 28 | const url = new URL(relPath, import.meta.url); 29 | const content = await fs.readFile(url, "utf8"); 30 | // More robust match: allow spaces and single/double quotes 31 | const match = content.match( 32 | /(?:^|\n)\s*script_version\s*=\s*(["'])([^"']+)\1/, 33 | ); 34 | return match?.[2] ?? "unknown"; 35 | } catch { 36 | return "unknown"; 37 | } 38 | } 39 | 40 | // Scripts live at the repository root; this component is at docs/src/components/ 41 | // So we traverse up three directories to reach the repo root. 42 | const version = await readVersion(`../../../${file}`); 43 | const isKnown = version !== "unknown"; 44 | const normalizedVersion = typeof version === "string" ? version.trim() : ""; 45 | const displayVersion = isKnown 46 | ? prefix === "" 47 | ? normalizedVersion 48 | : `${prefix}${normalizedVersion}` 49 | : "unknown"; 50 | --- 51 | 52 | <> 53 | { 54 | mode === "values" ? ( 55 | {displayVersion} 56 | ) : ( 57 | <> 58 | 62 | 63 | {displayVersion} 64 | 65 | ) 66 | } 67 | 68 | -------------------------------------------------------------------------------- /docs/public/logo-musl - Copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/public/logo-musl.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | -------------------------------------------------------------------------------- /.github/workflows/ci-checks.yml: -------------------------------------------------------------------------------- 1 | name: ci - checks 2 | on: 3 | push: 4 | pull_request: 5 | workflow_dispatch: 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.ref }} 9 | cancel-in-progress: true 10 | 11 | permissions: {} 12 | 13 | jobs: 14 | sh-checker: 15 | runs-on: ubuntu-24.04-arm 16 | steps: 17 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 18 | with: 19 | persist-credentials: false 20 | 21 | - name: Run the sh-checker 22 | uses: luizm/action-sh-checker@17bd25a6ee188d2b91f677060038f4ba37ba14b2 # v0.9.0 23 | env: 24 | GITHUB_TOKEN: ${{ github.token }} 25 | SHELLCHECK_OPTS: -e SC2034,SC1091 # It is possible to exclude some shellcheck warnings. 26 | SHFMT_OPTS: -ci -sr -i 0 # It is possible to pass arguments to shftm 27 | with: 28 | sh_checker_comment: true 29 | sh_checker_exclude: "" 30 | 31 | zizmor-checker: 32 | runs-on: ubuntu-24.04-arm 33 | permissions: 34 | security-events: write 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 38 | with: 39 | persist-credentials: false 40 | 41 | - name: Run zizmor 🌈 42 | uses: zizmorcore/zizmor-action@e639db99335bc9038abc0e066dfcd72e23d26fb4 # v0.3.0 43 | 44 | editorconfig-checker: 45 | runs-on: ubuntu-24.04-arm 46 | steps: 47 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 48 | with: 49 | persist-credentials: false 50 | 51 | - name: editorconfig-checker 52 | env: 53 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 54 | runner_arch: ${{ runner.arch }} 55 | run: | 56 | case "${runner_arch}" in 57 | X86 | X64) 58 | arch="amd64" 59 | ;; 60 | ARM | ARM64) 61 | arch="arm64" 62 | ;; 63 | esac 64 | 65 | curl -Lo- "https://github.com/editorconfig-checker/editorconfig-checker/releases/latest/download/ec-linux-${arch}.tar.gz" | tar xzf - --strip-components=1 66 | ./ec-linux-${arch} --exclude '^(docs/.*|patches/.*)$' | sed 's/\x1b\[[0-9;]*m//g' | { printf '%b\n' '```bash' >> "$GITHUB_STEP_SUMMARY"; tee -a "$GITHUB_STEP_SUMMARY"; printf '%b\n' '```' >> "$GITHUB_STEP_SUMMARY"; } 67 | exit_code=("${PIPESTATUS[0]}") 68 | # exit "${exit_code}" 69 | -------------------------------------------------------------------------------- /docs/src/content/docs/rules-of-engagement.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rules of Engagement 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | ⭐ The rules of engagement are: 31 | 32 | 33 | 34 | 1. ### Use Docker 35 | 36 | - Docker is the recommended method for building with the script. 37 | - This avoids many potential issues and conflicts with the host system, especially with Qt. 38 | 39 | 2. ### Use Alpine 40 | 41 | - Alpine is the main supported system; Debian is for testing and fallback. 42 | - You do not need to build on an older host to use these binaries there. 43 | 44 | 3. ### Privileges 45 | 46 | - `sudo` or `root` privileges are not required to run the script. 47 | - They are only required to install core dependencies if they are missing. 48 | 49 | 4. ### Additional flags and switches 50 | 51 | - Can add dependencies on demand that will need to be installed. 52 | - For example, `-c` for CMake and `-cd` for cache dependencies. 53 | - The script will require you to install these on demand. 54 | - Using `.qbt_env` or setting variables before running the script will handle this automatically. 55 | 56 | 5. ### Passing no arguments 57 | 58 | - `qbt-nox-static.bash` - will make no changes and instead provide information on what you need to do. 59 | - `qbittorrent-nox-static.sh` - will automatically install the required dependencies and configure the build environment. 60 | 61 | 6. ### Nothing is built until... 62 | 63 | - You provide the `all` argument or a specific module name as a positional parameter to the script. 64 | - This applies to both `qbt-nox-static.bash` and `qbittorrent-nox-static.sh`. 65 | 66 | 7. ### Use the help 67 | 68 | - Use `bash ~/qbt.bash -h` to see the help. 69 | - This applies to both `qbt-nox-static.bash` and `qbittorrent-nox-static.sh`. 70 | 71 | 8. ### Fork the repo 72 | 73 | - Build on GitHub using GitHub Actions to create your own custom releases. 74 | - This is the easiest way to get custom builds for your needs. 75 | 76 | 77 | -------------------------------------------------------------------------------- /docs/src/content/docs/systemd.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Systemd 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | ### Systemd service 31 | 32 | Location for the systemd service file: 33 | 34 | ```bash 35 | /etc/systemd/system/qbittorrent.service 36 | ``` 37 | 38 | Modify the path to the binary and your local username. 39 | 40 | ```ini 41 | [Unit] 42 | Description=qBittorrent-nox service 43 | Wants=network-online.target 44 | After=network-online.target nss-lookup.target 45 | 46 | [Service] 47 | Type=exec 48 | User=qbtuser 49 | ExecStart=/usr/local/bin/qbittorrent-nox 50 | Restart=on-failure 51 | SyslogIdentifier=qbittorrent-nox 52 | 53 | [Install] 54 | WantedBy=multi-user.target 55 | ``` 56 | 57 | After any changes to the services reload using this command. 58 | 59 | ```bash 60 | systemctl daemon-reload 61 | ``` 62 | 63 | Now you can enable the service 64 | 65 | ```bash 66 | systemctl enable --now qbittorrent.service 67 | ``` 68 | 69 | Now you can use these commands 70 | 71 | ```bash 72 | systemctl stop qbittorrent 73 | systemctl start qbittorrent 74 | systemctl restart qbittorrent 75 | ``` 76 | 77 | ### Systemd user service 78 | 79 | You can also use a local systemd service. 80 | 81 | ```bash 82 | ~/.config/systemd/user/qbittorrent.service 83 | ``` 84 | 85 | You can use this configuration with no modification required. 86 | 87 | ```ini 88 | [Unit] 89 | Description=qbittorrent 90 | Wants=network-online.target 91 | After=network-online.target nss-lookup.target 92 | 93 | [Service] 94 | Type=exec 95 | ExecStart=%h/bin/qbittorrent-nox 96 | Restart=on-failure 97 | SyslogIdentifier=qbittorrent-nox 98 | 99 | [Install] 100 | WantedBy=default.target 101 | ``` 102 | 103 | After any changes to the services reload using this command. 104 | 105 | ```bash 106 | systemctl --user daemon-reload 107 | ``` 108 | 109 | Now you can enable the service 110 | 111 | ```bash 112 | systemctl --user enable --now qbittorrent 113 | ``` 114 | 115 | Now you can use these commands 116 | 117 | ```bash 118 | systemctl --user stop qbittorrent 119 | systemctl --user start qbittorrent 120 | systemctl --user restart qbittorrent 121 | ``` 122 | -------------------------------------------------------------------------------- /patches/qtbase/6.7.2/patch: -------------------------------------------------------------------------------- 1 | From 8bb2a0c02b305f8ae8611e501fe7dd3d2b4468a6 Mon Sep 17 00:00:00 2001 2 | From: Joerg Bornemann 3 | Date: Tue, 11 Jun 2024 10:47:18 +0200 4 | Subject: [PATCH] CMake: Re-enable lupdate/lconvert/lrelease in no-gui builds 5 | 6 | This reverts 8dba0e48a0f7d3487b318a74f80f2d8e59c320f9 which disabled the 7 | 'linguist' feature if the 'printsupport' feature wasn't available. 8 | However, the 'linguist' feature controls not only the Qt Linguist 9 | application but also the command line tools lupdate, lconvert, and 10 | lrelease. In no-gui builds, which also disable printsupport, the command 11 | line tools were unexpectedly missing. 12 | 13 | Fix the issue by extending the feature condition in 14 | src/linguist/CMakeLists.txt. As drive-by, fix the FEATURE_png condition 15 | that was still in QMake form from the initial conversion. 16 | 17 | Fixes: QTBUG-126189 18 | Task-number: QTBUG-125066 19 | Change-Id: I59ebb82fd5823165b307ffbc967d7fd89a071ede 20 | Reviewed-by: Alexey Edelev 21 | Reviewed-by: Alexandru Croitor 22 | (cherry picked from commit 4be1823e4d459c89717e791ef27fd463ad04cb2b) 23 | Reviewed-by: Qt Cherry-pick Bot 24 | (cherry picked from commit aa9f8db49db2e7734c187445b8c3c56768f6e546) 25 | --- 26 | configure.cmake | 1 - 27 | src/linguist/CMakeLists.txt | 3 ++- 28 | 2 files changed, 2 insertions(+), 2 deletions(-) 29 | 30 | diff --git a/configure.cmake b/configure.cmake 31 | index 813789e9f7..7d9ab8724f 100644 32 | --- a/configure.cmake 33 | +++ b/configure.cmake 34 | @@ -74,7 +74,6 @@ qt_feature("kmap2qmap" PRIVATE 35 | qt_feature("linguist" PRIVATE 36 | LABEL "Qt Linguist" 37 | PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications." 38 | - CONDITION TARGET Qt::PrintSupport 39 | ) 40 | qt_feature("pixeltool" PRIVATE 41 | LABEL "pixeltool" 42 | diff --git a/src/linguist/CMakeLists.txt b/src/linguist/CMakeLists.txt 43 | index ab2169dec5..20ec247337 100644 44 | --- a/src/linguist/CMakeLists.txt 45 | +++ b/src/linguist/CMakeLists.txt 46 | @@ -14,7 +14,8 @@ add_subdirectory(lrelease) 47 | add_subdirectory(lrelease-pro) 48 | add_subdirectory(lupdate) 49 | add_subdirectory(lupdate-pro) 50 | -if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png) 51 | +if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton 52 | + AND QT_FEATURE_png AND QT_FEATURE_printsupport AND TARGET Qt::Widgets) 53 | add_subdirectory(linguist) 54 | endif() 55 | 56 | -- 57 | 2.16.3 58 | -------------------------------------------------------------------------------- /patches/qttools/6.7.2/patch: -------------------------------------------------------------------------------- 1 | From 8bb2a0c02b305f8ae8611e501fe7dd3d2b4468a6 Mon Sep 17 00:00:00 2001 2 | From: Joerg Bornemann 3 | Date: Tue, 11 Jun 2024 10:47:18 +0200 4 | Subject: [PATCH] CMake: Re-enable lupdate/lconvert/lrelease in no-gui builds 5 | 6 | This reverts 8dba0e48a0f7d3487b318a74f80f2d8e59c320f9 which disabled the 7 | 'linguist' feature if the 'printsupport' feature wasn't available. 8 | However, the 'linguist' feature controls not only the Qt Linguist 9 | application but also the command line tools lupdate, lconvert, and 10 | lrelease. In no-gui builds, which also disable printsupport, the command 11 | line tools were unexpectedly missing. 12 | 13 | Fix the issue by extending the feature condition in 14 | src/linguist/CMakeLists.txt. As drive-by, fix the FEATURE_png condition 15 | that was still in QMake form from the initial conversion. 16 | 17 | Fixes: QTBUG-126189 18 | Task-number: QTBUG-125066 19 | Change-Id: I59ebb82fd5823165b307ffbc967d7fd89a071ede 20 | Reviewed-by: Alexey Edelev 21 | Reviewed-by: Alexandru Croitor 22 | (cherry picked from commit 4be1823e4d459c89717e791ef27fd463ad04cb2b) 23 | Reviewed-by: Qt Cherry-pick Bot 24 | (cherry picked from commit aa9f8db49db2e7734c187445b8c3c56768f6e546) 25 | --- 26 | configure.cmake | 1 - 27 | src/linguist/CMakeLists.txt | 3 ++- 28 | 2 files changed, 2 insertions(+), 2 deletions(-) 29 | 30 | diff --git a/configure.cmake b/configure.cmake 31 | index 813789e9f7..7d9ab8724f 100644 32 | --- a/configure.cmake 33 | +++ b/configure.cmake 34 | @@ -74,7 +74,6 @@ qt_feature("kmap2qmap" PRIVATE 35 | qt_feature("linguist" PRIVATE 36 | LABEL "Qt Linguist" 37 | PURPOSE "Qt Linguist can be used by translator to translate text in Qt applications." 38 | - CONDITION TARGET Qt::PrintSupport 39 | ) 40 | qt_feature("pixeltool" PRIVATE 41 | LABEL "pixeltool" 42 | diff --git a/src/linguist/CMakeLists.txt b/src/linguist/CMakeLists.txt 43 | index ab2169dec5..20ec247337 100644 44 | --- a/src/linguist/CMakeLists.txt 45 | +++ b/src/linguist/CMakeLists.txt 46 | @@ -14,7 +14,8 @@ add_subdirectory(lrelease) 47 | add_subdirectory(lrelease-pro) 48 | add_subdirectory(lupdate) 49 | add_subdirectory(lupdate-pro) 50 | -if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton AND TARGET Qt::Widgets AND NOT no-png) 51 | +if(QT_FEATURE_process AND QT_FEATURE_pushbutton AND QT_FEATURE_toolbutton 52 | + AND QT_FEATURE_png AND QT_FEATURE_printsupport AND TARGET Qt::Widgets) 53 | add_subdirectory(linguist) 54 | endif() 55 | 56 | -- 57 | 2.16.3 58 | 59 | -------------------------------------------------------------------------------- /docs/src/content/docs/script-usage.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Script Usage 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | :::caution[Assumptions] 31 | The guide will assume you are using docker, with example commands that are either one liners or from within the container. 32 | ::: 33 | 34 | :::danger 35 | Don't run this directly on the host system unless you know what you are doing. It's not recommended and the build will probably fail. 36 | ::: 37 | 38 | 39 | 40 | 41 | 42 | 43 | ⭐ When you are familiar with the script you can do most builds you want with a one liner. It's pretty simple to use. 44 | 45 | ### Execute the script 46 | 47 | :::caution[A reminder] 48 | If you have a `.qbt_env` in the same folder as the script it will override any custom env settings you provide. 49 | 50 | Using flags will override your `.qbt_env` 51 | ::: 52 | 53 | ```bash 54 | ./qbt.bash 55 | ``` 56 | 57 | :::note 58 | Please see the [switches and flags summary](build-help/#switches-and-flags-summarised) to see what options you can pass and how to use them 59 | ::: 60 | 61 | The first thing you should do is to run the script with the `-h` flag to see the help output and the script defaults. 62 | 63 | ```bash 64 | ./qbt.bash -h 65 | ``` 66 | 67 | By passing `all` as the first argument, you can build everything based on the default settings. 68 | 69 | ```bash 70 | ./qbt.bash all 71 | ``` 72 | 73 | For example of using custom settings, 74 | 75 | - to use `ICU` using `-i` 76 | - optimise for the host system CPU using `-o` to set `-march=native` 77 | - build using libtorrent v1.2.19 78 | 79 | ```bash 80 | ./qbt.bash all -i -o -s -lt v1.2.19 81 | ``` 82 | 83 | Same as previous command but using `env` settings 84 | 85 | ```bash 86 | qbt_libtorrent_tag="v1.2.19" qbt_skip_icu="yes" qbt_optimize="yes" ./qbt.bash all 87 | ``` 88 | 89 | For an older version of qBittorrent, you can specify the version using `-qt` and the libtorrent version using `-lt` 90 | 91 | ```bash 92 | ./qbt.bash all -q -qt release-4.1.9.1 -lt libtorrent-1_1_14 -bt boost-1.76.0 93 | ``` 94 | -------------------------------------------------------------------------------- /docs/src/content/docs/github-actions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Github Actions 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | This project relies heavily on Github Actions to build and release the binaries. The actions are defined in the `.github/workflows` directory. 31 | 32 | :::note 33 | The jobs can be viewed here: [https://github.com/userdocs/qbittorrent-nox-static/actions](https://github.com/userdocs/qbittorrent-nox-static/actions) 34 | 35 | They workflows are located here: [https://github.com/userdocs/qbittorrent-nox-static/tree/master/.github/workflows](https://github.com/userdocs/qbittorrent-nox-static/tree/master/.github/workflows) 36 | ::: 37 | 38 | ## Github repo Actions settings 39 | 40 | The required permissions for each workflow and job have been configured granularly in the workflows themselves. The permissions are defined in the `permissions` section of the workflow. 41 | 42 | :::tip 43 | They are already configured in the workflows and you should not need to configure any forked repos to use these actions. 44 | ::: 45 | 46 | ## Workflows 47 | 48 | These workflows are using a reusable caller workflow that allows for inputs to be passed to the reusable workflows. This allows for a single workflow to be used to call multiple workflows with different inputs. 49 | 50 | ![](/qbittorrent-nox-static/docs_images/reusable_workflow_inputs.png) 51 | 52 | This is the structure of the workflows: 53 | 54 | ``` 55 | ci-main-reusable-caller 56 | ├─ ci-debian-build 57 | ├─ ci-alpine-build 58 | ├─ ci-alpine-release 59 | └─ ci-auto-rerun-failed-jobs 60 | ``` 61 | 62 |
63 | The primary reusable caller workflow 64 | 65 |
66 | 67 |
68 | The debian build workflow 69 | 70 |
71 | 72 |
73 | The alpine build workflow 74 | 75 |
76 | 77 |
78 | The alpine release workflow 79 | 80 |
81 | 82 |
83 | This workflow automatically reruns any failed jobs. Mostly targeted for the release jobs to ensure the release is created. 84 | 85 |
86 | -------------------------------------------------------------------------------- /docs/src/components/Header.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import type { Props } from "@astrojs/starlight/props"; 3 | 4 | import LanguageSelect from "@astrojs/starlight/components/LanguageSelect.astro"; 5 | import Search from "@astrojs/starlight/components/Search.astro"; 6 | import SiteTitle from "@astrojs/starlight/components/SiteTitle.astro"; 7 | import SocialIcons from "@astrojs/starlight/components/SocialIcons.astro"; 8 | import ThemeSelect from "@astrojs/starlight/components/ThemeSelect.astro"; 9 | 10 | const shouldRenderSearch = true; 11 | 12 | import App from "./AdvancedButton.astro"; 13 | --- 14 | 15 |
16 |
17 |
18 | 19 |
20 | 21 |
22 |
23 | {shouldRenderSearch && } 24 |
25 |
26 | 29 | 30 | 31 |
32 |
33 | 34 | 96 | -------------------------------------------------------------------------------- /docs/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "astro/config"; 2 | import starlight from "@astrojs/starlight"; 3 | import starlightImageZoom from "starlight-image-zoom"; 4 | import starlightGitHubAlerts from "starlight-github-alerts"; 5 | 6 | // https://astro.build/config 7 | export default defineConfig({ 8 | site: "https://userdocs.github.io", 9 | base: "/qbittorrent-nox-static", 10 | integrations: [ 11 | starlight({ 12 | plugins: [starlightImageZoom(), starlightGitHubAlerts()], 13 | title: "qbittorrent-nox-static", 14 | logo: { 15 | src: "./public/logo-static.svg", 16 | }, 17 | components: { 18 | Header: "./src/components/Header.astro", 19 | }, 20 | 21 | social: [ 22 | { icon: 'github', label: 'GitHub', href: 'https://github.com/userdocs/qbittorrent-nox-static' }, 23 | ], 24 | 25 | customCss: [ 26 | // Relative path to your custom CSS file 27 | "./src/styles/custom.css", 28 | ], 29 | sidebar: [ 30 | { 31 | label: "Read the docs", 32 | items: [ 33 | // Each item here is one entry in the navigation menu. 34 | { 35 | label: "Introduction", 36 | link: "/introduction", 37 | }, 38 | { 39 | label: "Rules of Engagement", 40 | link: "/rules-of-engagement", 41 | }, 42 | { 43 | label: "Prerequisites Check List", 44 | link: "/prerequisites", 45 | }, 46 | { 47 | label: "Script Installation", 48 | link: "/script-installation", 49 | }, 50 | { 51 | label: "Script Usage", 52 | link: "/script-usage", 53 | }, 54 | { 55 | label: "Build Help", 56 | link: "/build-help", 57 | }, 58 | { 59 | label: "Patching", 60 | link: "/patching", 61 | }, 62 | { 63 | label: "Debugging", 64 | link: "/debugging", 65 | }, 66 | { 67 | label: "Install qbittorrent", 68 | link: "/install-qbittorrent", 69 | }, 70 | { 71 | label: "Nginx proxypass", 72 | link: "/nginx-proxypass", 73 | }, 74 | { 75 | label: "Systemd", 76 | link: "/systemd", 77 | }, 78 | { 79 | label: "Github - Artifact Attestations", 80 | link: "/artifact-attestations", 81 | }, 82 | { 83 | label: "Github actions", 84 | link: "/github-actions", 85 | }, 86 | { 87 | label: "Change Log", 88 | link: "/changelog", 89 | }, 90 | { 91 | label: "Credits", 92 | link: "/credits", 93 | }, 94 | { 95 | label: "Glossary", 96 | link: "/glossary", 97 | }, 98 | ], 99 | }, 100 | ], 101 | }), 102 | ], 103 | 104 | // https://discord.com/channels/830184174198718474/1070481941863878697/1211398665101516842 105 | vite: { 106 | plugins: [ 107 | { 108 | name: "custom-page-props", 109 | transform: (code, id) => { 110 | if ( 111 | id.includes("@astrojs/starlight/components/Page.astro") 112 | ) { 113 | return code.replace( 114 | /]*>([\\s\\S]*?)<\\/blockquote>`, "gi"); 12 | // Markdown pattern: > [!TYPE]\n> line ... (stops at first blank or non > line) 13 | const MD_CALLOUT_RE = new RegExp( 14 | `(^|\n)>\\s*\\[!(${CALLOUT_TYPE_PATTERN})\\]\\s*\n((?:>.*(?:\n|$))+)(?=\n[^>]|$)?`, 15 | "gi" 16 | ); 17 | 18 | // Mapping to starlight aside variants 19 | const CALLOUT_MAP: Record = { 20 | NOTE: "note", 21 | TIP: "tip", 22 | WARNING: "caution", 23 | IMPORTANT: "note", 24 | CAUTION: "danger", 25 | }; 26 | 27 | function createAside(rawType: string, innerHtml: string): string { 28 | const type = (rawType || "NOTE").toUpperCase() as CalloutType; 29 | const variant = CALLOUT_MAP[type] ?? "note"; 30 | // Avoid double-wrapping if already processed 31 | if (/starlight-aside__title/i.test(innerHtml)) return innerHtml; 32 | return `

${type}

${innerHtml}
`; 33 | } 34 | 35 | function stripFirstMarkerLine(block: string): { type: string; html: string } { 36 | const markerLineRe = new RegExp(`^\\s*(?:

)?\\s*\\[!(${CALLOUT_TYPE_PATTERN})\\]\\s*(?:<\\/p>)?\\s*`, "i"); 37 | const match = block.match(CALLOUT_MARKER_RE); 38 | const type = match?.[1] || "NOTE"; 39 | const html = block.replace(markerLineRe, "").trim(); 40 | return { type, html }; 41 | } 42 | 43 | function processBlockquoteCallouts(src: string): string { 44 | return src.replace(BLOCKQUOTE_RE, (full, inner) => { 45 | if (!CALLOUT_MARKER_RE.test(inner)) return full; // leave normal blockquotes 46 | const { type, html } = stripFirstMarkerLine(inner); 47 | return createAside(type, html); 48 | }); 49 | } 50 | 51 | function processMarkdownCallouts(src: string): string { 52 | return src.replace(MD_CALLOUT_RE, (full, _lead, type, lines) => { 53 | // Remove leading ">" markers & blank lines 54 | const cleaned = lines 55 | .split(/\n/) 56 | .map((l: string) => l.replace(/^>\s?/, "")) 57 | .filter((l: string) => l.trim().length > 0) 58 | .join("\n"); 59 | return `\n${createAside(type, cleaned)}\n`; 60 | }); 61 | } 62 | 63 | function processCallouts(htmlContent: string): string { 64 | if (!htmlContent || typeof htmlContent !== "string") return htmlContent; 65 | // Quick escape if no markers 66 | if (!CALLOUT_MARKER_RE.test(htmlContent)) return htmlContent; 67 | let out = htmlContent; 68 | out = processBlockquoteCallouts(out); 69 | out = processMarkdownCallouts(out); 70 | return out; 71 | } 72 | 73 | let processedContent: string; 74 | try { 75 | processedContent = processCallouts(content); 76 | } catch (e) { 77 | // Fail open: render original content if processing breaks 78 | processedContent = content; 79 | } 80 | --- 81 | 82 |

83 | -------------------------------------------------------------------------------- /docs/src/utils/modal-utils.ts: -------------------------------------------------------------------------------- 1 | interface GlossaryEntry { 2 | compiledContent: () => Promise; 3 | Content: any; 4 | file: string; 5 | toString: () => string; 6 | } 7 | 8 | export class GlossaryError extends Error { 9 | constructor(message: string, public code: string) { 10 | super(message); 11 | this.name = 'GlossaryError'; 12 | } 13 | } 14 | 15 | // Content cache for performance 16 | const contentCache = new Map(); 17 | 18 | // Basic HTML sanitization 19 | export const sanitizeHtml = (html: string): string => { 20 | return html 21 | .replace(/)<[^<]*)*<\/script>/gi, '') 22 | .replace(/javascript:/gi, '') 23 | .replace(/on\w+\s*=/gi, ''); 24 | }; 25 | 26 | // Generate unique ID with crypto fallback 27 | export const generateUniqueId = (id: string): string => { 28 | try { 29 | return `modal-${id}-${crypto.randomUUID().slice(0, 6)}`; 30 | } catch { 31 | // Fallback for environments without crypto.randomUUID 32 | return `modal-${id}-${Math.random().toString(36).slice(2, 8)}`; 33 | } 34 | }; 35 | 36 | // Get cached content with error handling 37 | const getCachedContent = async (id: string, post: GlossaryEntry): Promise => { 38 | if (contentCache.has(id)) { 39 | return contentCache.get(id)!; 40 | } 41 | 42 | try { 43 | const content = await post.compiledContent(); 44 | const htmlContent = String(content); 45 | contentCache.set(id, htmlContent); 46 | return htmlContent; 47 | } catch (e) { 48 | const msg = e instanceof Error ? e.message : String(e); 49 | throw new GlossaryError(`Failed to extract content for "${id}": ${msg}`, 'CONTENT_EXTRACTION_FAILED'); 50 | } 51 | }; 52 | 53 | // Escape regex special characters 54 | const escapeRegExp = (s: string): string => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 55 | 56 | export interface LoadedGlossaryContent { 57 | primaryHtml: string; 58 | moreHtml: string; 59 | hasMore: boolean; 60 | } 61 | 62 | export const loadGlossaryEntry = async (id: string): Promise => { 63 | const posts = import.meta.glob( 64 | "/src/content/docs/glossary/*.md", 65 | { eager: true } 66 | ); 67 | 68 | if (!id) { 69 | throw new GlossaryError("Modal id parameter is required", 'MISSING_ID'); 70 | } 71 | 72 | const safeId = escapeRegExp(String(id)); 73 | const regex = new RegExp(`(?:${safeId})\\.(?:md|mdx)$`); 74 | const [, post] = Object.entries(posts).find(([p]) => regex.test(p)) ?? []; 75 | 76 | if (!post) { 77 | const availableEntries = Object.keys(posts) 78 | .map(path => path.split('/').pop()?.replace(/\.mdx?$/, '')) 79 | .filter(Boolean) 80 | .slice(0, 5); 81 | 82 | throw new GlossaryError( 83 | `Glossary entry "${id}" not found. Available entries include: ${availableEntries.join(', ')}`, 84 | 'ENTRY_NOT_FOUND' 85 | ); 86 | } 87 | 88 | const htmlContent = await getCachedContent(id, post); 89 | 90 | if (!htmlContent || htmlContent.trim().length === 0) { 91 | throw new GlossaryError(`Empty content for "${id}"`, 'EMPTY_CONTENT'); 92 | } 93 | 94 | // Split at any
tag variant case-insensitively 95 | const htmlSplit = htmlContent.split(//i); 96 | if (!htmlSplit.length) { 97 | throw new GlossaryError(`Invalid content format for "${id}"`, 'INVALID_FORMAT'); 98 | } 99 | 100 | const primaryHtml = sanitizeHtml(htmlSplit[0] ?? ""); 101 | const moreHtml = sanitizeHtml(htmlSplit[1] ?? ""); 102 | const hasMore = Boolean(moreHtml && moreHtml.trim().length > 0); 103 | 104 | return { primaryHtml, moreHtml, hasMore }; 105 | }; -------------------------------------------------------------------------------- /docs/src/content/docs/prerequisites.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Prerequisite Check list 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | 31 | 32 | :::tip[Optional - Paid service for faster build times] 33 | For faster build times you can consider a paid service like to use as self hosted runners with the Github Actions 34 | ::: 35 | 36 | 37 | 38 | ## Prerequisite Check list 39 | 40 | If you want to self host you need to be able to meet these conditions on your host in order to use the script. 41 | 42 | 🟩 Supported host build platforms 43 | - Debian: `trixie` 44 | - Ubuntu: `noble` 45 | - Alpine: `3.18` or greater 46 | 47 | 🟩 Build environment 48 | - via a shell like or 49 | - : `Windows` `MacOS` `WSL2` 50 | - WSL2 51 | - Run directly in the Debian or Ubuntu image ❌ (works but not recommended) 52 | - Via ✅ (recommended method) 53 | - Docker installed in image ✅ (alternative recommendation) 54 | 55 | 🟩 Bash Shell script 56 | - This is 100% a modern bash shell script and it requires having access to bash to run it. 57 | 58 | 🟧 Host permissions 59 | 60 | - The script needs to install some system dependencies in order to proceed and if you do not have permission or access to do this or no access to docker to use a container you must find a more suitable host environment. 61 | - You can simply [fork the repo on Github](/qbittorrent-nox-static/github-actions) and create your own releases if you have no access to a suitable build host 62 | 63 | 🟥 Emulation requirements for cross building 64 | 65 | - `icu` `qtbase` and `qttools` requires `qemu` emulation to be available by default in order to cross build them. 66 | - This was reworked in script version `v2.2.2` and now the user has more choice of how to build. 67 | - Two env vars specific to dealing with this were introduced 68 | - `qbt_with_qemu` - this defaults to `yes` but if set to `no` if will enable `_host_deps` version of the modules that need a host version to be build before they can cross build. 69 | - this means longer build times as these modules are essentially built twice. 70 | - `qbt_host_deps` - defaults to `no` but if set to yes it will not build locally but instead pull in prebuilt host deps for the these modules avoiding the need to build them locally. 71 | - They are built and sourced from here https://github.com/userdocs/qbt-host-deps 72 | - This make build time equivalent to using `qemu` without the requirement of having `qemu` 73 | 74 | If you build using Qt6 you will need to have these dependencies installed on the host (not inside the docker), 75 | 76 | 77 | 78 | 79 | ```bash 80 | sudo apt install qemu-user-static binfmt-support 81 | ``` 82 | 83 | 84 | 85 | 86 | ```bash 87 | sudo apk add qemu qemu-openrc 88 | ``` 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/src/content/docs/index.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: qbittorrent-nox-static 3 | description: Get started building your docs site with Starlight. 4 | template: splash 5 | hero: 6 | tagline: Fully static linux binaries for qbittorrent-nox. 7 | image: 8 | file: /public/logo-static.svg 9 | actions: 10 | - text: Docs 11 | link: /qbittorrent-nox-static/introduction 12 | icon: right-arrow 13 | variant: primary 14 | 15 | - text: Github repo 16 | link: https://github.com/userdocs/qbittorrent-nox-static 17 | icon: right-arrow 18 | variant: secondary 19 | 20 | - text: Latest release 21 | link: https://github.com/userdocs/qbittorrent-nox-static/releases/latest 22 | icon: right-arrow 23 | variant: secondary 24 | - text: Legacy build 25 | link: https://github.com/userdocs/qbittorrent-nox-static-legacy/releases/latest 26 | icon: right-arrow 27 | variant: secondary 28 | --- 29 | 30 | import { Card, CardGrid } from '@astrojs/starlight/components'; 31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 |
40 |

41 | Making the most of the Github ecosystem by leveraging Github Actions to automate the build process and release new versions as soon as core dependencies are updated and available. 42 |

43 |
44 | 45 |
46 |
47 | 48 |
49 | 50 | 51 |
52 | 53 |
54 | 55 |
56 |

57 | Musl libc to create statically linked binaries than can run on any Linux based OS. It was never supposed to be hard to do this. Musl makes it easy. 58 |

59 |
60 | 61 |
62 |
63 | 64 |
65 | 66 | 67 |
68 | 69 |
70 | 71 |
72 |

73 | The build host - Alpine Linux is a security-oriented, lightweight Linux distribution based on musl libc and busybox. It is designed for security, simplicity, and resource efficiency. 74 |

75 |
76 | 77 |
78 |
79 | 80 |
81 | 82 | 83 |
84 | 85 |
86 | 87 |
88 |

89 | A fully static build of qbittorrent-nox. No need to install any dependencies. Just download and run. Deploy it however you want. Easy to deploy as a binary or as part of a docker solution. 90 |

91 |
92 | 93 |
94 |
95 | 96 | 97 | -------------------------------------------------------------------------------- /.github/workflows/qi-bash.yml: -------------------------------------------------------------------------------- 1 | name: qi.bash tests 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - "qi.bash" 8 | 9 | permissions: 10 | contents: write 11 | 12 | jobs: 13 | test: 14 | runs-on: ${{ matrix.runs-on }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | runs-on: ["ubuntu-24.04"] 19 | arch: ["amd64", "arm32v6", "arm32v7", "arm64v8", "i386", "riscv64"] 20 | container_image: ["ubuntu:latest", "debian:latest", "alpine:edge"] 21 | include: 22 | - arch: amd64 23 | platform: linux/amd64 24 | - arch: arm32v6 25 | platform: linux/arm/v6 26 | - arch: arm32v7 27 | platform: linux/arm/v7 28 | - arch: arm64v8 29 | platform: linux/arm64 30 | - arch: i386 31 | platform: linux/i386 32 | - arch: riscv64 33 | platform: linux/riscv64 34 | exclude: 35 | - arch: i386 36 | container_image: ubuntu:latest 37 | - arch: arm32v6 38 | container_image: ubuntu:latest 39 | - arch: riscv64 40 | container_image: debian:latest 41 | - arch: arm32v6 42 | container_image: debian:latest 43 | 44 | env: 45 | container_name: "build" 46 | steps: 47 | - name: Checkout 48 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 49 | with: 50 | persist-credentials: false 51 | 52 | - name: Set up QEMU 53 | uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 54 | 55 | - name: Create docker ${{ env.container_name }} ${{ matrix.container_image }} ${{ matrix.platform }} container 56 | run: > 57 | docker run --name ${container_name} -it -d 58 | -w /root 59 | -v ${{ github.workspace }}:/root 60 | -e "LANG=C.UTF-8" 61 | -e "GH_TOKEN=${{ github.token }}" 62 | --platform ${{ matrix.platform }} 63 | ${{ matrix.arch }}/${{ matrix.container_image }} 64 | 65 | - name: Run apk update 66 | if: matrix.container_image == 'alpine:edge' 67 | run: | 68 | docker exec ${container_name} apk update 69 | docker exec ${container_name} apk add bash github-cli 70 | 71 | - name: Run apk update 72 | if: matrix.container_image == 'ubuntu:latest' 73 | run: | 74 | docker exec ${container_name} apt-get update 75 | docker exec ${container_name} apt-get install -y jq 76 | 77 | - name: Run apk update 78 | if: matrix.container_image == 'alpine:edge' 79 | run: docker exec ${container_name} gh --version 80 | 81 | - name: Run alpine apk --print-arch 82 | if: matrix.container_image == 'alpine:edge' 83 | run: | 84 | printf '\n%b\n' "\`\`\`bash" >> $GITHUB_STEP_SUMMARY 85 | docker exec ${container_name} apk --print-arch | tee -a $GITHUB_STEP_SUMMARY 86 | printf '\n%b\n' "\`\`\`" >> $GITHUB_STEP_SUMMARY 87 | 88 | - name: Run debian dpkg --print-architecture 89 | if: matrix.container_image == 'debian:latest' || matrix.container_image == 'ubuntu:latest' 90 | run: | 91 | printf '\n%b\n' "\`\`\`bash" >> $GITHUB_STEP_SUMMARY 92 | docker exec ${container_name} dpkg --print-architecture | tee -a $GITHUB_STEP_SUMMARY 93 | printf '\n%b\n' "\`\`\`" >> $GITHUB_STEP_SUMMARY 94 | 95 | - name: Run apt-get update 96 | if: matrix.container_image == 'debian:latest' || matrix.container_image == 'ubuntu:latest' 97 | run: | 98 | docker exec ${container_name} apt-get update 99 | docker exec ${container_name} apt-get install -y wget 100 | 101 | - run: | 102 | chmod +x qi.bash 103 | printf '\n%b\n' "\`\`\`bash" >> $GITHUB_STEP_SUMMARY 104 | docker exec ${container_name} bash -l qi.bash | sed 's/\x1b\[[0-9;]*m//g' | tee -a $GITHUB_STEP_SUMMARY 105 | printf '\n%b\n' "\`\`\`" >> $GITHUB_STEP_SUMMARY 106 | -------------------------------------------------------------------------------- /docs/src/content/docs/script-installation.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Script Installation 3 | description: Script Installation 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | :::note[Host environment] 31 | The recommended build platform is Alpine Linux and the supported build method is via docker. It will just make things easier. 32 | 33 | We do not support a non docker build environment. If you are not using docker, you are on your own. 34 | ::: 35 | 36 | :::tip[Github Actions] 37 | If you cannot or don't want to use docker, you can use the [Github Actions](/qbittorrent-nox-static/github-actions) to build the project by forking the repository. 38 | ::: 39 | 40 | ## Bootstrapping the container 41 | 42 | 43 | 44 | 45 |
46 | 47 | Some notes on the dockers method: 48 | 49 | - The script installs the necessary dependencies so there is no docker file needed. 50 | - We use a subdirectory `qbt`, not your `$HOME` directory, to avoid `.bashrc` and `.profile` conflicts. 51 | - A subdirectory is automatically created, named `qbt` by the use of `-v $HOME/qbt:/root` 52 | - The default path will be `HOME/qbt` outside the docker container and `/root/qbt` inside it. 53 | - We use `-e "LANG=C.UTF-8"` with Debian based images to avoid some UTF errors. 54 | 55 | :::tip[env file] 56 | You do not need to configure the env while bootstrapping the container. It can be done after via the `.qbt_env` file or exporting them. 57 | 58 | There are multiple ways to pass an env file when using Docker. 59 | 60 | - You can use the `--env-file` switch when creating the docker and provide a file with your [envs](/qbittorrent-nox-static/build-help#env-settings). 61 | - If a `.qbt_env` file is found in the same directory as the script, it will be used automatically. 62 | - Using ENV in a dockerfile is also possible. 63 | 64 | The easist method is the `.qbt_env` as the script has support flags for this purpose. 65 | ::: 66 | 67 |
68 | 69 | 70 | 71 |
72 | 73 | :::note[tags] 74 | You use `alpine:edge` `alpine:latest` 75 | ::: 76 | 77 | To bootstrap the container: 78 | 79 | ```bash 80 | docker run -it -w /root -p 8080:8080 -v ~/qbt:/root alpine:edge /bin/ash -c 'apk update && apk add bash curl && bash' 81 | ``` 82 | 83 | If you need to download the script use this command 84 | 85 | ```bash 86 | curl -sLO usrdx.github.io/s/qbt.bash && chmod +x qbt.bash 87 | ``` 88 | 89 |
90 | 91 | 92 | 93 |
94 | 95 | :::note[tags] 96 | You use `debian:trixie` `debian:latest` or a supported tag 97 | ::: 98 | 99 | To bootstrap the container: 100 | 101 | ```bash 102 | docker run -it -w /root -p 8080:8080 -e "LANG=C.UTF-8" -v ~/qbt:/root debian:latest /bin/bash -c 'apt update && apt install -y curl && bash' 103 | ``` 104 | 105 | If you need to download the script use this command 106 | 107 | ```bash 108 | curl -sLO usrdx.github.io/s/qbt.bash && chmod +x qbt.bash 109 | ``` 110 | 111 |
112 | 113 | 114 |
115 | 116 | :::note[tags] 117 | You use `ubuntu:noble` `ubuntu:latest` 118 | ::: 119 | 120 | To bootstrap the container: 121 | 122 | ```bash 123 | docker run -it -w /root -p 8080:8080 -e "LANG=C.UTF-8" -v ~/qbt:/root ubuntu:latest /bin/bash -c 'apt update && apt install -y curl && bash' 124 | ``` 125 | 126 | If you need to download the script use this command 127 | 128 | ```bash 129 | curl -sLO usrdx.github.io/s/qbt.bash && chmod +x qbt.bash 130 | ``` 131 | 132 |
133 | 134 | 135 | 136 |
137 | 138 | 139 | 140 |
141 |
142 | 143 | You are now ready to run the script. 144 | -------------------------------------------------------------------------------- /docs/src/components/Scriptinfo.astro: -------------------------------------------------------------------------------- 1 | --- 2 | const { class: className, id, summary, stage } = Astro.props; 3 | 4 | import Stage1 from "/src/assets/stage1.html?raw"; 5 | import Stage2 from "/src/assets/stage2.html?raw"; 6 | import Stage3 from "/src/assets/stage3.html?raw"; 7 | 8 | // Select the appropriate stage content 9 | let stageContent; 10 | switch (stage?.toLowerCase()) { 11 | case "stage1": 12 | stageContent = Stage1; 13 | break; 14 | case "stage2": 15 | stageContent = Stage2; 16 | break; 17 | case "stage3": 18 | stageContent = Stage3; 19 | break; 20 | default: 21 | stageContent = Stage3; 22 | } 23 | --- 24 | 25 |
26 |
27 | {summary} 28 |
29 |
30 |
31 | 32 | 63 | 64 | 150 | -------------------------------------------------------------------------------- /.github/workflows/ci-main-reusable-caller.yml: -------------------------------------------------------------------------------- 1 | name: ci - main reusable caller 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | script_name: 7 | description: "Which script to run?" 8 | required: true 9 | default: "qbt-nox-static.bash" 10 | type: choice 11 | options: ["qbt-nox-static.bash", "qbittorrent-nox-static.sh"] 12 | debian-build: 13 | description: "Debian: build" 14 | required: true 15 | default: false 16 | type: boolean 17 | alpine-build: 18 | description: "Alpine: build" 19 | required: true 20 | default: true 21 | type: boolean 22 | workflow-files: 23 | description: "Workflow files" 24 | required: true 25 | default: true 26 | type: boolean 27 | icu: 28 | description: "Enable icu" 29 | required: true 30 | default: false 31 | type: boolean 32 | debug: 33 | description: "Debug builds (symbols)" 34 | required: true 35 | default: false 36 | type: boolean 37 | release: 38 | description: "Release assets?" 39 | required: true 40 | default: true 41 | type: boolean 42 | distinct_id: 43 | description: "Distinct id" 44 | required: false 45 | type: string 46 | skip_rerun: 47 | description: "Skip rerun?" 48 | required: true 49 | default: false 50 | type: boolean 51 | retries: 52 | description: "Number of rerun retries" 53 | required: true 54 | default: "1" 55 | type: choice 56 | options: ["1", "2", "3", "4", "5", "6", "7", "8", "9"] 57 | 58 | permissions: {} 59 | 60 | jobs: 61 | ci-debian-build: 62 | if: github.event.inputs.debian-build == 'true' 63 | concurrency: 64 | group: ci-debian-build 65 | cancel-in-progress: true 66 | permissions: 67 | id-token: write 68 | contents: read 69 | attestations: write 70 | uses: ./.github/workflows/ci-debian-build.yml 71 | with: 72 | distinct_id: ${{ github.event.inputs.distinct_id }} 73 | workflow-files: ${{ github.event.inputs.workflow-files == 'true' && 'yes' || 'no' }} 74 | icu: ${{ github.event.inputs.icu == 'true' && 'no' || 'yes' }} 75 | debug: ${{ github.event.inputs.debug == 'true' && 'yes' || 'no' }} 76 | script_name: ${{ github.event.inputs.script_name }} 77 | 78 | ci-alpine-build: 79 | if: github.event.inputs.alpine-build == 'true' 80 | concurrency: 81 | group: ci-alpine-build 82 | cancel-in-progress: true 83 | permissions: 84 | id-token: write 85 | contents: read 86 | attestations: write 87 | uses: ./.github/workflows/ci-alpine-build.yml 88 | with: 89 | distinct_id: ${{ github.event.inputs.distinct_id }} 90 | workflow-files: ${{ github.event.inputs.workflow-files == 'true' && 'yes' || 'no' }} 91 | icu: ${{ github.event.inputs.icu == 'true' && 'no' || 'yes' }} 92 | debug: ${{ github.event.inputs.debug == 'true' && 'yes' || 'no' }} 93 | script_name: ${{ github.event.inputs.script_name }} 94 | 95 | ci-alpine-release: 96 | needs: [ci-alpine-build] 97 | if: github.event.inputs.release == 'true' && contains(needs.*.result, 'success') && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') 98 | concurrency: 99 | group: ci-alpine-release 100 | cancel-in-progress: true 101 | permissions: 102 | contents: write 103 | uses: ./.github/workflows/ci-alpine-release.yml 104 | with: 105 | distinct_id: ${{ github.event.inputs.distinct_id }} 106 | 107 | ci-auto-rerun-failed-jobs: 108 | if: failure() && (github.event.inputs.skip_rerun || 'false') == 'false' 109 | needs: [ci-debian-build, ci-alpine-build, ci-alpine-release] 110 | concurrency: 111 | group: ci-auto-rerun-failed-jobs 112 | cancel-in-progress: true 113 | permissions: 114 | actions: write 115 | runs-on: ubuntu-24.04-arm 116 | env: 117 | GH_TOKEN: "${{ secrets.AUTO_RERUN || github.token }}" 118 | github_repo: "" # To use ci-auto-rerun-failed-jobs.yml hosted in a remote repository else default to the current repository. Requires PAT token AUTO_RERUN 119 | retries: ${{ github.event.inputs.retries || '1' }} 120 | distinct_id: ${{ github.event.inputs.distinct_id }} 121 | steps: 122 | - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 123 | with: 124 | persist-credentials: false 125 | - name: ci-auto-rerun-failed-jobs via ${{ env.github_repo || github.repository }} 126 | run: > 127 | gh workflow run ci-auto-rerun-failed-jobs-action.yml 128 | --repo "${github_repo:-$GITHUB_REPOSITORY}" 129 | -f github_repo=${GITHUB_REPOSITORY} 130 | -f run_id=${GITHUB_RUN_ID} 131 | -f attempts=${GITHUB_RUN_ATTEMPT} 132 | -f retries=${retries} 133 | -f distinct_id=${distinct_id} 134 | -------------------------------------------------------------------------------- /.github/workflows/ci-alpine-release.yml: -------------------------------------------------------------------------------- 1 | name: ci - alpine-release 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | distinct_id: 7 | description: "Distinct ID for the artifacts" 8 | required: true 9 | type: string 10 | 11 | jobs: 12 | release: 13 | runs-on: ubuntu-24.04-arm 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | qbt_libtorrent_version: ["1.2", "2.0"] 18 | include: 19 | - qbt_libtorrent_version: "1.2" 20 | preview_release: true 21 | 22 | - qbt_libtorrent_version: "2.0" 23 | preview_release: false 24 | 25 | name: "Publish release libtorrent-v${{ matrix.qbt_libtorrent_version }}" 26 | 27 | env: 28 | qbt_build_dir: "qbt-build" 29 | 30 | steps: 31 | - name: Checkout ${{ inputs.distinct_id }} 32 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 33 | with: 34 | persist-credentials: false 35 | 36 | - name: Pandoc - Bootstrap 37 | run: | 38 | pandoc_git_tag="$(git ls-remote -q -t --refs https://github.com/jgm/pandoc.git | awk '/tags\/[0-9]/{sub("refs/tags/", ""); print $2 }' | awk '!/^$/' | sort -rV | head -n 1)" 39 | curl -sLo- "https://github.com/jgm/pandoc/releases/latest/download/pandoc-${pandoc_git_tag}-linux-$(dpkg --print-architecture).tar.gz" | tar xzf - --strip-components 2 -C "$(pwd)" --exclude="share" 40 | 41 | - name: Host - Download 1.2 qbittorrent-nox artifacts ${{ inputs.distinct_id }} 42 | uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 43 | with: 44 | path: "1.2" 45 | pattern: libtorrent-v1.2-*-qbittorrent-nox 46 | merge-multiple: true 47 | 48 | - name: Host - Download 2.0 qbittorrent-nox artifacts ${{ inputs.distinct_id }} 49 | uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 50 | with: 51 | path: "2.0" 52 | pattern: libtorrent-v2.0-*-qbittorrent-nox 53 | merge-multiple: true 54 | 55 | - name: Host - merge release-info ${{ inputs.distinct_id }} 56 | env: 57 | lt_version: ${{ matrix.qbt_libtorrent_version }} 58 | run: | 59 | shopt -s nullglob 60 | 61 | revision="$(jq -r .revision "${lt_version}"/*-dependency-version.json | sort -nr | head -n1)" 62 | boost="$(jq -r .boost "${lt_version}"/*-dependency-version.json | head -n1)" 63 | 64 | # this need to check both 1.2 and 2.0 folders to merge the libtorrent versions in the dependency-version.json 65 | for dependency_version_json in {1.2,2.0}/*-dependency-version.json; do 66 | if [[ -f ${dependency_version_json} ]]; then 67 | sed -r 's/"boost": (.*)/BOOST_PLACEHOLDER/g' -i "${dependency_version_json}" 68 | sed -r 's/"revision": (.*)/REVISION_PLACEHOLDER/g' -i "${dependency_version_json}" 69 | dependency_version+=("${dependency_version_json}") 70 | fi 71 | done 72 | 73 | # This file only needs to merge info specific to the libtorrent matrix running it. 74 | for release_md in "${lt_version}"/*-release.md; do 75 | if [[ -f ${release_md} ]]; then 76 | sed -r 's/^\|(.*)revision(.*)\|(.*)\|$/REVISION_PLACEHOLDER/g' -i "${release_md}" 77 | release_md+=("${release_md}") 78 | fi 79 | done 80 | 81 | readarray -t release_sorted < <(printf '%s\n' "${release_md[@]}" | sort) 82 | readarray -t dependency_version_sorted < <(printf '%s\n' "${dependency_version[@]}" | sort) 83 | 84 | paste -d '\n' "${release_sorted[@]}" | uniq | awk '!(NF && seen[$0]++) || /^>/' > "tmp-release.md" 85 | paste -d '\n' "${dependency_version_sorted[@]}" | uniq | awk '!(NF && seen[$0]++)' > "dependency-version.json" 86 | 87 | sed -i "s|BOOST_PLACEHOLDER|\"boost\": \"${boost}\",|" dependency-version.json 88 | sed -i "s|REVISION_PLACEHOLDER|\"revision\": \"${revision}\"|" dependency-version.json 89 | sed -i "s/REVISION_PLACEHOLDER/| revision |${revision} |/" tmp-release.md 90 | 91 | ./pandoc --wrap=preserve -f gfm tmp-release.md -t gfm -o release.md 92 | 93 | - name: Host - Bootstrap release tag ${{ inputs.distinct_id }} 94 | run: printf '%s\n' "release_tag=$(cat ${{ matrix.qbt_libtorrent_version }}/tag.md)" >> $GITHUB_ENV 95 | 96 | - name: Host - Bootstrap release title ${{ inputs.distinct_id }} 97 | run: printf '%s\n' "release_title=$(cat ${{ matrix.qbt_libtorrent_version }}/title.md)" >> $GITHUB_ENV 98 | 99 | - name: Host- Create release - tag - assets ${{ inputs.distinct_id }} 100 | uses: ncipollo/release-action@b7eabc95ff50cbeeedec83973935c8f306dfcd0b # v1.20.0 101 | with: 102 | prerelease: "${{ matrix.preview_release }}" 103 | artifacts: "${{ matrix.qbt_libtorrent_version }}/*-qbittorrent-nox,dependency-version.json" 104 | replacesArtifacts: true 105 | tag: "${{ env.release_tag }}" 106 | name: "${{ env.release_title }}" 107 | bodyFile: "release.md" 108 | allowUpdates: true 109 | token: "${{ github.TOKEN }}" 110 | -------------------------------------------------------------------------------- /docs/src/assets/stage1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Aura Output 4 | 39 | 40 |
41 | Checking: available privileges 42 | 43 | root 44 | sudo 45 | 46 | Checking: test 47 | 48 | bash 49 | curl 50 | git 51 | 52 | Checking: core 53 | 54 | autoconf 55 | automake 56 | build-base 57 | cmake 58 | curl 59 | git 60 | graphviz 61 | libtool 62 | linux-headers 63 | ninja-build 64 | ninja-is-really-ninja 65 | perl 66 | pkgconf 67 | py3-numpy 68 | py3-numpy-dev 69 | python3 70 | python3-dev 71 | re2c 72 | ttf-freefont 73 | xz 74 | 75 | Info: /workspace/qbt-nox-static.bash 76 | 77 | qbt-nox-static.bash install_test ------ installs minimum required tools to run tests 78 | qbt-nox-static.bash install_core ------ installs required build tools to use script 79 | qbt-nox-static.bash bootstrap_deps ---- install_test + install_core 80 | 81 | Warning: Missing required test_tools 82 | 83 | Warning: Missing required components of install_core 84 | 85 |
86 | -------------------------------------------------------------------------------- /patches/qbittorrent/4.5.1/patch: -------------------------------------------------------------------------------- 1 | From 3be5273246e9e399041db91892e3dbb281055076 Mon Sep 17 00:00:00 2001 2 | From: Vladimir Golovnev 3 | Date: Mon, 27 Feb 2023 09:08:18 +0300 4 | Subject: [PATCH 1/3] Prevent RSS folder from being moved into itself 5 | 6 | PR #18619. 7 | Closes #18446. 8 | --- 9 | src/base/rss/rss_session.cpp | 5 ++++- 10 | src/gui/rss/feedlistwidget.cpp | 10 ++++++---- 11 | 2 files changed, 10 insertions(+), 5 deletions(-) 12 | 13 | diff --git a/src/base/rss/rss_session.cpp b/src/base/rss/rss_session.cpp 14 | index bbc4d413d12..1d1ed81b1dd 100644 15 | --- a/src/base/rss/rss_session.cpp 16 | +++ b/src/base/rss/rss_session.cpp 17 | @@ -185,8 +185,11 @@ nonstd::expected Session::moveItem(Item *item, const QString &des 18 | if (!result) 19 | return result.get_unexpected(); 20 | 21 | - auto srcFolder = static_cast(m_itemsByPath.value(Item::parentPath(item->path()))); 22 | const auto destFolder = result.value(); 23 | + if (static_cast(destFolder) == item) 24 | + return nonstd::make_unexpected(tr("Couldn't move folder into itself.")); 25 | + 26 | + auto srcFolder = static_cast(m_itemsByPath.value(Item::parentPath(item->path()))); 27 | if (srcFolder != destFolder) 28 | { 29 | srcFolder->removeItem(item); 30 | diff --git a/src/gui/rss/feedlistwidget.cpp b/src/gui/rss/feedlistwidget.cpp 31 | index 8657dcca82e..428fd95463a 100644 32 | --- a/src/gui/rss/feedlistwidget.cpp 33 | +++ b/src/gui/rss/feedlistwidget.cpp 34 | @@ -105,7 +105,8 @@ FeedListWidget::FeedListWidget(QWidget *parent) 35 | m_rssToTreeItemMapping[RSS::Session::instance()->rootFolder()] = invisibleRootItem(); 36 | 37 | m_unreadStickyItem = new FeedListItem(this); 38 | - m_unreadStickyItem->setData(0, Qt::UserRole, QVariant::fromValue(RSS::Session::instance()->rootFolder())); 39 | + m_unreadStickyItem->setData(0, Qt::UserRole, QVariant::fromValue( 40 | + reinterpret_cast(RSS::Session::instance()->rootFolder()))); 41 | m_unreadStickyItem->setText(0, tr("Unread (%1)").arg(RSS::Session::instance()->rootFolder()->unreadCount())); 42 | m_unreadStickyItem->setData(0, Qt::DecorationRole, UIThemeManager::instance()->getIcon(u"mail-inbox"_qs)); 43 | m_unreadStickyItem->setData(0, StickyItemTagRole, true); 44 | @@ -211,9 +212,10 @@ QList FeedListWidget::getAllOpenedFolders(QTreeWidgetItem *pa 45 | 46 | RSS::Item *FeedListWidget::getRSSItem(QTreeWidgetItem *item) const 47 | { 48 | - if (!item) return nullptr; 49 | + if (!item) 50 | + return nullptr; 51 | 52 | - return item->data(0, Qt::UserRole).value(); 53 | + return reinterpret_cast(item->data(0, Qt::UserRole).value()); 54 | } 55 | 56 | QTreeWidgetItem *FeedListWidget::mapRSSItem(RSS::Item *rssItem) const 57 | @@ -275,7 +277,7 @@ QTreeWidgetItem *FeedListWidget::createItem(RSS::Item *rssItem, QTreeWidgetItem 58 | { 59 | auto *item = new FeedListItem; 60 | item->setData(0, Qt::DisplayRole, u"%1 (%2)"_qs.arg(rssItem->name(), QString::number(rssItem->unreadCount()))); 61 | - item->setData(0, Qt::UserRole, QVariant::fromValue(rssItem)); 62 | + item->setData(0, Qt::UserRole, QVariant::fromValue(reinterpret_cast(rssItem))); 63 | m_rssToTreeItemMapping[rssItem] = item; 64 | 65 | QIcon icon; 66 | 67 | From c21c3d230019431ab8f03faa3471474a66590c9c Mon Sep 17 00:00:00 2001 68 | From: Vladimir Golovnev 69 | Date: Mon, 27 Feb 2023 09:09:33 +0300 70 | Subject: [PATCH 2/3] WebAPI: Allow to set read-only directory as torrent 71 | location 72 | 73 | PR #18613. 74 | Closes #18480. 75 | --- 76 | src/webui/api/torrentscontroller.cpp | 4 ---- 77 | 1 file changed, 4 deletions(-) 78 | 79 | diff --git a/src/webui/api/torrentscontroller.cpp b/src/webui/api/torrentscontroller.cpp 80 | index 6ede337e5f0..6080febeae3 100644 81 | --- a/src/webui/api/torrentscontroller.cpp 82 | +++ b/src/webui/api/torrentscontroller.cpp 83 | @@ -1099,10 +1099,6 @@ void TorrentsController::setLocationAction() 84 | if (!Utils::Fs::mkpath(newLocation)) 85 | throw APIError(APIErrorType::Conflict, tr("Cannot make save path")); 86 | 87 | - // check permissions 88 | - if (!Utils::Fs::isWritable(newLocation)) 89 | - throw APIError(APIErrorType::AccessDenied, tr("Cannot write to directory")); 90 | - 91 | applyToTorrents(hashes, [newLocation](BitTorrent::Torrent *const torrent) 92 | { 93 | LogMsg(tr("WebUI Set location: moving \"%1\", from \"%2\" to \"%3\"") 94 | 95 | From 38c0864bf2119183e67fb7f2a1d5a8421f82b99f Mon Sep 17 00:00:00 2001 96 | From: Vladimir Golovnev 97 | Date: Mon, 27 Feb 2023 16:50:50 +0300 98 | Subject: [PATCH 3/3] Reject requests that contain backslash in path 99 | 100 | PR #18626. 101 | Closes #18618. 102 | --- 103 | src/webui/webapplication.cpp | 11 ++++++++--- 104 | 1 file changed, 8 insertions(+), 3 deletions(-) 105 | 106 | diff --git a/src/webui/webapplication.cpp b/src/webui/webapplication.cpp 107 | index f16e6e81220..629639e8a71 100644 108 | --- a/src/webui/webapplication.cpp 109 | +++ b/src/webui/webapplication.cpp 110 | @@ -151,9 +151,14 @@ WebApplication::~WebApplication() 111 | 112 | void WebApplication::sendWebUIFile() 113 | { 114 | - const QStringList pathItems {request().path.split(u'/', Qt::SkipEmptyParts)}; 115 | - if (pathItems.contains(u".") || pathItems.contains(u"..")) 116 | - throw InternalServerErrorHTTPError(); 117 | + if (request().path.contains(u'\\')) 118 | + throw BadRequestHTTPError(); 119 | + 120 | + if (const QList pathItems = QStringView(request().path).split(u'/', Qt::SkipEmptyParts) 121 | + ; pathItems.contains(u".") || pathItems.contains(u"..")) 122 | + { 123 | + throw BadRequestHTTPError(); 124 | + } 125 | 126 | const QString path = (request().path != u"/") 127 | ? request().path 128 | -------------------------------------------------------------------------------- /docs/src/content/docs/install-qbittorrent.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Installing nox 3 | hide_title: true 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | Once the script has successfully built `qbittorrent-nox` you can install the binary using this command: 31 | 32 | ```bash 33 | bash ~/qbt.bash install 34 | ``` 35 | 36 | :::tip 37 | If you built to a custom directory you will need to specify this to the install command using the `-b` argument. 38 | ::: 39 | 40 | ```bash 41 | bash ~/qbt.bash -b "/path/to/built/binary" install 42 | ``` 43 | 44 | The default installation path is determined by type of user executing the script. 45 | 46 | 47 | 48 | 49 | Built to - `qbt-build` 50 | 51 | Optionally installed to `/usr/local/bin/qbittorrent-nox` 52 | 53 | 54 | 55 | 56 | Built to - `qbt-build` 57 | 58 | Optionally installed to `$HOME/bin/qbittorrent-nox` 59 | 60 | 61 | 62 | 63 | ## GitHub Releases 64 | 65 | Optionally you can just download the existing prebuilt binaries released using GitHub Actions. 66 | 67 | ### Quick Install 68 | 69 | > [!NOTE] 70 | > 71 | > `qi.bash`: The quick installer supports Alpine or Debian like systems. 72 | 73 | Latest release using libtorrent `v2` 74 | 75 | ```bash 76 | bash <(curl -sL usrdx.github.io/s/qi.bash) 77 | ``` 78 | 79 | Latest release using libtorrent `v1.2` 80 | 81 | ```bash 82 | bash <(curl -sL usrdx.github.io/s/qi.bash) -lt v1 83 | ``` 84 | 85 | Using Libtorrent v1.2 and forcing the armv7 binary 86 | 87 | ```bash 88 | bash <(curl -sL usrdx.github.io/s/qi.bash) -lt v1 -fa armv7 89 | ``` 90 | 91 | Show the help section 92 | 93 | ```bash 94 | bash <(curl -sL usrdx.github.io/s/qi.bash) -h 95 | ``` 96 | 97 | You can now run it using this command: 98 | 99 | ```bash 100 | ~/bin/qbittorrent 101 | ``` 102 | 103 | > [!TIP] 104 | > Access the WebUI at `http://localhost:8080` 105 | 106 | ### Manual install 107 | 108 | 109 | 110 | 111 | ```bash 112 | mkdir -p ~/bin && source ~/.profile 113 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/x86-qbittorrent-nox 114 | chmod 700 ~/bin/qbittorrent-nox 115 | ``` 116 | 117 | 118 | 119 | ```bash 120 | mkdir -p ~/bin && source ~/.profile 121 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/x86_64-qbittorrent-nox 122 | chmod 700 ~/bin/qbittorrent-nox 123 | ``` 124 | 125 | 126 | 127 | ```bash 128 | mkdir -p ~/bin && source ~/.profile 129 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/aarch64-qbittorrent-nox 130 | chmod 700 ~/bin/qbittorrent-nox 131 | ``` 132 | 133 | 134 | 135 | ```bash 136 | mkdir -p ~/bin && source ~/.profile 137 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/armv7-qbittorrent-nox 138 | chmod 700 ~/bin/qbittorrent-nox 139 | ``` 140 | 141 | 142 | 143 | ```bash 144 | mkdir -p ~/bin && source ~/.profile 145 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/armhf-qbittorrent-nox 146 | chmod 700 ~/bin/qbittorrent-nox 147 | ``` 148 | 149 | 150 | 151 | ## Configuring qbittorrent 152 | 153 | If you want to configure qBittorrent before you start it use this method: 154 | 155 | Create the default configuration directory. 156 | 157 | ```bash 158 | mkdir -p ~/.config/qBittorrent 159 | ``` 160 | 161 | Create the configuration file. 162 | 163 | ```bash 164 | touch ~/.config/qBittorrent/qBittorrent.conf 165 | ``` 166 | 167 | Edit the file 168 | 169 | ```bash 170 | nano ~/.config/qBittorrent/qBittorrent.conf 171 | ``` 172 | 173 | Add this. Make sure to change your web ui port. 174 | 175 | ```ini 176 | [LegalNotice] 177 | Accepted=true 178 | 179 | [Preferences] 180 | WebUI\Port=PORT 181 | ``` 182 | 183 | Default login: 184 | 185 | ```bash 186 | username: admin 187 | password: adminadmin 188 | ``` 189 | 190 | Some key start-up arguments to help you along. Using the command above with no arguments will loads the defaults or the settings defined in the `~/.config/qBittorrent/qBittorrent.conf` 191 | 192 | ```plaintext 193 | Usage: 194 | ./qbittorrent-nox [options] [( | )...] 195 | Options: 196 | -v | --version Display program version and exit 197 | -h | --help Display this help message and exit 198 | --webui-port= Change the Web UI port 199 | -d | --daemon Run in daemon-mode (background) 200 | --profile= Store configuration files in 201 | --configuration= Store configuration files in directories 202 | qBittorrent_ 203 | --relative-fastresume Hack into libtorrent fastresume files and make 204 | file paths relative to the profile directory 205 | files or URLs Download the torrents passed by the user 206 | 207 | Options when adding new torrents: 208 | --save-path= Torrent save path 209 | --add-paused= Add torrents as started or paused 210 | --skip-hash-check Skip hash check 211 | --category= Assign torrents to category. If the category 212 | doesn't exist, it will be created. 213 | --sequential Download files in sequential order 214 | --first-and-last Download first and last pieces first 215 | --skip-dialog= Specify whether the "Add New Torrent" dialog 216 | opens when adding a torrent. 217 | 218 | Option values may be supplied via environment variables. For option named 219 | 'parameter-name', environment variable name is 'QBT_PARAMETER_NAME' (in upper 220 | case, '-' replaced with '_'). To pass flag values, set the variable to '1' or 221 | 'TRUE'. For example, to disable the splash screen: 222 | QBT_NO_SPLASH=1 ./qbittorrent-nox 223 | Command line parameters take precedence over environment variables 224 | ``` 225 | 226 | ## Starting qbittorrent 227 | 228 | Now you just run it and enjoy! 229 | 230 | ```bash 231 | ~/bin/qbittorrent-nox 232 | ``` 233 | 234 | ## Web ui 235 | 236 | To get your external IP with the default qbittorrent command use this command: 237 | 238 | ```bash 239 | echo $(wget -qO - icanhazip.com):8080 240 | ``` 241 | 242 | ## Second instance 243 | 244 | When you simply call the binary using `~/qbittorrent-nox ` it will look for it's configuration in `~/.config/qbittorrent`. 245 | 246 | If you would like to run a second instance using another configuration you can do so like this 247 | 248 | ```bash 249 | ~/bin/qbittorrent-nox --configuration=NAME 250 | ``` 251 | 252 | This will create a new configuration directory using this suffix. 253 | 254 | ```bash 255 | ~/.config/qbittorrent_NAME 256 | ``` 257 | 258 | You will also need a custom nginx proxypass and systemd service. 259 | 260 | And you can now configure this instance separately. 261 | -------------------------------------------------------------------------------- /docs/src/content/docs/introduction.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | description: Introduction 4 | --- 5 | 6 | import { 7 | AdvancedMarkdown, 8 | Aside, 9 | BuildConfigTool, 10 | Badge, 11 | BuildinfoIntroduction, 12 | BuildinfoBuildHelp, 13 | Card, 14 | CardGrid, 15 | Charts, 16 | Details, 17 | FileTree, 18 | GithubActions, 19 | Icon, 20 | LinkCard, 21 | Modal, 22 | Patchinfo, 23 | Scriptinfo, 24 | ScriptVersions, 25 | Steps, 26 | TabItem, 27 | Tabs 28 | } from "/src/components/global.jsx" 29 | 30 | ## What is it? 31 | 32 |
33 | 34 |
35 | 36 | `qbt-nox-static.bash™` was originally a simple, amateurish bash script to build a static `qbittorrent-nox` binary for `x86_64`. The script has grown and evolved since then and now it's complicated, amateurish bash script. 37 | 38 | ### Why are there two scripts? 39 | 40 | `qbittorrent-nox-static.sh` and `qbt-nox-static.bash` 41 | 42 | The former is a fork of the latter, with the following significant changes: 43 | 44 | - Dependency and data handling logic were heavily modified to allow more modular use of the script. 45 | - Breaking changes to the default behavior of the script that would affect existing setups using it. 46 | - Renaming the script to `.bash` from `.sh` as it is not a POSIX-compliant script. 47 | - Combined, these changes would have effectively made `qbittorrent-nox-static.sh` unavailable for use. 48 | - Changes were backported to `qbittorrent-nox-static.sh` during the transition to prevent disruption. 49 | 50 | The transition is complete, and all these changes have been merged into `qbittorrent-nox-static.sh`, so they are effectively the same script with a minor difference in default configuration. 51 | 52 | `qbittorrent-nox-static.sh` has `qbt_legacy_mode="yes"` to emulate the original behavior of the script to facilitate transition with no breaking changes. 53 | 54 | Moving forward, the recommended script is `qbt-nox-static.bash`, but essentially all that matters is the setting of `qbt_legacy_mode="yes"` to determine default behavior. 55 | 56 | ### Script differences? 57 | 58 | 59 | 60 | 61 |
62 | 63 |
64 | 65 | Default behavior: `qbt_legacy_mode="no"` 66 | 67 | When the script is run with no arguments, it will only detect dependencies and offer options required to proceed toward building a binary. 68 | 69 | ```bash 70 | ⬤ qbt.bash install_test ------ installs the minimum required tools to run tests 71 | ⬤ qbt.bash install_core ------ installs the required build tools to use the script 72 | ⬤ qbt.bash bootstrap_deps ---- install_test + install_core 73 | ``` 74 | 75 | It will not do anything else unless prompted to do so and the required dependencies are present. 76 | 77 | :::tip 78 | With the minimum test dependencies installed — `git`, `bash`, and `curl` — it can perform most dynamic help functions and testing required to configure the script before installing the core dependencies. 79 | ::: 80 | 81 | This allows configuration to be done before installing core dependencies when the script is used interactively. 82 | 83 | This makes sense when you consider you don't need to install host `gcc` to cross-build, something the script handles automatically when configured to cross-build. 84 | 85 |
86 | 87 | 88 |
89 | 90 |
91 | 92 | Default behavior: `qbt_legacy_mode="yes"` 93 | 94 | - When the script is run with no arguments and the required privileges are available it will attempt to automatically install the host dependencies if it can. It does this with no user input. 95 | - When arguments are set that create dependency changes, the script will install them automatically when run. 96 | 97 | Reason for this behavior: 98 | 99 | - It was designed to be used in a Docker container as root, not on a normal host, and interactive options came later. 100 | - It was mainly used with GitHub workflows. 101 | 102 | Concerns: 103 | 104 | - It means the environment needs to be configured correctly or commands passed before it is run for the first time to avoid unnecessary dependency installation. 105 | - The behavior of installing dependencies without user interaction is undesirable. 106 | - It was not clear to the end user what was happening without the required context. 107 | 108 | If the host environment is pre-configured, this produces the desired result, but if the user does not understand this and runs the script, it will be confusing to see it installing many packages with no context. 109 | 110 |
111 |
112 | 113 | ### What does it mean to you? 114 | 115 | The documentation will be focused on `qbt-nox-static.bash` as it is the better-behaved script with a better user experience. 116 | 117 | :::note 118 | The binary outcome should be identical for both. You should use `qbt-nox-static.bash`, but if you understand how it works and are using Docker, `.qbt_env`, or a pre-configured environment, `qbittorrent-nox-static.sh` will do the same thing. 119 | ::: 120 | 121 | ## What does it do? 122 | 123 | It handles a lot of the nuanced complexity around building various dependencies on two different host platforms toward the same outcome and can target these architectures via cross-building: 124 | 125 | Cross-building is done by on Alpine and on Debian-based. 126 | 127 |
128 | `armel` `armhf` `armv7` `aarch64` 129 | 130 | `x86` `x86_64` 131 | 132 | `s390x` 133 | 134 | `powerpc` `ppc64el` 135 | 136 | `mips` `mipsel` `mips64` `mips64el` 137 | 138 | `loongarch64` 139 | 140 | `riscv64` 141 |
142 | 143 | ⭐ On supported host build platforms, the `qbt-nox-static.bash` will perform these three main tasks via a simple prompt: 144 | 145 | 146 | 147 | 1. Update the system and install the core build dependencies, based on activated options — requires `root` or `sudo` privileges if any dependencies are missing. 148 | 149 | 2. Download all dependencies locally and build `qbittorrent-nox` with no special privileges required. 150 | 151 | 3. Build a fully static and portable `qbittorrent-nox` binary using the latest versions of all supported dependencies. 152 | 153 | 154 | 155 | The script is highly configurable and is capable of native and cross-building. These more advanced configurations will be discussed in later sections of the documentation. 156 | 157 | ## What is the outcome? 158 | 159 | ⭐ Here is an example successful default build profile: 160 | 161 | 162 | 163 | 164 | 165 | 166 | The script creates a fully static `qbittorrent-nox` binary using 167 | 168 | The final result will show this when using `ldd` 169 | 170 | ```bash 171 | ldd ~/qbt-build/bin/qbittorrent-nox 172 | ``` 173 | 174 | Gives this result: 175 | 176 | ```bash 177 | not a dynamic executable 178 | ``` 179 | 180 | 181 | 182 | 183 | The script creates a fully static `qbittorrent-nox` binary using 184 | 185 | The final result will show this when using `ldd` 186 | 187 | ```bash 188 | ldd ~/qbt-build/bin/qbittorrent-nox 189 | ``` 190 | 191 | Gives this result: 192 | 193 | ```bash 194 | statically linked 195 | ``` 196 | 197 | 198 | 199 | 200 | ### How do I use it? 201 | 202 | The script can be downloaded locally and run on a supported host or via Docker. It has a comprehensive built-in help section, available via the `-h` flag, that explains all options and demonstrates dynamic command choices. The best thing to do is to read the script installation and usage sections to understand the key features and how to use them. 203 | 204 | :::tip[The hard part is done.] 205 | You always have an easy method available to build your own releases — simply fork the repository and use the available workflows. How to do this will be shown in the sections later on. You can build locally or fork the repository, and build and release using CI, where the Git repository acts as a local environment for the script. 206 | ::: 207 | -------------------------------------------------------------------------------- /.github/workflows/ci-alpine-build.yml: -------------------------------------------------------------------------------- 1 | name: ci - alpine build 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | distinct_id: 7 | description: "Distinct id" 8 | required: false 9 | type: string 10 | workflow-files: 11 | description: "Alpine: workflow-files files" 12 | required: true 13 | type: string 14 | icu: 15 | description: "enable icu" 16 | required: true 17 | type: string 18 | debug: 19 | description: "debug builds" 20 | required: true 21 | type: string 22 | script_name: 23 | description: "script name" 24 | required: true 25 | type: string 26 | 27 | jobs: 28 | build: 29 | runs-on: ${{ matrix.runs_on }} 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | runs_on: ["ubuntu-24.04-arm"] 34 | os_id: ["alpine"] 35 | os_version_id: ["edge"] 36 | qbt_cross_name: 37 | ["armhf", "armv7", "aarch64", "riscv64", "x86_64", "x86"] 38 | qbt_libtorrent_version: ["1.2", "2.0"] 39 | qbt_build_tool: [""] 40 | qbt_qbittorrent_tag: [""] 41 | include: 42 | - qbt_build_tool: "" 43 | qbt_qt_version_name: "" 44 | 45 | name: "${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}libtorrent-v${{ matrix.qbt_libtorrent_version }}" 46 | 47 | env: 48 | qbt_build_dir: "qbt-build" 49 | script_name: ${{ inputs.script_name }} 50 | set_skip_icu: ${{ inputs.icu }} 51 | set_workflow_files: ${{ inputs.workflow-files }} 52 | set_build_debug: ${{ inputs.debug }} 53 | set_qbt_mcm_url: "" # default is userdocs/qbt-musl-cross-make 54 | set_qbt_with_qemu: "" # default is yes 55 | set_qbt_host_deps: "" # default is no 56 | set_qbt_host_deps_repo: "" # default is userdocs/qbt-host-deps 57 | workspace: ${{ github.workspace }} 58 | 59 | steps: 60 | - name: Checkout ${{ inputs.distinct_id }} 61 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 62 | with: 63 | persist-credentials: false 64 | 65 | - name: Download ${{ env.script_name }} 66 | run: | 67 | # Make sure the branch is set to master for qbittorrent-nox-static and main qbittorrent-nox-static-test 68 | if [[ ! -f "${script_name}" ]]; then 69 | echo "Downloading ${script_name} from userdocs/qbittorrent-nox-static" 70 | curl -LO "https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/refs/heads/master/${script_name}" 71 | chmod +x "${script_name}" 72 | fi 73 | 74 | - name: Host - Create Docker template env file ${{ inputs.distinct_id }} 75 | run: | 76 | printf '%s\n' "qbt_revision_url=${{ github.repository }}" > env.custom 77 | printf '%s\n' "qbt_zlib_type=zlib" >> env.custom 78 | printf '%s\n' "qbt_skip_icu=${set_skip_icu}" >> env.custom 79 | printf '%s\n' "qbt_boost_tag=${{ matrix.qbt_boost_tag }}" >> env.custom 80 | printf '%s\n' "qbt_libtorrent_version=${{ matrix.qbt_libtorrent_version }}" >> env.custom 81 | printf '%s\n' "qbt_libtorrent_tag=${{ matrix.qbt_libtorrent_tag }}" >> env.custom 82 | printf '%s\n' "qbt_libtorrent_master_jamfile=" >> env.custom 83 | printf '%s\n' "qbt_qt_version=${{ matrix.qbt_qt_version }}" >> env.custom 84 | printf '%s\n' "qbt_qt_tag=${{ matrix.qbt_qt_tag }}" >> env.custom 85 | printf '%s\n' "qbt_qbittorrent_tag=${{ matrix.qbt_qbittorrent_tag }}" >> env.custom 86 | printf '%s\n' "qbt_build_dir=${qbt_build_dir}" >> env.custom 87 | printf '%s\n' "qbt_build_tool=${{ matrix.qbt_build_tool }}" >> env.custom 88 | printf '%s\n' "qbt_cross_name=${{ matrix.qbt_cross_name }}" >> env.custom 89 | printf '%s\n' "qbt_mcm_url=${set_qbt_mcm_url}" >> env.custom 90 | printf '%s\n' "qbt_patches_url=${{ github.repository }}" >> env.custom 91 | printf '%s\n' "qbt_workflow_files=${set_workflow_files}" >> env.custom 92 | printf '%s\n' "qbt_cache_dir=" >> env.custom 93 | printf '%s\n' "qbt_optimise_strip=" >> env.custom 94 | printf '%s\n' "qbt_build_debug=${set_build_debug}" >> env.custom 95 | printf '%s\n' "qbt_standard=" >> env.custom 96 | printf '%s\n' "qbt_static_ish=" >> env.custom 97 | printf '%s\n' "qbt_optimise=${qbt_optimise}" >> env.custom 98 | printf '%s\n' "qbt_with_qemu=${set_qbt_with_qemu}" >> env.custom 99 | printf '%s\n' "qbt_host_deps=${set_qbt_host_deps}" >> env.custom 100 | printf '%s\n\n' "qbt_host_deps_repo=${set_qbt_host_deps_repo}" >> env.custom 101 | 102 | - name: Host - Debian based specific env ${{ inputs.distinct_id }} 103 | if: matrix.os_id != 'alpine' 104 | run: | 105 | printf '%s\n' "LANG=C.UTF-8" >> env.custom 106 | printf '%s\n' "LC_ALL=C.UTF-8" >> env.custom 107 | printf '%s\n\n' "DEBIAN_FRONTEND=noninteractive" >> env.custom 108 | 109 | - name: Host - Bootstrap qemu 110 | uses: userdocs/actions/qemu@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 111 | with: 112 | target_arch: ${{ matrix.qbt_cross_name }} 113 | 114 | - name: Host - Bootstrap docker container 115 | uses: userdocs/actions/qbt_docker@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 116 | with: 117 | os_id: ${{ matrix.os_id }} 118 | os_version_id: ${{ matrix.os_version_id }} 119 | additional_apps: "curl git" 120 | 121 | - name: Host - patches ${{ inputs.distinct_id }} 122 | if: hashFiles('patches/**') != '' 123 | run: mkdir -p "${qbt_build_dir}/patches" && cp -rf patches/* "${qbt_build_dir}/patches/" 124 | 125 | - name: Docker - bootstrap_deps ${{ inputs.distinct_id }} 126 | if: inputs.script_name == 'qbt-nox-static.bash' 127 | run: docker exec "${container_name}" bash "${script_name}" bootstrap_deps 128 | 129 | - name: Docker - Bootstrap build ${{ inputs.distinct_id }} 130 | run: docker exec "${container_name}" bash "${script_name}" -bs-a 131 | 132 | - name: Docker - glibc ${{ inputs.distinct_id }} 133 | if: matrix.os_id != 'alpine' 134 | run: docker exec "${container_name}" bash "${script_name}" glibc 135 | 136 | - name: Docker - zlib ${{ inputs.distinct_id }} 137 | run: docker exec "${container_name}" bash "${script_name}" zlib 138 | 139 | - name: Docker - iconv ${{ inputs.distinct_id }} 140 | if: matrix.qbt_libtorrent_version == '1.2' 141 | run: docker exec "${container_name}" bash "${script_name}" iconv 142 | 143 | - name: Docker - icu ${{ inputs.distinct_id }} 144 | if: env.set_skip_icu == 'no' 145 | run: docker exec "${container_name}" bash "${script_name}" icu 146 | 147 | - name: Docker - openssl ${{ inputs.distinct_id }} 148 | run: docker exec "${container_name}" bash "${script_name}" openssl 149 | 150 | - name: Docker - boost ${{ inputs.distinct_id }} 151 | run: docker exec "${container_name}" bash "${script_name}" boost 152 | 153 | - name: Docker - libtorrent ${{ inputs.distinct_id }} 154 | run: docker exec "${container_name}" bash "${script_name}" libtorrent 155 | 156 | # - name: Docker - double_conversion ${{ inputs.distinct_id }} 157 | # if: matrix.qbt_build_tool == '' 158 | # run: docker exec "${container_name}" bash "${script_name}" double_conversion 159 | 160 | - name: Docker - qtbase ${{ inputs.distinct_id }} 161 | run: docker exec "${container_name}" bash "${script_name}" qtbase 162 | 163 | - name: Docker - qttools ${{ inputs.distinct_id }} 164 | run: docker exec "${container_name}" bash "${script_name}" qttools 165 | 166 | - name: Docker - qbittorrent ${{ inputs.distinct_id }} 167 | run: docker exec "${container_name}" bash "${script_name}" qbittorrent 168 | 169 | - name: Docker - Set release asset name ${{ inputs.distinct_id }} 170 | run: docker exec -w ${wd}/${qbt_build_dir}/completed "${container_name}" mv -f qbittorrent-nox "${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox" 171 | 172 | - name: Generate artifact attestation ${{ inputs.distinct_id }} 173 | uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 174 | with: 175 | subject-path: "${{ env.qbt_build_dir }}/completed/${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox" 176 | 177 | - name: Docker - Release Info ${{ inputs.distinct_id }} 178 | working-directory: "${{ env.workspace }}/${{ env.qbt_build_dir }}/release_info" 179 | run: | 180 | mv *.md *.json "${workspace}/${qbt_build_dir}/completed" 181 | 182 | - name: Host - Upload libtorrent-v${{ matrix.qbt_libtorrent_version }}-qbittorrent-nox and release info artifact ${{ inputs.distinct_id }} 183 | if: success() 184 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 185 | with: 186 | name: libtorrent-v${{ matrix.qbt_libtorrent_version }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox 187 | path: | 188 | ${{ env.qbt_build_dir }}/completed/* 189 | !${{ env.qbt_build_dir }}/completed/*.png 190 | 191 | - name: Host - Upload cmake graphs artifact ${{ inputs.distinct_id }} 192 | if: success() && matrix.qbt_build_tool == '' 193 | uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 194 | with: 195 | name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-graphs" 196 | path: "${{ env.qbt_build_dir }}/completed/*.png" 197 | 198 | # - name: Host - Upload build dir on error or cancel 199 | # if: ( cancelled() || failure() ) 200 | # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 201 | # with: 202 | # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-logs" 203 | # path: "${{ env.qbt_build_dir }}" 204 | -------------------------------------------------------------------------------- /.github/workflows/ci-debian-build.yml: -------------------------------------------------------------------------------- 1 | name: ci - debian build 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | distinct_id: 7 | description: "Distinct id" 8 | required: false 9 | type: string 10 | workflow-files: 11 | description: "Alpine: workflow-files files" 12 | required: true 13 | type: string 14 | icu: 15 | description: "enable icu" 16 | required: true 17 | type: string 18 | debug: 19 | description: "debug builds" 20 | required: true 21 | type: string 22 | script_name: 23 | description: "script name" 24 | required: true 25 | type: string 26 | 27 | jobs: 28 | build: 29 | runs-on: ${{ matrix.runs_on }} 30 | strategy: 31 | fail-fast: false 32 | matrix: 33 | runs_on: ["ubuntu-24.04", "ubuntu-24.04-arm"] 34 | os_id: ["debian", "ubuntu"] 35 | os_version_id: ["trixie", "noble"] 36 | qbt_cross_name: ["default", "aarch64", "x86_64", "riscv64"] 37 | qbt_libtorrent_version: ["1.2", "2.0"] 38 | qbt_build_tool: [""] 39 | qbt_qt_version: ["6"] 40 | exclude: 41 | - os_id: "debian" 42 | os_version_id: "noble" 43 | - os_id: "ubuntu" 44 | os_version_id: "trixie" 45 | 46 | - runs_on: "ubuntu-24.04" 47 | qbt_cross_name: "x86_64" 48 | - runs_on: "ubuntu-24.04-arm" 49 | qbt_cross_name: "aarch64" 50 | 51 | include: 52 | - runs_on: "ubuntu-24.04" 53 | host_name: "x86_64" 54 | - runs_on: "ubuntu-24.04-arm" 55 | host_name: "aarch64" 56 | - qbt_build_tool: "" 57 | qbt_qt_version_name: "" 58 | 59 | name: "${{ matrix.host_name }}-${{ matrix.os_id }}-${{ matrix.os_version_id }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}libtorrent-v${{ matrix.qbt_libtorrent_version }}" 60 | 61 | env: 62 | qbt_build_dir: "qbt-build" 63 | script_name: ${{ inputs.script_name }} 64 | set_skip_icu: ${{ inputs.icu }} 65 | set_workflow_files: ${{ inputs.workflow-files }} 66 | set_build_debug: ${{ inputs.debug }} 67 | set_qbt_mcm_url: "" # default is userdocs/qbt-musl-cross-make 68 | set_qbt_with_qemu: "" # default is yes 69 | set_qbt_host_deps: "" # default is no 70 | set_qbt_host_deps_repo: "" # default is userdocs/qbt-host-deps 71 | workspace: ${{ github.workspace }} 72 | 73 | steps: 74 | - name: Checkout ${{ inputs.distinct_id }} 75 | uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 76 | with: 77 | persist-credentials: false 78 | 79 | - name: Download ${{ env.script_name }} 80 | run: | 81 | # Make sure the branch is set to master for qbittorrent-nox-static and main qbittorrent-nox-static-test 82 | if [[ ! -f "${script_name}" ]]; then 83 | echo "Downloading ${script_name} from userdocs/qbittorrent-nox-static" 84 | curl -LO "https://raw.githubusercontent.com/userdocs/qbittorrent-nox-static/refs/heads/master/${script_name}" 85 | chmod +x "${script_name}" 86 | fi 87 | 88 | - name: Host - Create Docker template env file ${{ inputs.distinct_id }} 89 | run: | 90 | printf '%s\n' "qbt_revision_url=${{ github.repository }}" > env.custom 91 | printf '%s\n' "qbt_zlib_type=zlib" >> env.custom 92 | printf '%s\n' "qbt_skip_icu=${set_skip_icu}" >> env.custom 93 | printf '%s\n' "qbt_boost_tag=${{ matrix.qbt_boost_tag }}" >> env.custom 94 | printf '%s\n' "qbt_libtorrent_version=${{ matrix.qbt_libtorrent_version }}" >> env.custom 95 | printf '%s\n' "qbt_libtorrent_tag=${{ matrix.qbt_libtorrent_tag }}" >> env.custom 96 | printf '%s\n' "qbt_libtorrent_master_jamfile=" >> env.custom 97 | printf '%s\n' "qbt_qt_version=${{ matrix.qbt_qt_version }}" >> env.custom 98 | printf '%s\n' "qbt_qt_tag=${{ matrix.qbt_qt_tag }}" >> env.custom 99 | printf '%s\n' "qbt_qbittorrent_tag=${{ matrix.qbt_qbittorrent_tag }}" >> env.custom 100 | printf '%s\n' "qbt_build_dir=${qbt_build_dir}" >> env.custom 101 | printf '%s\n' "qbt_build_tool=${{ matrix.qbt_build_tool }}" >> env.custom 102 | printf '%s\n' "qbt_cross_name=${{ matrix.qbt_cross_name }}" >> env.custom 103 | printf '%s\n' "qbt_mcm_url=${set_qbt_mcm_url}" >> env.custom 104 | printf '%s\n' "qbt_patches_url=${{ github.repository }}" >> env.custom 105 | printf '%s\n' "qbt_workflow_files=${set_workflow_files}" >> env.custom 106 | printf '%s\n' "qbt_cache_dir=" >> env.custom 107 | printf '%s\n' "qbt_optimise_strip=" >> env.custom 108 | printf '%s\n' "qbt_build_debug=${set_build_debug}" >> env.custom 109 | printf '%s\n' "qbt_standard=" >> env.custom 110 | printf '%s\n' "qbt_static_ish=" >> env.custom 111 | printf '%s\n' "qbt_optimise=${qbt_optimise}" >> env.custom 112 | printf '%s\n' "qbt_with_qemu=${set_qbt_with_qemu}" >> env.custom 113 | printf '%s\n' "qbt_host_deps=${set_qbt_host_deps}" >> env.custom 114 | printf '%s\n\n' "qbt_host_deps_repo=${set_qbt_host_deps_repo}" >> env.custom 115 | 116 | - name: Host - Debian based specific env ${{ inputs.distinct_id }} 117 | if: matrix.os_id != 'alpine' 118 | run: | 119 | printf '%s\n' "LANG=C.UTF-8" >> env.custom 120 | printf '%s\n' "LC_ALL=C.UTF-8" >> env.custom 121 | printf '%s\n\n' "DEBIAN_FRONTEND=noninteractive" >> env.custom 122 | 123 | - name: Host - Bootstrap qemu 124 | uses: userdocs/actions/qemu@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 125 | with: 126 | target_arch: ${{ matrix.qbt_cross_name }} 127 | 128 | - name: Host - Bootstrap docker container 129 | uses: userdocs/actions/qbt_docker@e8f57bd585c7bb6dcce011694d6772bab657abca # v1.0.7 130 | with: 131 | os_id: ${{ matrix.os_id }} 132 | os_version_id: ${{ matrix.os_version_id }} 133 | additional_apps: "curl git" 134 | 135 | - name: Host - patches ${{ inputs.distinct_id }} 136 | if: hashFiles('patches/**') != '' 137 | run: mkdir -p "${qbt_build_dir}/patches" && cp -rf patches/* "${qbt_build_dir}/patches/" 138 | 139 | - name: Docker - bootstrap_deps ${{ inputs.distinct_id }} 140 | if: inputs.script_name == 'qbt-nox-static.bash' 141 | run: docker exec "${container_name}" bash "${script_name}" bootstrap_deps 142 | 143 | - name: Docker - Bootstrap build ${{ inputs.distinct_id }} 144 | run: docker exec "${container_name}" bash "${script_name}" -bs-a 145 | 146 | - name: Docker - glibc ${{ inputs.distinct_id }} 147 | if: matrix.os_id != 'alpine' 148 | run: docker exec "${container_name}" bash "${script_name}" glibc 149 | 150 | - name: Docker - zlib ${{ inputs.distinct_id }} 151 | run: docker exec "${container_name}" bash "${script_name}" zlib 152 | 153 | - name: Docker - iconv ${{ inputs.distinct_id }} 154 | if: matrix.qbt_libtorrent_version == '1.2' 155 | run: docker exec "${container_name}" bash "${script_name}" iconv 156 | 157 | - name: Docker - icu ${{ inputs.distinct_id }} 158 | if: env.set_skip_icu == 'no' 159 | run: docker exec "${container_name}" bash "${script_name}" icu 160 | 161 | - name: Docker - openssl ${{ inputs.distinct_id }} 162 | run: docker exec "${container_name}" bash "${script_name}" openssl 163 | 164 | - name: Docker - boost ${{ inputs.distinct_id }} 165 | run: docker exec "${container_name}" bash "${script_name}" boost 166 | 167 | - name: Docker - libtorrent ${{ inputs.distinct_id }} 168 | run: docker exec "${container_name}" bash "${script_name}" libtorrent 169 | 170 | # - name: Docker - double_conversion ${{ inputs.distinct_id }} 171 | # if: matrix.qbt_build_tool == '' 172 | # run: docker exec "${container_name}" bash "${script_name}" double_conversion 173 | 174 | - name: Docker - qtbase ${{ inputs.distinct_id }} 175 | run: docker exec "${container_name}" bash "${script_name}" qtbase 176 | 177 | - name: Docker - qttools ${{ inputs.distinct_id }} 178 | run: docker exec "${container_name}" bash "${script_name}" qttools 179 | 180 | - name: Docker - qbittorrent ${{ inputs.distinct_id }} 181 | run: docker exec "${container_name}" bash "${script_name}" qbittorrent 182 | 183 | - name: Docker - Set release asset name ${{ inputs.distinct_id }} 184 | run: docker exec -w ${wd}/${qbt_build_dir}/completed "${container_name}" mv -f qbittorrent-nox ${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox 185 | 186 | # - name: Generate artifact attestation ${{ inputs.distinct_id }} 187 | # uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 188 | # with: 189 | # subject-path: "${{ env.qbt_build_dir }}/completed/${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox" 190 | 191 | # - name: Docker - Release Info ${{ inputs.distinct_id }} 192 | # working-directory: "${{ env.workspace }}/${{ env.qbt_build_dir }}/release_info" 193 | # run: | 194 | # mv *.md *.json "${workspace}/${qbt_build_dir}/completed" 195 | 196 | # - name: Host - Upload libtorrent-v${{ matrix.qbt_libtorrent_version }}-qbittorrent-nox and release info artifact ${{ inputs.distinct_id }} 197 | # if: success() 198 | # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 199 | # with: 200 | # name: libtorrent-v${{ matrix.qbt_libtorrent_version }}-${{ matrix.qbt_cross_name }}-${{ matrix.qbt_qt_version_name }}qbittorrent-nox 201 | # path: | 202 | # ${{ env.qbt_build_dir }}/completed/* 203 | # !${{ env.qbt_build_dir }}/completed/*.png 204 | 205 | # - name: Host - Upload cmake graphs artifact ${{ inputs.distinct_id }} 206 | # if: success() && matrix.qbt_build_tool == '' 207 | # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 208 | # with: 209 | # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-graphs" 210 | # path: "${{ env.qbt_build_dir }}/completed/*.png" 211 | 212 | # - name: Host - Upload build dir on error or cancel 213 | # if: ( cancelled() || failure() ) 214 | # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 215 | # with: 216 | # name: "${{ matrix.qbt_cross_name }}-libtorrent-v${{ matrix.qbt_libtorrent_version }}-logs" 217 | # path: "${{ env.qbt_build_dir }}" 218 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # qBittorrent-nox Static Builds 2 | 3 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/9817ad80d35c480aa9842b53001d55b0)](https://app.codacy.com/gh/userdocs/qbittorrent-nox-static?utm_source=github.com&utm_medium=referral&utm_content=userdocs/qbittorrent-nox-static&utm_campaign=Badge_Grade) 4 | [![CodeFactor](https://www.codefactor.io/repository/github/userdocs/qbittorrent-nox-static/badge)](https://www.codefactor.io/repository/github/userdocs/qbittorrent-nox-static) 5 | [![CI](https://github.com/userdocs/qbittorrent-nox-static/actions/workflows/ci-main-reusable-caller.yml/badge.svg)](https://github.com/userdocs/qbittorrent-nox-static/actions/workflows/ci-main-reusable-caller.yml) 6 | 7 | Cross-platform static builds of qBittorrent-nox with the latest dependencies 8 | 9 | [📦 Latest Release](https://github.com/userdocs/qbittorrent-nox-static/releases/latest) • [📖 Documentation](https://userdocs.github.io/qbittorrent-nox-static/introduction/) • [🏷️ All Releases](https://github.com/userdocs/qbittorrent-nox-static/tags) 10 | 11 | > [!TIP] 12 | > 13 | > Docker: Use https://hotio.dev/containers/qbittorrent 14 | > 15 | > Libtorrent `v1.2` and `v2` static builds combined into a single docker image with vpn support. 16 | 17 | ## 🚀 Quick Start 18 | 19 | ### Quick Install 20 | 21 | > [!NOTE] 22 | > 23 | > `qi.bash`: The quick installer supports Alpine or Debian like systems. 24 | 25 | Latest release using libtorrent `v2` 26 | 27 | ```bash 28 | bash <(curl -sL usrdx.github.io/s/qi.bash) 29 | ``` 30 | 31 | Latest release using libtorrent `v1.2` 32 | 33 | ```bash 34 | bash <(curl -sL usrdx.github.io/s/qi.bash) -lt v1 35 | ``` 36 | 37 | Using Libtorrent v1.2 and forcing the armv7 binary 38 | 39 | ```bash 40 | bash <(curl -sL usrdx.github.io/s/qi.bash) -lt v1 -fa armv7 41 | ``` 42 | 43 | Show the help section 44 | 45 | ```bash 46 | bash <(curl -sL usrdx.github.io/s/qi.bash) -h 47 | ``` 48 | 49 | You can now run it using this command: 50 | 51 | ```bash 52 | ~/bin/qbittorrent 53 | ``` 54 | 55 | > [!TIP] 56 | > Access the WebUI at `http://localhost:8080` 57 | 58 | ### What You Get 59 | 60 | - ✅ **No installation hassles** - Single static binary 61 | - ✅ **Latest versions** - Always up-to-date dependencies 62 | - ✅ **Universal compatibility** - Runs on any Linux distro 63 | - ✅ **Multiple architectures** - Support for ARM devices too 64 | 65 | ## 📋 Table of Contents 66 | 67 | - [Overview](#-overview) 68 | - [Features](#-features) 69 | - [Installation](#-installation) 70 | - [Libtorrent Versions](#-libtorrent-versions) 71 | - [Version Management](#-version-management) 72 | - [Dependency Tracking](#-dependency-tracking) 73 | - [Build Attestation](#%EF%B8%8F-build-attestation) 74 | - [Related Projects](#-related-projects) 75 | - [WSL2 Support](#-wsl2-support) 76 | - [Documentation](#-documentation) 77 | 78 | ## 🔍 Overview 79 | 80 | The `qbittorrent-nox-static` project provides a bash build script that compiles static `qbittorrent-nox` binaries using the latest available dependencies from their source. These statically linked binaries offer several advantages: 81 | 82 | - **Universal compatibility**: Run on any Linux distribution with matching CPU architecture 83 | - **No dependencies**: All required libraries are statically linked 84 | - **Latest versions**: Built with the most recent stable releases of all dependencies 85 | - **Multiple architectures**: Support for x86, x86_64, ARM variants 86 | 87 | ## ✨ Features 88 | 89 | - 🔧 **Static compilation** - No external dependencies required 90 | - 🏗️ **Multi-architecture support** - x86, x86_64, armhf, armv7, aarch64 91 | - 📦 **Latest dependencies** - Always built with current stable versions 92 | - 🔄 **Automated builds** - CI/CD pipeline ensures fresh releases 93 | - 🛡️ **Build attestation** - Cryptographically signed provenance 94 | - 📊 **Version tracking** - JSON metadata for dependency versions 95 | 96 | ## 📦 Installation 97 | 98 | Choose the command that matches your system architecture: 99 | 100 | ### x86 (32-bit Intel/AMD) 101 | 102 | ```bash 103 | mkdir -p ~/bin && source ~/.profile 104 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/x86-qbittorrent-nox 105 | chmod 700 ~/bin/qbittorrent-nox 106 | ``` 107 | 108 | ### x86_64 (64-bit Intel/AMD) 109 | 110 | ```bash 111 | mkdir -p ~/bin && source ~/.profile 112 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/x86_64-qbittorrent-nox 113 | chmod 700 ~/bin/qbittorrent-nox 114 | ``` 115 | 116 | ### armhf (ARM v6 - Raspberry Pi 1/Zero) 117 | 118 | ```bash 119 | mkdir -p ~/bin && source ~/.profile 120 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/armhf-qbittorrent-nox 121 | chmod 700 ~/bin/qbittorrent-nox 122 | ``` 123 | 124 | ### armv7 (ARM v7 - Raspberry Pi 2/3/4 32-bit) 125 | 126 | ```bash 127 | mkdir -p ~/bin && source ~/.profile 128 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/armv7-qbittorrent-nox 129 | chmod 700 ~/bin/qbittorrent-nox 130 | ``` 131 | 132 | ### aarch64 (ARM 64-bit - Raspberry Pi 3/4/5 64-bit) 133 | 134 | ```bash 135 | mkdir -p ~/bin && source ~/.profile 136 | wget -qO ~/bin/qbittorrent-nox https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/aarch64-qbittorrent-nox 137 | chmod 700 ~/bin/qbittorrent-nox 138 | ``` 139 | 140 | ## 🔧 Libtorrent Versions 141 | 142 | > [!IMPORTANT] 143 | > **Libtorrent v1.2** is currently the main branch supported by qBittorrent since the release of [4.4.5](https://www.qbittorrent.org/news.php). However, both v1.2 and v2.0 builds are provided. 144 | 145 | This project automatically builds and releases binaries for both Libtorrent versions: 146 | 147 | - **Libtorrent v1.2**: Stable and widely supported (recommended) 148 | - **Libtorrent v2.0**: Latest features and improvements 149 | 150 | > [!TIP] 151 | > You can view all current releases and pre-releases at 152 | 153 | ## 🎯 Version Management 154 | 155 | ### Getting Version-Specific Releases 156 | 157 | Since this project builds both v1.2 and v2.0 simultaneously, you can target specific libtorrent versions using these commands: 158 | 159 | #### Libtorrent v1.2 Release Info 160 | 161 | ```bash 162 | jq -r '. | "release-\(.qbittorrent)_v\(.libtorrent_1_2)"' < <(curl -sL https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/dependency-version.json) 163 | ``` 164 | 165 | #### Libtorrent v2.0 Release Info 166 | 167 | ```bash 168 | jq -r '. | "release-\(.qbittorrent)_v\(.libtorrent_2_0)"' < <(curl -sL https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/dependency-version.json) 169 | ``` 170 | 171 | ### Build Revisions 172 | 173 | The build system tracks 5 main dependencies that trigger automatic rebuilds: 174 | 175 | - qBittorrent 176 | - Libtorrent 177 | - Qt 178 | - Boost 179 | - OpenSSL 180 | 181 | **Revision Tracking:** 182 | 183 | - New releases start at revision `0` 184 | - Incremented by `1` for each rebuild 185 | - Updates to Qt, Boost, or OpenSSL only update existing release assets 186 | - Updates to qBittorrent or Libtorrent create new releases 187 | 188 | #### Check Latest Revision 189 | 190 | ```bash 191 | jq -r '.revision' < <(curl -sL "https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/dependency-version.json") 192 | ``` 193 | 194 | #### Track Specific Version Revisions 195 | 196 | For independent tracking of v1.2 and v2.0 revisions: 197 | 198 | 1. **Get the release tag:** 199 | 200 | ```bash 201 | release="$(jq -r '. | "release-\(.qbittorrent)_v\(.libtorrent_1_2)"' < <(curl -sL https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/dependency-version.json))" 202 | ``` 203 | 204 | 2. **Get the revision for that release:** 205 | 206 | ```bash 207 | jq -r '.revision' < <(curl -sL "https://github.com/userdocs/qbittorrent-nox-static/releases/download/${release}/dependency-version.json") 208 | ``` 209 | 210 | ## 📊 Dependency Tracking 211 | 212 | Each release includes a `dependency-version.json` file that provides version information shared across latest and pre-releases. This helps overcome API limitations for consistent access to version data. 213 | 214 | ### Download Dependency Information 215 | 216 | ```bash 217 | curl -sL https://github.com/userdocs/qbittorrent-nox-static/releases/latest/download/dependency-version.json 218 | ``` 219 | 220 | ### Example Output 221 | 222 | ```json 223 | { 224 | "openssl": "3.2.0", 225 | "boost": "1.84.0", 226 | "libtorrent_1_2": "1.2.19", 227 | "libtorrent_2_0": "2.0.9", 228 | "qt5": "5.15.12", 229 | "qt6": "6.6.1", 230 | "qbittorrent": "4.6.2", 231 | "revision": "3" 232 | } 233 | ``` 234 | 235 | > [!IMPORTANT] 236 | > Starting with qBittorrent v5, configure-based builds will be unsupported. Only CMake builds will be available, with Qt6 as the default. Qt5 builds will be considered legacy and eventually dropped. 237 | 238 | ## 🛡️ Build Attestation 239 | 240 | Binaries built from `release-5.0.0_v2.0.10` and `release-5.0.0_v1.2.19` revision `1` onwards use [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) for cryptographic verification. 241 | 242 | ### Verify Binary Integrity 243 | 244 | You can verify the integrity and provenance of downloaded binaries using GitHub CLI: 245 | 246 | ```bash 247 | gh attestation verify x86_64-qbittorrent-nox -o userdocs 248 | ``` 249 | 250 | ### Example Verification Output 251 | 252 | ```bash 253 | Loaded digest sha256:a656ff57b03ee6218205d858679ea189246caaecbbcc38d4d2b57eb81d8e59bb for file://x86_64-qbittorrent-nox 254 | Loaded 1 attestation from GitHub API 255 | ✓ Verification succeeded! 256 | 257 | sha256:a656ff57b03ee6218205d858679ea189246caaecbbcc38d4d2b57eb81d8e59bb was attested by: 258 | REPO PREDICATE_TYPE WORKFLOW 259 | userdocs/qbittorrent-nox-static https://slsa.dev/provenance/v1 .github/workflows/matrix_multi_build_and_release_qbt_workflow_files.yml@refs/heads/master 260 | ``` 261 | 262 | For more information, visit the [GitHub CLI attestation documentation](https://cli.github.com/manual/gh_attestation_verify). 263 | 264 | ## 🔗 Related Projects 265 | 266 | This build script depends on several related repositories: 267 | 268 | - [qbt-musl-cross-make](https://github.com/userdocs/qbt-musl-cross-make) - Cross-compilation toolchain 269 | - [qbt-workflow-files](https://github.com/userdocs/qbt-workflow-files) - CI/CD workflow templates 270 | - [qbt-host-deps](https://github.com/userdocs/qbt-host-deps) - Host dependency management 271 | 272 | ## 💻 WSL2 Support 273 | 274 | > [!TIP] 275 | > These static builds work perfectly on WSL2! After installation, access the WebUI at `localhost:8080` from your Windows browser. 276 | 277 | The static nature of these builds makes them ideal for WSL2 environments where dependency management can be challenging. 278 | 279 | ## 📖 Documentation 280 | 281 | > [!TIP] 282 | > For comprehensive documentation, visit the [project documentation](https://userdocs.github.io/qbittorrent-nox-static/introduction/) which covers: 283 | > 284 | > - Detailed build instructions 285 | > - Advanced configuration options 286 | > - Troubleshooting guides 287 | > - Contributing guidelines 288 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | # AI Coding Guide for This Repo 2 | 3 | Purpose: Make AI contributions precise, minimal, and correct. Follow these rules strictly. Do not expand scope beyond the prompt. 4 | 5 | ## Bash scripting (applies to all repos) 6 | 7 | Do 8 | - Use `#!/bin/bash` as the shebang for Bash scripts. 9 | - Use the `.bash` extension for Bash; use `.sh` only for POSIX-only scripts. 10 | - Prefer `$BASH_SOURCE` over `$0` for script path detection. 11 | - Use `printf '%s'` for plain strings and `printf '%b'` for escape sequences. Avoid `echo`. 12 | - Keep changes simple, modular, and scoped to the exact prompt. 13 | - Write readable code; add concise comments explaining intent and non-obvious logic. 14 | - Handle errors explicitly (per function is acceptable); return helpful, actionable messages. 15 | - Structure changes in small stages; keep functions focused. 16 | - Format using Google’s Shell Style Guide: https://google.github.io/styleguide/shellguide.html 17 | - For Bash references, consult: https://mywiki.wooledge.org and https://mywiki.wooledge.org/BashFAQ and include a source link when possible. Do not invent links. 18 | 19 | Avoid 20 | - Global “set -euo pipefail”; prefer targeted checks and explicit error handling. 21 | - Uppercase variable names for general scripting (reserve UPPERCASE for Docker/env settings). 22 | - Clever one-liners that harm clarity. 23 | - Generalized or speculative changes not asked for in the prompt. 24 | - Over-engineering; keep it stable, concise, and C-like in mindset. 25 | 26 | Scope and behavior 27 | - Only implement what the prompt requests. 28 | - Keep solutions minimal and modular; do not add placeholders or future-proofing unless required. 29 | - When giving Bash/shell answers, add a relevant wooledge link if helpful; never fabricate links. 30 | 31 | ## GitHub Workflows (all repos) 32 | 33 | - In reusable workflows, any job that uses outputs from another job must declare that job in `needs` to avoid null outputs. 34 | - Do not use outdated Actions. Check for current recommended versions before editing. 35 | - The `gh` CLI cannot fetch the ID of a workflow run it just started via `gh run workflow`. List runs afterward and extract the ID. 36 | 37 | ## If repo name matches `*-musl-cross-make` 38 | 39 | Toolchain specifics 40 | - Use both `-static` and `--static` to produce static toolchain binaries. Using only `-static` can miss POSIX threads. 41 | - When using `../config.mak`, always load options from both `../gcc-configure-options.md` and `../gcc-configure-options-recursive.md`. 42 | - The binutils gold linker is deprecated. Use `ld=default` and `--disable-gold`. 43 | 44 | Fully static toolchains with musl 45 | - Do not use LTO: avoid `-flto` and `-fuse-linker-plugin`. 46 | - Do not add any LTO-related settings. 47 | - Only set linker options such as `LDFLAGS` at link time, not during library builds. 48 | - GNU libtool redefines `-static`; to ensure static linking, use `--static` or `-Wl,-static` (optionally with `-static`) in `LDFLAGS`. 49 | - For static OpenSSL: do not use `openssl -static` (it disables threads/PIE/PIC). For `-static-pie` with musl/Alpine, use the correct flags and approach. 50 | - Do not use glibc-only flags or glibcisms for musl toolchains. 51 | 52 | ## Debugging with QEMU 53 | 54 | - Start the target under QEMU with gdbstub, then attach with gdb: 55 | - `qemu -g ` (e.g., `qemu -g 1234 ./qbt-nox-static`) 56 | - In another terminal: `gdb ./qbt-nox-static` and `target remote :1234` 57 | 58 | ## If repo name matches `*qbittorrent-nox-static` 59 | 60 | `qi.bash` script goals 61 | - Simple installer that verifies installation and binaries. 62 | - Shebang must be `#!/bin/bash`. 63 | 64 | OS detection 65 | - `source /etc/os-release`. 66 | - Supported: `ID=alpine`, `ID=debian`, or `ID_LIKE` contains `debian`. Otherwise exit with a clear reason. 67 | 68 | Transfer tools 69 | - Prefer `curl` if present; use `wget` if present and `curl` is not; exit if neither is available. 70 | - Detect presence of `gh` CLI and use it when available, but it is not required. 71 | 72 | Architecture detection 73 | - Alpine: `apk --print-arch`. 74 | - Debian-like: `dpkg --print-architecture`. 75 | - Architectures are the same across distros except `armhf`: Debian uses `armv7`, Alpine uses `armv6`. 76 | - If architecture is not valid/supported, exit with a reason. 77 | 78 | Download function 79 | - Build the download URL from the detected architecture. 80 | - Create and store the download’s SHA-256 sum. 81 | 82 | Attestation (optional) 83 | - When `gh` CLI is available and usable, verify downloaded binaries: 84 | - `gh attestation verify --repo 2> /dev/null` 85 | 86 | Error handling 87 | - Provide a helper that checks command exit codes and exits with a concise, helpful message on failure. 88 | 89 | Output formatting 90 | - Provide a print helper that supports: 91 | - `[INFO]` (blue), `[WARNING]` (yellow), `[ERROR]` (red), `[SUCCESS]` (green), `[FAILURE]` (magenta) 92 | - Use `printf '%s'` and `printf '%b'`; do not use `echo`. 93 | - Keep messages succinct. Be verbose only on errors to aid troubleshooting. 94 | 95 | --- 96 | 97 | Meta for AI contributors 98 | - Be conservative: do only what the prompt requests. No broad refactors. 99 | - Prefer small, well-named functions and staged changes. 100 | - Preserve existing public behavior and style unless the prompt requires changes. 101 | - If something cannot be done with available context/tools, state why and propose the smallest viable alternative. 102 | # Bash Scripting - All repos 103 | 104 | - use $BASH_SOURCE instead of $0 105 | - don't use uppercase variables for general scripting. Only use them for docker specific environment settings 106 | - avoid set -euo pipefail - instead focus on thorough testing, validation and error handling. 107 | - ideally error handling should be considered holistically but per function is acceptable. 108 | - changes and recommendations should be simple, modular, focused on the requirement of the prompt. 109 | - never make generalized changes that are not specifically required for the prompt. 110 | - don't over complicated the solution or pollute it with noisy or complex solutions. 111 | - Always makes changes in stages, a modular approach. 112 | - use Google style guide for formatting of bash scripts - https://google.github.io/styleguide/shellguide.html 113 | - Always use `#!/bin/bash` as the shebang. 114 | - Always use the extensions `bash` for bash script and `sh` only for posix shell scripts 115 | - Use `printf '%s'` for printing strings and `printf '%b'` for escape sequences. **Avoid using `echo`.** 116 | - Comment code to explain changes and logic. 117 | - always prefer readability of code over complex one lines. Unless that foramt is promoted by the style guide. 118 | - For Bash/shell questions, consult [mywiki.wooledge.org](https://mywiki.wooledge.org) or [BashFAQ](https://mywiki.wooledge.org/BashFAQ) first. **Provide a source link when possible.** 119 | - Don't hallucinate links in comments 120 | - think like a c developer not a javascript developer. stable, concise, elegant and thoughtful. Not edgy and bleeding edge for the sake of it. 121 | - when providing a solution to a prompt don't provide solutions outside the scope of the prompt nor add loads checks and fallbacks that quickly become redundant in following prompts. 122 | - it makes me wast premium tokens making you fix the brken things you added or changed that were outside the scope of the prompt to begin with. 123 | - provide changes specific to the prompt given. 124 | 125 | # GitHub Workflows - All repos 126 | 127 | - In reusable workflows, jobs that use outputs from other jobs **must** include those jobs in their `needs` section to avoid null variables. 128 | - Do not use outdated GitHub Actions in workflow code. Always check the version recommended is the current version 129 | - The `gh` CLI cannot get the ID of a workflow it started with `gh run workflow`; you must list runs after and extract the ID. 130 | 131 | # If repo = *-musl-cross-make 132 | GCC / Binutils 133 | - Use both `-static` and `--static` to create static toolchain binaries. Using `-static` alone can cause errors (e.g., missing POSIX threads). 134 | - When working with `../config.mak`, always load options from both `../gcc-configure-options.md` and `../gcc-configure-options-recursive.md`. 135 | - The binutils gold linker is deprecated. Use `ld=default` and `--disable-gold`. 136 | - For fully static toolchains linked to musl: 137 | - Do **not** use `-flto` or `-fuse-linker-plugin` (LTO is not supported; plugins require dynamic loading). 138 | - Do **not** add any LTO settings. 139 | - Only set linker options like `LDFLAGS` when linking, **not** when building libraries. 140 | - GNU libtool redefines `-static`; to ensure static linking, use `--static` or `-Wl,-static` in `LDFLAGS` (possibly with `-static`). 141 | - When building OpenSSL statically, do **not** use `openssl -static` (it disables threads, PIE, PIC). For `-static-pie` binaries with musl/Alpine, use the correct flags. 142 | - Do **not** suggest glibc-only flags or glibcisms for musl toolchains. 143 | 144 | # Debugging with qemu 145 | 146 | - To debug with QEMU: 147 | Run `qemu -g ` (e.g., `qemu -g 1234 ./qbt-nox-static`), then connect with `gdb ./qbt-nox-static` in another terminal. 148 | 149 | # If repo = * qbittorrent-nox-static 150 | 151 | ## qi.bash script 152 | 153 | General features 154 | - Always use `#!/bin/bash` as the shebang. 155 | - this script is focused on being a simple installer that verifies installation and binaries. 156 | 157 | basic check for supported os 158 | - use source /etc/os-release 159 | - if ID = alpine of debian or if the or if ID_LIKE=debian is debian like we can proceed. 160 | - if not supported os exit with reason. 161 | 162 | basic check for wget or curl, default to curl if present. 163 | - if no tools exit with reason. 164 | - wget or curl must have, curl default if present but use wget if there. 165 | - check if gh cli is available to use but no required. 166 | 167 | basic check of which arch using 168 | - alpine use apk --print-arch 169 | - debian like use dpkg --print-architecture 170 | - all arches are the same except armhf. on debian this is armv7 and alpine armv6 171 | - if not valid arch exit with reason. 172 | 173 | create download function based on arch checks. 174 | - configure download url based on arch. 175 | - creates sha256 of download. 176 | 177 | gh cli function 178 | - if gh cli exists and is usable use it to very the binaries downloaded 179 | - if gh attestation verify --repo 2> /dev/null; then ... 180 | 181 | error handling 182 | - there should be a error handling function to test commands exit the script with helpful explanations when a command or function fails. 183 | 184 | ouputs 185 | - there should be a function to handle printing outputs. 186 | - It should handle [INFO] (blue) [WARNING] (yellow) [ERROR] (red) [SUCCESS] (Green) [FAILURE] (magenta) 187 | - Use `printf '%s'` for printing strings and `printf '%b'` for escape sequences. **Avoid using `echo`.** 188 | - this function will provide end user information understanding or troubleshooting script outcomes. 189 | - it should be succinct unless there is an error or failure, then it should be verbose enough to help. 190 | 191 | ## Astro and Astro starlight template for documentation 192 | 193 | - Always use the mcp server https://mcp.docs.astro.build/mcp 194 | - Always make sure imported mdx components start with an upper case letter. 195 | -------------------------------------------------------------------------------- /docs/src/assets/stage3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Aura Output 4 | 39 | 40 |
41 | Checking: available privileges 42 | 43 | root 44 | sudo 45 | 46 | Checking: test 47 | 48 | bash 49 | curl 50 | git 51 | 52 | Checking: core 53 | 54 | autoconf 55 | automake 56 | build-base 57 | cmake 58 | graphviz 59 | libtool 60 | linux-headers 61 | ninja-build 62 | ninja-is-really-ninja 63 | perl 64 | pkgconf 65 | py3-numpy 66 | py3-numpy-dev 67 | python3 68 | python3-dev 69 | re2c 70 | ttf-freefont 71 | xz 72 | 73 | Dependencies: All checks passed, continuing to build 74 | 75 | Test URL = passed 76 | 77 | Script version: 2.2.2 78 | 79 | Below is a list of supported modules: 80 | 81 | all zlib openssl boost libtorrent qtbase qttools qbittorrent 82 | 83 | Default env settings 84 | 85 | qbt_zlib_type="zlib" 86 | qbt_skip_icu="yes" 87 | qbt_boost_tag="boost-1.89.0" 88 | qbt_libtorrent_version="2.0" 89 | qbt_libtorrent_tag="v2.0.11" 90 | qbt_libtorrent_master_jamfile="no" 91 | qbt_qt_version="6" 92 | qbt_qt_tag="v6.9.1" 93 | qbt_qbittorrent_tag="release-5.1.2" 94 | qbt_build_dir="qbt-build" 95 | qbt_build_tool="cmake" 96 | qbt_cross_name="default" 97 | qbt_mcm_url="userdocs/qbt-musl-cross-make" 98 | qbt_patches_url="userdocs/qbittorrent-nox-static" 99 | qbt_workflow_files="no" 100 | qbt_cache_dir="" 101 | qbt_optimise_strip="yes" 102 | qbt_build_debug="no" 103 | qbt_standard="20" 104 | qbt_static_ish="no" 105 | qbt_optimise="no" 106 | qbt_with_qemu="yes" 107 | qbt_host_deps="no" 108 | qbt_host_deps_repo="userdocs/qbt-host-deps" 109 | qbt_legacy_mode="no" 110 | qbt_advanced_view="yes" 111 | 112 |
113 | --------------------------------------------------------------------------------