Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
736a93cb92 | ||
|
|
5c99cdf7c9 | ||
|
|
8da338a887 | ||
|
|
155097ce6f | ||
|
|
eb9bb069d6 | ||
|
|
53523a6a1e | ||
|
|
ffdc16fc22 | ||
|
|
8d14775759 | ||
|
|
cd5f96c26a | ||
|
|
877e5f3104 | ||
|
|
d91ea053a2 | ||
|
|
f326097d33 | ||
|
|
efa29074f8 | ||
|
|
99fcb02963 | ||
|
|
e4981957d4 | ||
|
|
8c83947331 | ||
|
|
13f9564fa4 | ||
|
|
4d8b162099 | ||
|
|
b8d7669c6c | ||
|
|
d08b483c3b | ||
|
|
f3f7d564e3 | ||
|
|
38b65fee63 | ||
|
|
6580ed01f3 | ||
|
|
8cc3d78b3d | ||
|
|
1dd74f3ec8 | ||
|
|
bacd3d053e | ||
|
|
287e792d29 | ||
|
|
383adc4e35 | ||
|
|
ba740b4568 | ||
|
|
e7c419ce78 | ||
|
|
363b79e13f | ||
|
|
05b1c8b829 | ||
|
|
cf03d6c8b3 | ||
|
|
6cfdbbd68b | ||
|
|
2c0d5584e2 | ||
|
|
288af543a6 | ||
|
|
afeb937db7 | ||
|
|
c8a699da0b | ||
|
|
6e49cf279f | ||
|
|
631378a80d | ||
|
|
1ef37a02dd | ||
|
|
b618e20fbf | ||
|
|
6be2bd85e5 | ||
|
|
8149cc0320 | ||
|
|
72b5439137 | ||
|
|
8f87aa9e43 | ||
|
|
e83f2c1808 | ||
|
|
a6d56657b2 | ||
|
|
67af2f3a95 | ||
|
|
b47fc056e3 | ||
|
|
007ecaea80 | ||
|
|
d2eea2e0f1 | ||
|
|
a88fa72b16 | ||
|
|
fead132b5c | ||
|
|
bfef7285f6 | ||
|
|
35efcea657 | ||
|
|
9b58aa30e5 | ||
|
|
38dce9b358 | ||
|
|
bc8daf18c0 | ||
|
|
4cd5d170ea | ||
|
|
4ec52a646b | ||
|
|
ee78c2c58b | ||
|
|
bdfa7f45fc | ||
|
|
1ec5582527 | ||
|
|
75697e4ebf | ||
|
|
7a19792be8 | ||
|
|
601b2db35b | ||
|
|
16506ed55a | ||
|
|
cc218245c3 | ||
|
|
b625cf4958 | ||
|
|
92c0f52324 | ||
|
|
880ab87da2 | ||
|
|
7e34e43cf5 | ||
|
|
4a1e06fda7 | ||
|
|
e1647d8f93 | ||
|
|
0badc70c4d | ||
|
|
9fbddc5b99 | ||
|
|
eb7e6f2ba2 | ||
|
|
a7eb82ffda | ||
|
|
d3f2509c30 | ||
|
|
3e1a31755c | ||
|
|
70bce92bf3 | ||
|
|
80e4a1c4f8 | ||
|
|
ceb3c04aff | ||
|
|
953f29b65e | ||
|
|
404f2efc04 | ||
|
|
c23389c0a8 | ||
|
|
7837373d81 | ||
|
|
3600ac54ea | ||
|
|
ec47877277 | ||
|
|
9a33749eca | ||
|
|
c104931341 | ||
|
|
6a245d70d9 | ||
|
|
4ca3b180a8 |
No files matched your search
@@ -246,6 +246,26 @@ jobs:
|
||||
if: inputs.push_digests
|
||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
- name: Verify OpenCode install with a read-only browser profile
|
||||
shell: bash
|
||||
env:
|
||||
IMAGE: ${{ inputs.push_digests && format('{0}@{1}', env.DOCKERHUB_IMAGE, steps.docker_build.outputs.digest) || matrix.local_tag }}
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
PROFILE_DIR="$(mktemp -d)"
|
||||
"$DOCKER_BINARY" run --rm --platform '${{ matrix.platform }}' \
|
||||
--volume "$PROFILE_DIR:/home/archivebox/.config/chromium:ro" \
|
||||
"$IMAGE" bash -c '
|
||||
set -Eeuo pipefail
|
||||
test -w "$XDG_CONFIG_HOME"
|
||||
test ! -w "$XDG_CONFIG_HOME/chromium"
|
||||
# Check the shipped executable before the installer can repair
|
||||
# an image that accidentally omitted this opt-in dependency.
|
||||
"$ABXPKG_LIB_DIR/pnpm/packages/opencode/node_modules/.bin/opencode" --version
|
||||
archivebox install opencode
|
||||
"$ABXPKG_LIB_DIR/pnpm/packages/opencode/node_modules/.bin/opencode" --version
|
||||
'
|
||||
|
||||
- name: Validate exact built image version and commit
|
||||
if: ${{ !inputs.push_digests }}
|
||||
shell: bash
|
||||
@@ -296,8 +316,8 @@ jobs:
|
||||
MANIFEST="$("$DOCKER_BINARY" buildx imagetools inspect --raw "${DOCKERHUB_IMAGE}@${IMAGE_DIGEST}")"
|
||||
fi
|
||||
COMPRESSED_SIZE="$(MANIFEST="$MANIFEST" "$UV_BINARY" run --no-cache --no-project python -c 'import json, os; manifest = json.loads(os.environ["MANIFEST"]); print(manifest["config"]["size"] + sum(layer["size"] for layer in manifest["layers"]))')"
|
||||
LIMIT=$((750 * 1024 * 1024))
|
||||
echo "${DIGEST} compressed_size=$((COMPRESSED_SIZE / 1024 / 1024)) MiB limit=750 MiB"
|
||||
LIMIT=$((900 * 1024 * 1024))
|
||||
echo "${DIGEST} compressed_size=$((COMPRESSED_SIZE / 1024 / 1024)) MiB limit=900 MiB"
|
||||
(( COMPRESSED_SIZE < LIMIT ))
|
||||
|
||||
- name: Resolve real Docker CLI test dependencies through abxpkg
|
||||
@@ -423,7 +443,7 @@ jobs:
|
||||
'${{ runner.temp }}/archivebox-image.tar' \
|
||||
'${{ steps.docker_build_pr.outputs.digest }}' \
|
||||
"$LOCAL_IMAGE_ID" \
|
||||
"$((750 * 1024 * 1024))" <<'PY'
|
||||
"$((900 * 1024 * 1024))" <<'PY'
|
||||
from hashlib import sha256
|
||||
import json
|
||||
import os
|
||||
|
||||
@@ -49,3 +49,17 @@ jobs:
|
||||
push_digests: true
|
||||
full_tests: false
|
||||
secrets: inherit
|
||||
|
||||
opencode:
|
||||
needs: prepare
|
||||
if: needs.prepare.outputs.action == 'ready' || needs.prepare.outputs.action == 'reserved'
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test_file:
|
||||
- archivebox/tests/test_opencode_agent.py
|
||||
- archivebox/tests/test_opencode_browser.py
|
||||
uses: ./.github/workflows/test-parallel.yml
|
||||
with:
|
||||
test_file: ${{ matrix.test_file }}
|
||||
secrets: inherit
|
||||
@@ -2,6 +2,12 @@ name: Parallel Tests
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
test_file:
|
||||
description: Run one discovered test file; empty runs the complete matrix
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
|
||||
env:
|
||||
PYTHONIOENCODING: utf-8
|
||||
@@ -58,10 +64,15 @@ jobs:
|
||||
|
||||
- name: Discover every test exactly once
|
||||
id: discover
|
||||
env:
|
||||
TEST_FILE: ${{ inputs.test_file }}
|
||||
run: |
|
||||
set -Eeuo pipefail
|
||||
mapfile -t output < <("$PYTHON_BINARY" .github/scripts/discover_test_matrix.py)
|
||||
test "${#output[@]}" -eq 2
|
||||
if [[ -n "$TEST_FILE" ]]; then
|
||||
output[1]="$("$JQ_BINARY" -ce '[.[] | select(.paths == [env.TEST_FILE])] | select(length == 1)' <<< "${output[1]}")"
|
||||
fi
|
||||
echo "tests=${output[1]}" >> "$GITHUB_OUTPUT"
|
||||
echo "${output[0]}"
|
||||
"$JQ_BINARY" -e 'length > 0 and length <= 256 and ([.[].paths[]] | length == (unique | length))' <<< "${output[1]}"
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
|
||||
# Multistage ArchiveBox Dockerfile that consumes the abx-dl runtime image.
|
||||
# abx-dl owns Python, Node, Chromium, and downloader plugin runtimes.
|
||||
# ArchiveBox owns sonic, supervisor, Django, and the app runtime.
|
||||
# WHY: abx-dl owns Python, Node, Chromium, and extraction dependencies so the
|
||||
# standalone downloader stays independent of ArchiveBox's server features.
|
||||
# ArchiveBox-only dependencies (Sonic, OpenCode, supervisor, Django) belong in
|
||||
# the layers added by this Dockerfile, never in the shared abx-dl base image.
|
||||
# Build abx-dl first, then point this file at it:
|
||||
# docker buildx build ../abx-dl -f ../abx-dl/Dockerfile \
|
||||
# --build-context abxbus=../abxbus \
|
||||
@@ -10,10 +12,10 @@
|
||||
# --build-context abx-plugins=../abx-plugins \
|
||||
# -t archivebox/abx-dl:dev
|
||||
# docker buildx build . -f Dockerfile \
|
||||
# --build-arg ABX_DL_IMAGE=archivebox/abx-dl:1.12.289 \
|
||||
# --build-arg ABX_DL_IMAGE=archivebox/abx-dl:1.12.315 \
|
||||
# -t archivebox:multistage
|
||||
|
||||
ARG ABX_DL_IMAGE=archivebox/abx-dl:1.12.289
|
||||
ARG ABX_DL_IMAGE=archivebox/abx-dl:1.12.315
|
||||
|
||||
FROM archivebox/sonic:1.4.9 AS sonic
|
||||
FROM ${ABX_DL_IMAGE} AS archivebox-runtime-base
|
||||
@@ -250,6 +252,17 @@ RUN --mount=type=cache,target=/opt/archivebox/lib/cache,sharing=locked,mode=1777
|
||||
&& echo -e "\nARCHIVEBOX_USER=$ARCHIVEBOX_USER ARCHIVEBOX_UID=$(id -u "$ARCHIVEBOX_USER") ARCHIVEBOX_GID=$(id -g "$ARCHIVEBOX_USER")" | tee -a /VERSION.txt \
|
||||
&& echo -e "TMP_DIR=$TMP_DIR\nABXPKG_LIB_DIR=$ABXPKG_LIB_DIR\nPLAYWRIGHT_BROWSERS_PATH=$PLAYWRIGHT_BROWSERS_PATH\nMACHINE_ID=$(cat /etc/machine-id)\n" | tee -a /VERSION.txt
|
||||
|
||||
# The optional AI service belongs to ArchiveBox, not the downloader base image.
|
||||
# Always bundle its executable while leaving OPENCODE_ENABLED opt-in.
|
||||
RUN --mount=type=cache,target=/var/tmp/abxpkg-cache,sharing=locked,mode=1777,id=archivebox-opencode-$TARGETARCH \
|
||||
env ABXPKG_TMP_CACHE_DIR=/var/tmp/abxpkg-cache XDG_CACHE_HOME=/var/tmp/abxpkg-cache \
|
||||
setpriv --reuid="$ARCHIVEBOX_USER" --regid="$ARCHIVEBOX_USER" --init-groups abx-dl install opencode \
|
||||
# pnpm includes musl variants that Debian's glibc runtime cannot use.
|
||||
&& find "$ABXPKG_LIB_DIR/pnpm/packages/opencode/node_modules" -type l -name 'opencode-linux-*-musl' -delete \
|
||||
&& find "$ABXPKG_LIB_DIR/pnpm/packages/opencode/node_modules/.pnpm" -maxdepth 1 -type d -name 'opencode-linux-*-musl@*' -exec rm -rf {} +
|
||||
RUN --network=none setpriv --reuid="$ARCHIVEBOX_USER" --regid="$ARCHIVEBOX_USER" --init-groups \
|
||||
bash -c '"$ABXPKG_LIB_DIR/pnpm/packages/opencode/node_modules/.bin/opencode" --version && abx-dl install opencode'
|
||||
|
||||
WORKDIR "$DATA_DIR"
|
||||
RUN echo "[+] Initializing image collection..." \
|
||||
&& find "$DATA_DIR" -mindepth 1 -maxdepth 1 -exec rm -rf {} + \
|
||||
|
||||
@@ -151,6 +151,17 @@ curl -fsSL 'https://get.archivebox.io' | bash
|
||||
|
||||
#### ✳️ Easy Setup
|
||||
|
||||
<details>
|
||||
<summary><b><img src="https://archivebox.github.io/ios-archivebox/docs/icons/apple.svg" alt="Apple" height="28px" align="top"/> <code>ArchiveBox Server.app</code></b> (macOS)</summary>
|
||||
<br/>
|
||||
<ol>
|
||||
<li><a href="https://github.com/ArchiveBox/ios-archivebox/releases">Download <code>ArchiveBox Server.app</code></a>, move it to Applications, and open it.</li>
|
||||
<li>Set up an admin account and generate an API Key.</li>
|
||||
<li>Use the Web UI or <a href="https://archivebox.github.io/ios-archivebox/"><code>ArchiveBox.app</code></a>, and optionally connect REST API clients, the <a href="https://archivebox.github.io/ios-archivebox/">mobile app</a>, the <a href="https://archivebox.github.io/archivebox-browser-extension/">browser extension</a>, and other integrations to your server using your API Key.</li>
|
||||
</ol>
|
||||
<br/>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b><img src="https://user-images.githubusercontent.com/511499/117447182-29758200-af0b-11eb-97bd-58723fee62ab.png" alt="Docker" height="28px" align="top"/> <code>docker-compose</code></b> (macOS/Linux) <b>👈 recommended</b> <i>(click to expand)</i></summary>
|
||||
<br/>
|
||||
@@ -561,6 +572,20 @@ docker compose run --rm archivebox config --set PERMISSIONS=public
|
||||
</code></pre>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><b><img src="https://archivebox.github.io/ios-archivebox/docs/icons/apple.svg" alt="Apple" height="22px" align="top"/> <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@v2.17.0/icons/windows11/windows11-original.svg" alt="Windows" height="22px" align="top"/> 🐧 Desktop / Mobile / Extension Usage</b></summary>
|
||||
<br/>
|
||||
|
||||
- 📱 [<code>ArchiveBox</code> iOS Mobile App](https://archivebox.github.io/ios-archivebox/)
|
||||
- 🖥️ [<code>ArchiveBox.app</code> macOS Desktop App](https://archivebox.github.io/ios-archivebox/)
|
||||
- 🧩 [ArchiveBox Browser Extension](https://archivebox.github.io/archivebox-browser-extension/)
|
||||
- 💻 [Linux/Windows Desktop App (Requires Docker Desktop)](https://github.com/ArchiveBox/electron-archivebox)
|
||||
|
||||
<br/>
|
||||
</details>
|
||||
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
@@ -614,7 +639,10 @@ docker run -it -v $PWD:/data archivebox/archivebox:dev add --depth=1 'https://ex
|
||||
|
||||
|
||||
- <img src="https://github.com/ArchiveBox/ArchiveBox/assets/511499/ff20d251-5347-4b85-ae9b-83037d0ac01e" height="28px"/> <b>From the official <a href="https://github.com/ArchiveBox/archivebox-extension">ArchiveBox Browser Extension</a></b>
|
||||
<i>Provides realtime archiving of browsing history or selected pages from Chrome/Chromium/Firefox browsers.</i>
|
||||
<i>Provides realtime archiving of browsing history or selected pages from Chrome/Chromium/Firefox/Safari browsers.</i>
|
||||
|
||||
- <img src="https://archivebox.github.io/ios-archivebox/App/AppIcon.icon/Assets/ArchiveBox.png" alt="ArchiveBox app icon" height="28px"/> <b>From the official <a href="https://archivebox.github.io/ios-archivebox/">ArchiveBox macOS Desktop App or iOS Mobile App</a></b><br/>
|
||||
<i>Save directly from the Share menu or Siri/Shortcuts to your server.</i>
|
||||
|
||||
- <img src="https://github.com/ArchiveBox/ArchiveBox/assets/511499/64078483-21d7-4eb1-aa6e-9ad55afe45b8" height="22px"/> From manual imports of URLs from RSS, JSON, CSV, TXT, SQL, HTML, Markdown, etc. files
|
||||
<i>ArchiveBox supports injesting URLs in [any text-based format](https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#Import-a-list-of-URLs-from-a-text-file).</i>
|
||||
|
||||
@@ -109,6 +109,7 @@ def create_personas(
|
||||
profile: str | None = None,
|
||||
source: str | None = None,
|
||||
browser_binary: str | None = None,
|
||||
permissions: str | None = None,
|
||||
) -> int:
|
||||
"""
|
||||
Create Personas from names.
|
||||
@@ -162,7 +163,10 @@ def create_personas(
|
||||
rprint(f'[red]Invalid persona name "{name}": {error_msg}[/red]', file=sys.stderr)
|
||||
continue
|
||||
|
||||
persona, created = Persona.objects.get_or_create(name=name)
|
||||
persona, created = Persona.objects.get_or_create(
|
||||
name=name,
|
||||
defaults={"config": {"PERMISSIONS": permissions}} if permissions else {},
|
||||
)
|
||||
|
||||
if created:
|
||||
persona.ensure_dirs()
|
||||
@@ -441,7 +445,11 @@ def main():
|
||||
|
||||
@main.command("create")
|
||||
@click.argument("names", nargs=-1)
|
||||
@click.option("--import", "import_from", help="Import from chrome, chromium, brave, edge, a persona directory, or a live CDP URL")
|
||||
@click.option(
|
||||
"--import",
|
||||
"import_from",
|
||||
help="Import from chrome, chrome-beta, chromium, brave, edge, a persona directory, or a live CDP URL",
|
||||
)
|
||||
@click.option("--source", help="Source browser user-data directory or exact profile path (including Docker mounts)")
|
||||
@click.option(
|
||||
"--browser-binary",
|
||||
@@ -449,9 +457,30 @@ def main():
|
||||
help="Source Chromium browser executable; required for other Chromium-based browsers",
|
||||
)
|
||||
@click.option("--profile", help="Profile directory name under the user data dir (e.g. Default, Profile 1)")
|
||||
def create_cmd(names: tuple, import_from: str | None, profile: str | None, source: str | None, browser_binary: str | None):
|
||||
@click.option(
|
||||
"--permissions",
|
||||
type=click.Choice(["public", "unlisted", "private"]),
|
||||
help="Visibility for a newly created persona (existing personas are unchanged)",
|
||||
)
|
||||
def create_cmd(
|
||||
names: tuple,
|
||||
import_from: str | None,
|
||||
profile: str | None,
|
||||
source: str | None,
|
||||
browser_binary: str | None,
|
||||
permissions: str | None,
|
||||
):
|
||||
"""Create Personas, optionally importing from a browser profile."""
|
||||
sys.exit(create_personas(names, import_from=import_from, profile=profile, source=source, browser_binary=browser_binary))
|
||||
sys.exit(
|
||||
create_personas(
|
||||
names,
|
||||
import_from=import_from,
|
||||
profile=profile,
|
||||
source=source,
|
||||
browser_binary=browser_binary,
|
||||
permissions=permissions,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@main.command("list")
|
||||
|
||||
@@ -460,9 +460,9 @@ def system_warnings_banner(context):
|
||||
"""Render the top-of-page warning banner for one of the conditions below,
|
||||
in priority order (highest first):
|
||||
|
||||
1. ``mode="unconfigured"``— ``BASE_URL`` is empty. Security/correctness
|
||||
issue: until it's pinned, generated URLs can echo any Host the client
|
||||
sends, and admin/web/api routing has no canonical anchor.
|
||||
1. ``mode="unconfigured"``— ``BASE_URL`` is empty and the operator has
|
||||
not selected safe single-domain routing. That mode intentionally uses
|
||||
each device's connection address, including LAN and Tailscale IPs.
|
||||
2. ``mode="base_url_mismatch"`` — the browser reached ArchiveBox through
|
||||
an origin that differs from the configured canonical ``BASE_URL``.
|
||||
3. ``mode="unsafe"`` — ``SERVER_SECURITY_MODE`` explicitly enables
|
||||
@@ -489,7 +489,7 @@ def system_warnings_banner(context):
|
||||
|
||||
config = get_config(resolve_plugins=False)
|
||||
|
||||
if not config.BASE_URL:
|
||||
if not config.BASE_URL and config.SERVER_SECURITY_MODE != "safe-onedomain-nojsreplay":
|
||||
return get_setup_wizard_context(context.get("request"), config)
|
||||
mismatch = get_base_url_mismatch_context(context.get("request"), config)
|
||||
if mismatch and not _is_web_subdomain_alias(mismatch["browser_url"], mismatch["configured_base_url"]):
|
||||
|
||||
@@ -27,7 +27,7 @@ class PersonaAdmin(ConfigEditorMixin, BaseModelAdmin):
|
||||
"Persona",
|
||||
{
|
||||
"fields": ("name", "created_by", "permissions"),
|
||||
"classes": ("card", "persona-card-primary"),
|
||||
"classes": ("card", "wide", "persona-card-primary"),
|
||||
},
|
||||
),
|
||||
(
|
||||
@@ -42,7 +42,7 @@ class PersonaAdmin(ConfigEditorMixin, BaseModelAdmin):
|
||||
"import_extract_cookies",
|
||||
"import_capture_storage",
|
||||
),
|
||||
"classes": ("card", "wide"),
|
||||
"classes": ("card", "wide", "persona-card-import"),
|
||||
},
|
||||
),
|
||||
(
|
||||
|
||||
@@ -55,7 +55,7 @@ class PersonaAdminForm(PluginConfigFormMixin, forms.ModelForm):
|
||||
label="Autodiscovered profiles",
|
||||
widget=forms.RadioSelect,
|
||||
choices=(),
|
||||
help_text="Detected from local Chrome, Chromium, Brave, and Edge profile roots.",
|
||||
help_text="Detected from local Chrome, Chrome Beta, Chromium, Brave, and Edge profile roots.",
|
||||
)
|
||||
import_source = forms.CharField(
|
||||
required=False,
|
||||
|
||||
@@ -18,6 +18,7 @@ import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from dataclasses import dataclass, field
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
from urllib.parse import urlparse
|
||||
@@ -31,6 +32,7 @@ if TYPE_CHECKING:
|
||||
|
||||
BROWSER_LABELS = {
|
||||
"chrome": "Google Chrome",
|
||||
"chrome-beta": "Google Chrome Beta",
|
||||
"chromium": "Chromium",
|
||||
"brave": "Brave",
|
||||
"edge": "Microsoft Edge",
|
||||
@@ -216,24 +218,29 @@ class PersonaImportResult:
|
||||
return self.profile_copied or self.cookies_imported or self.storage_captured or self.user_agent_imported
|
||||
|
||||
|
||||
def get_chrome_user_data_dir() -> Path | None:
|
||||
def get_chrome_user_data_dir(*, beta: bool = False) -> Path | None:
|
||||
"""Get the default Chrome user data directory for the current platform."""
|
||||
system = platform.system()
|
||||
home = Path.home()
|
||||
app_name = "Chrome Beta" if beta else "Chrome"
|
||||
|
||||
if system == "Darwin":
|
||||
candidates = [
|
||||
home / "Library" / "Application Support" / "Google" / "Chrome",
|
||||
home / "Library" / "Application Support" / "Google" / app_name,
|
||||
]
|
||||
elif system == "Linux":
|
||||
candidates = [
|
||||
home / ".config" / "google-chrome",
|
||||
home / ".config" / "chrome",
|
||||
]
|
||||
candidates = (
|
||||
[home / ".config" / "google-chrome-beta"]
|
||||
if beta
|
||||
else [
|
||||
home / ".config" / "google-chrome",
|
||||
home / ".config" / "chrome",
|
||||
]
|
||||
)
|
||||
elif system == "Windows":
|
||||
local_app_data = Path(os.environ.get("LOCALAPPDATA", home / "AppData" / "Local"))
|
||||
candidates = [
|
||||
local_app_data / "Google" / "Chrome" / "User Data",
|
||||
local_app_data / "Google" / app_name / "User Data",
|
||||
]
|
||||
else:
|
||||
candidates = []
|
||||
@@ -320,6 +327,7 @@ def get_edge_user_data_dir() -> Path | None:
|
||||
|
||||
BROWSER_PROFILE_FINDERS = {
|
||||
"chrome": get_chrome_user_data_dir,
|
||||
"chrome-beta": partial(get_chrome_user_data_dir, beta=True),
|
||||
"chromium": get_chromium_user_data_dir,
|
||||
"brave": get_brave_user_data_dir,
|
||||
"edge": get_edge_user_data_dir,
|
||||
@@ -354,6 +362,12 @@ def validate_persona_name(name: str) -> tuple[bool, str]:
|
||||
|
||||
|
||||
def discover_local_browser_profiles() -> list[PersonaImportSource]:
|
||||
# The macOS companion exports with the host Keychain before creating personas.
|
||||
# Raw mounts alone cannot decrypt macOS cookies in the Linux container.
|
||||
if host_profiles := os.environ.get("ARCHIVEBOX_HOST_BROWSER_PROFILES"):
|
||||
host_templates = discover_persona_template_profiles(Path(host_profiles))
|
||||
host_names = {source.source_name for source in host_templates}
|
||||
return host_templates + [source for source in discover_persona_template_profiles() if source.source_name not in host_names]
|
||||
discovered: list[PersonaImportSource] = []
|
||||
|
||||
for browser, finder in BROWSER_PROFILE_FINDERS.items():
|
||||
@@ -430,6 +444,11 @@ def discover_persona_template_profiles(personas_dir: Path | None = None) -> list
|
||||
|
||||
def resolve_browser_import_source(browser: str, profile_dir: str | None = None) -> PersonaImportSource:
|
||||
browser = browser.lower().strip()
|
||||
if host_profiles := os.environ.get("ARCHIVEBOX_HOST_BROWSER_PROFILES"):
|
||||
label = BROWSER_LABELS.get(browser, browser)
|
||||
exported = Path(host_profiles) / f"{label} - {profile_dir or 'Default'}"
|
||||
if exported.is_dir():
|
||||
return resolve_custom_import_source(str(exported))
|
||||
if browser not in BROWSER_PROFILE_FINDERS:
|
||||
supported = ", ".join(BROWSER_PROFILE_FINDERS)
|
||||
raise ValueError(f"Unknown browser: {browser}. Supported browsers: {supported}")
|
||||
@@ -547,6 +566,7 @@ def resolve_source_browser_binary(source: PersonaImportSource) -> str:
|
||||
return str(Path(source.browser_binary).expanduser().resolve())
|
||||
names = {
|
||||
"chrome": ("Google Chrome", "google-chrome"),
|
||||
"chrome-beta": ("Google Chrome Beta", "google-chrome-beta"),
|
||||
"chromium": ("Chromium", "chromium"),
|
||||
"brave": ("Brave Browser", "brave-browser"),
|
||||
"edge": ("Microsoft Edge", "microsoft-edge"),
|
||||
@@ -561,6 +581,7 @@ def resolve_source_browser_binary(source: PersonaImportSource) -> str:
|
||||
elif platform.system() == "Windows":
|
||||
relative = {
|
||||
"chrome": "Google/Chrome/Application/chrome.exe",
|
||||
"chrome-beta": "Google/Chrome Beta/Application/chrome.exe",
|
||||
"edge": "Microsoft/Edge/Application/msedge.exe",
|
||||
"brave": "BraveSoftware/Brave-Browser/Application/brave.exe",
|
||||
"chromium": "Chromium/Application/chrome.exe",
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
border-bottom: 1px dashed #64748b;
|
||||
}
|
||||
|
||||
.field-import_mode ul,
|
||||
.field-import_discovered_profile ul {
|
||||
.abx-import-mode,
|
||||
.abx-profile-picker {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
@@ -47,20 +47,26 @@
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.field-import_mode ul {
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
.abx-import-mode {
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
|
||||
}
|
||||
|
||||
.field-import_discovered_profile ul {
|
||||
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||
max-height: 460px;
|
||||
overflow: auto;
|
||||
padding-right: 4px;
|
||||
.abx-profile-picker {
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
|
||||
}
|
||||
|
||||
.field-import_mode li,
|
||||
.field-import_discovered_profile li {
|
||||
.abx-import-mode > div,
|
||||
.abx-profile-picker > div {
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Import rows grow with their contents instead of sharing a fixed flex
|
||||
height. Avoid overflow-x:hidden turning overflow-y:visible into auto. */
|
||||
#content-main #persona_form .persona-card-import > .form-row,
|
||||
#content-main #persona_form .persona-card-import fieldset > div {
|
||||
flex: none;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.field-import_mode label,
|
||||
@@ -68,7 +74,6 @@
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
min-height: 100%;
|
||||
padding: 14px 16px;
|
||||
border-radius: 14px;
|
||||
border: 1px solid #dbe4ee;
|
||||
@@ -167,9 +172,14 @@
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
body.model-persona.change-form #content-main form fieldset.persona-card-primary {
|
||||
flex: 1 1 520px !important;
|
||||
max-width: calc(66.66% - 10px) !important;
|
||||
#content-main #persona_form .field-name .flex-container {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
#persona_form .field-name input {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body.model-persona.change-form #content-main form fieldset.persona-card-timestamps {
|
||||
@@ -257,6 +267,11 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
or by pasting in a CDP url from
|
||||
<code class="persona-import-copy" data-copy-text="chrome://inspect#remote-debugging" title="Copy chrome://inspect#remote-debugging">chrome://inspect#remote-debugging</code> (e.g. <code>http://127.0.0.1:9222</code>).
|
||||
</p>
|
||||
<p>
|
||||
You can also import cookies into this persona from another browser using the
|
||||
<a href="https://archivebox.github.io/archivebox-browser-extension/" target="_blank" rel="noopener noreferrer">ArchiveBox browser extension</a>.
|
||||
Create the persona here, then select it in the extension's settings to sync cookies from that browser.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
{{ block.super }}
|
||||
@@ -264,9 +279,9 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
{% block after_field_sets %}
|
||||
{{ block.super }}
|
||||
<section id="plugin-config" class="module aligned persona-plugin-config">
|
||||
<fieldset id="plugin-config" class="module aligned wide persona-plugin-config">
|
||||
<h2>Plugin Config</h2>
|
||||
<p>These typed controls update the same Persona config JSON shown above. Shared config keys stay synced across plugin sections.</p>
|
||||
{% include "plugins/plugin_config_grid.html" with plugin_groups=adminform.form.plugin_groups %}
|
||||
</section>
|
||||
</fieldset>
|
||||
{% endblock %}
|
||||
@@ -287,7 +287,8 @@
|
||||
<code>daily</code> - Run once per day<br/>
|
||||
<code>weekly</code> - Run once per week<br/>
|
||||
<code>0 */6 * * *</code> - Every 6 hours (cron format)<br/>
|
||||
<code>0 0 * * 0</code> - Every Sunday at midnight (cron format)
|
||||
<code>0 0 * * 0</code> - Every Sunday at midnight (cron format)<br/>
|
||||
<a href="https://crontab.guru/" target="_blank" rel="noopener">Cron Format Helper</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -16,6 +16,23 @@ def test_persona_help_runs_successfully(tmp_path):
|
||||
assert "list" in result.stdout
|
||||
|
||||
|
||||
def test_persona_create_permissions_preserves_existing_persona(initialized_archive):
|
||||
from archivebox.tests.conftest import run_python_cwd
|
||||
|
||||
result = run_archivebox_cmd(["persona", "create", "--permissions=private", "host-profile"], cwd=initialized_archive)
|
||||
assert result.returncode == 0, result.stderr
|
||||
existing = run_archivebox_cmd(["persona", "create", "--permissions=public", "host-profile"], cwd=initialized_archive)
|
||||
assert existing.returncode == 0, existing.stderr
|
||||
stdout, stderr, returncode = run_python_cwd(
|
||||
"import os; os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'archivebox.core.settings'); "
|
||||
"import django; django.setup(); from archivebox.personas.models import Persona; "
|
||||
"p = Persona.objects.get(name='host-profile'); assert p.permissions == 'private'; print('private')",
|
||||
cwd=initialized_archive,
|
||||
)
|
||||
assert returncode == 0, stderr
|
||||
assert "private" in stdout
|
||||
|
||||
|
||||
def test_persona_import_missing_source_is_actionable_and_does_not_create(initialized_archive, tmp_path):
|
||||
result = run_archivebox_cmd(
|
||||
["persona", "create", "--import=brave", "--source", str(tmp_path / "missing"), "broken"],
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import socket
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from concurrent.futures import TimeoutError as FutureTimeoutError
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from urllib.parse import parse_qs, quote, urlsplit
|
||||
@@ -359,6 +361,45 @@ def test_opencode_proxy_preserves_protocol_headers(admin_client, live_opencode):
|
||||
assert deleted.status_code == 200, deleted.content
|
||||
|
||||
|
||||
def test_opencode_oauth_callback_waits_for_user_and_preserves_cancellation(live_opencode):
|
||||
from abx_plugins.plugins.opencode import runtime
|
||||
|
||||
settings = {**live_opencode.settings, "timeout": 1}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
status, _, body = runtime.proxy(settings, "POST", "provider/openai/oauth/authorize", (), headers, b'{"method":0}')
|
||||
assert status == 200
|
||||
authorization = json.loads(body)
|
||||
assert urlsplit(authorization["url"]).hostname == "auth.openai.com"
|
||||
redirect = parse_qs(urlsplit(authorization["url"]).query)["redirect_uri"][0]
|
||||
callback_origin = urlsplit(redirect)
|
||||
assert callback_origin.hostname == "localhost"
|
||||
|
||||
with ThreadPoolExecutor(max_workers=1) as executor:
|
||||
callback = executor.submit(runtime.proxy, settings, "POST", "provider/openai/oauth/callback", (), headers, b'{"method":0}')
|
||||
try:
|
||||
# A real pending authorization must outlive the ordinary API read
|
||||
# timeout. No tokens or substituted provider responses are used.
|
||||
with pytest.raises(FutureTimeoutError):
|
||||
callback.result(timeout=2)
|
||||
finally:
|
||||
cancelled = requests.get(f"{callback_origin.scheme}://{callback_origin.netloc}/cancel", timeout=5)
|
||||
assert cancelled.status_code == 200
|
||||
assert cancelled.text == "Login cancelled"
|
||||
status, response_headers, body = callback.result(timeout=5)
|
||||
assert status == 500
|
||||
assert response_headers["Content-Type"].startswith("application/json")
|
||||
error = json.loads(body)
|
||||
assert error["name"] == "UnknownError"
|
||||
assert error["data"]["ref"].startswith("err_")
|
||||
runtime._stop_owned_process()
|
||||
# The pnpm launcher can exit before its server child. Stopping the owned
|
||||
# process must release both listeners so another collection can authorize.
|
||||
with pytest.raises(requests.ConnectionError):
|
||||
requests.get(settings["origin"] + "/global/health", timeout=2)
|
||||
with pytest.raises(requests.ConnectionError):
|
||||
requests.get(f"{callback_origin.scheme}://{callback_origin.netloc}/cancel", timeout=2)
|
||||
|
||||
|
||||
def test_opencode_static_assets_cache_privately_and_revalidate(admin_client, live_opencode):
|
||||
headers = {"HTTP_HOST": ADMIN_TEST_HOST, "HTTP_SEC_FETCH_SITE": "same-origin"}
|
||||
page = admin_client.get("/admin/agent/opencode/", **headers)
|
||||
@@ -392,9 +433,26 @@ def test_opencode_proxy_sse_response_is_unbuffered(admin_client, live_opencode):
|
||||
assert response.headers["Cache-Control"] == "no-store"
|
||||
|
||||
|
||||
def test_opencode_proxy_sse_delivers_first_event_immediately(admin_client, live_opencode):
|
||||
@pytest.mark.parametrize("path", ["event", "global/event"])
|
||||
def test_opencode_proxy_sse_delivers_first_event_immediately(admin_client, live_opencode, path):
|
||||
from abx_plugins.plugins.opencode import runtime
|
||||
|
||||
# The real /event endpoint emits heartbeats indefinitely. A bounded
|
||||
# upstream read exposes accidental buffering without hanging the test.
|
||||
status, headers, body = runtime.proxy(
|
||||
{**live_opencode.settings, "timeout": 1},
|
||||
"GET",
|
||||
path,
|
||||
(),
|
||||
{},
|
||||
b"",
|
||||
)
|
||||
assert status == 200
|
||||
assert not isinstance(body, bytes)
|
||||
assert headers["Content-Type"] == "text/event-stream"
|
||||
asyncio.run(body.aclose())
|
||||
response = admin_client.get(
|
||||
"/admin/agent/opencode/global/event",
|
||||
f"/admin/agent/opencode/{path}",
|
||||
HTTP_HOST=ADMIN_TEST_HOST,
|
||||
HTTP_SEC_FETCH_SITE="same-origin",
|
||||
)
|
||||
|
||||
@@ -20,8 +20,21 @@ from .test_server_security_browser import browser_runtime as browser_runtime
|
||||
pytestmark = pytest.mark.django_db(transaction=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"agent_server",
|
||||
[
|
||||
("safe-onedomain-nojsreplay", False),
|
||||
("safe-subdomains-fullreplay", True),
|
||||
("danger-onedomain-fullreplay", False),
|
||||
("auto", False),
|
||||
("auto", True),
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_agent_navigation_stays_inside_mount(agent_server, browser_runtime):
|
||||
server_url, _, _ = agent_server
|
||||
server_url, data_dir, _ = agent_server
|
||||
filename = "proxy acceptance #é.txt"
|
||||
(data_dir / filename).write_text("Proxy file read: café", encoding="utf-8")
|
||||
script = r"""
|
||||
const assert = require('node:assert/strict');
|
||||
const puppeteer = require('puppeteer');
|
||||
@@ -31,6 +44,14 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
args: ['--no-sandbox', '--disable-frame-rate-limit']});
|
||||
try {
|
||||
const page = await browser.newPage();
|
||||
const escapedRequests = [];
|
||||
page.on('request', request => {
|
||||
const url = new URL(request.url());
|
||||
if (request.frame()?.parentFrame() && url.origin === config.url &&
|
||||
!url.pathname.startsWith('/admin/agent/opencode/')) {
|
||||
escapedRequests.push(request.method() + ' ' + url.pathname);
|
||||
}
|
||||
});
|
||||
await page.setViewport({width: 1440, height: 900});
|
||||
await page.goto(config.url + '/admin/login/', {waitUntil: 'domcontentloaded'});
|
||||
await page.locator('#login-form input[name="username"]').fill('agent-browser-test');
|
||||
@@ -44,7 +65,9 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
const links = await frame.$$eval('a[href*="/session"]', nodes => nodes.map(node => node.getAttribute('href')));
|
||||
assert.ok(links.length, 'OpenCode must expose session navigation');
|
||||
for (const href of links) assert.ok(href.startsWith('/admin/agent/opencode/'), href);
|
||||
const initialSessionUrl = frame.url();
|
||||
await frame.locator('::-p-aria(New session[role="button"])').click();
|
||||
await frame.waitForFunction(previous => location.href !== previous, {}, initialSessionUrl);
|
||||
await frame.waitForSelector('[contenteditable="true"]');
|
||||
let navigation;
|
||||
for (const link of await frame.$$('a[href*="/session"]')) {
|
||||
@@ -61,6 +84,101 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
assert.equal((await frame.goto(sessionUrl, {waitUntil: 'domcontentloaded'})).status(), 200);
|
||||
await frame.waitForSelector('[contenteditable="true"]');
|
||||
assert.ok(!(await frame.$eval('body', node => node.innerText)).includes('Something went wrong'));
|
||||
// Real JSON methods, encoded file paths, and both SSE subscriptions must
|
||||
// work on the admin origin in every routing mode, without installing or
|
||||
// authenticating a paid model provider during the test.
|
||||
const requests = await frame.evaluate(async filename => {
|
||||
const base = location.origin + '/admin/agent/opencode';
|
||||
const json = async (path, method = 'GET', body) => {
|
||||
const response = await fetch(base + path, {
|
||||
method, headers: {'Content-Type': 'application/json'},
|
||||
...(body === undefined ? {} : {body: JSON.stringify(body)}),
|
||||
});
|
||||
if (!response.ok) throw new Error(method + ' ' + path + ': ' + response.status);
|
||||
if (!response.headers.get('Content-Type')?.includes('application/json')) {
|
||||
throw new Error('Non-JSON response: ' + path);
|
||||
}
|
||||
return response.json();
|
||||
};
|
||||
const providers = await json('/provider');
|
||||
const auth = await json('/provider/auth');
|
||||
const file = await json('/file/content?path=' + encodeURIComponent(filename));
|
||||
const session = await json('/session', 'POST', {title: 'Proxy request verification'});
|
||||
let renamed;
|
||||
try {
|
||||
renamed = await json('/session/' + session.id, 'PATCH', {title: 'Proxy: café & # symbols'});
|
||||
const readback = await json('/session/' + session.id);
|
||||
if (readback.title !== renamed.title) throw new Error('Session mutation was not persisted');
|
||||
} finally { await json('/session/' + session.id, 'DELETE'); }
|
||||
const streams = [];
|
||||
for (const path of ['/event', '/global/event']) {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 5000);
|
||||
try {
|
||||
const response = await fetch(base + path, {signal: controller.signal});
|
||||
if (!response.ok || !response.headers.get('Content-Type')?.includes('text/event-stream')) {
|
||||
throw new Error('Invalid event stream: ' + path);
|
||||
}
|
||||
const reader = response.body.getReader();
|
||||
const first = await reader.read();
|
||||
streams.push(new TextDecoder().decode(first.value));
|
||||
await reader.cancel();
|
||||
} finally { clearTimeout(timeout); controller.abort(); }
|
||||
}
|
||||
return {providers: providers.all.map(provider => provider.id), auth, file, renamed, streams};
|
||||
}, config.filename);
|
||||
for (const provider of ['openai', 'anthropic']) assert.ok(requests.providers.includes(provider), provider);
|
||||
assert.ok(requests.auth.openai.some(method => method.type === 'oauth'));
|
||||
assert.equal(requests.file.content, 'Proxy file read: café');
|
||||
assert.equal(requests.renamed.title, 'Proxy: café & # symbols');
|
||||
for (const event of requests.streams) assert.ok(event.includes('server.connected'), event);
|
||||
for (const provider of ['OpenAI', 'Anthropic']) {
|
||||
await frame.locator('[data-action="prompt-model"]').click();
|
||||
await frame.locator('::-p-aria(' + provider + '[role="button"])').click();
|
||||
if (provider === 'OpenAI') {
|
||||
await frame.waitForSelector('::-p-aria(ChatGPT Pro/Plus Headless[role="button"])');
|
||||
await frame.waitForSelector('::-p-aria(ChatGPT Pro/Plus Browser[role="button"])');
|
||||
await frame.locator('::-p-aria(API key Browser[role="button"])').click();
|
||||
}
|
||||
const input = await frame.waitForSelector('::-p-aria(' + provider + ' API key[role="textbox"])');
|
||||
assert.equal(await input.evaluate(node => node.value), '');
|
||||
await frame.waitForSelector('::-p-aria(Continue[role="button"])');
|
||||
await frame.locator('::-p-aria(Close[role="button"])').click();
|
||||
}
|
||||
// Submit a real shell command from a fresh draft. This exercises draft
|
||||
// promotion and the shell API without needing a paid model or API key.
|
||||
await frame.locator('::-p-aria(New session[role="button"])').click();
|
||||
await frame.waitForFunction(() => location.pathname.endsWith('/new-session'));
|
||||
await (await frame.waitForSelector('[contenteditable="true"]')).focus();
|
||||
const modifier = await page.evaluate(() => navigator.platform.includes('Mac') ? 'Meta' : 'Control');
|
||||
await page.keyboard.down(modifier);
|
||||
await page.keyboard.down('Shift');
|
||||
await page.keyboard.press('x');
|
||||
await page.keyboard.up('Shift');
|
||||
await page.keyboard.up(modifier);
|
||||
await page.keyboard.type('printf ABX_DRAFT_SHELL_OK');
|
||||
await frame.locator('::-p-aria(Send[role="button"])').click();
|
||||
await frame.waitForFunction(() => /\/session\/ses_/.test(location.pathname));
|
||||
assert.ok(new URL(frame.url()).pathname.startsWith('/admin/agent/opencode/'), frame.url());
|
||||
await frame.waitForFunction(async () => {
|
||||
const sessionID = location.pathname.match(/\/session\/(ses_[^/]+)/)[1];
|
||||
const response = await fetch('/admin/agent/opencode/session/' + sessionID + '/message');
|
||||
if (!response.ok) throw new Error('Shell message readback: ' + response.status);
|
||||
const messages = await response.json();
|
||||
return messages.some(message => message.parts.some(part =>
|
||||
part.type === 'tool' && part.state.status === 'completed' &&
|
||||
part.state.output.trim() === 'ABX_DRAFT_SHELL_OK'));
|
||||
}, {polling: 250});
|
||||
// The tabbed layout's own route parser must recognize mounted sessions.
|
||||
// Otherwise Home incorrectly appears selected and clicking it does nothing.
|
||||
const shellSessionUrl = frame.url();
|
||||
const home = await frame.waitForSelector('[aria-label="Home"]');
|
||||
assert.equal(await home.evaluate(node => node.getAttribute('aria-pressed')), 'false');
|
||||
await home.click();
|
||||
await frame.waitForFunction(() => location.pathname.replace(/\/+$/, '') === '/admin/agent/opencode');
|
||||
assert.equal(await home.evaluate(node => node.getAttribute('aria-pressed')), 'true');
|
||||
await home.click();
|
||||
await frame.waitForFunction(expected => location.href === expected, {}, shellSessionUrl);
|
||||
// Exercise the actual public PTY API and native browser WebSocket. No
|
||||
// intercepted traffic or replacement server: this runs a real shell.
|
||||
const terminal = await frame.evaluate(async () => {
|
||||
@@ -97,6 +215,7 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
} finally { await fetch(base + '/pty/' + pty.id, {method: 'DELETE'}); }
|
||||
});
|
||||
assert.ok(terminal.includes('ABX_TERMINAL_OK'), terminal);
|
||||
assert.deepEqual(escapedRequests, [], 'OpenCode requests must stay inside its proxy mount');
|
||||
assert.equal((await page.goto(config.url + '/add/', {waitUntil: 'domcontentloaded'})).status(), 200);
|
||||
console.log('AGENT_NAVIGATION_OK');
|
||||
} finally { await browser.close(); }
|
||||
@@ -104,7 +223,7 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
"""
|
||||
result = subprocess.run(
|
||||
[str(browser_runtime["node_binary"]), "-e", script],
|
||||
input=json.dumps({"chrome": str(browser_runtime["chrome_binary"]), "url": server_url}),
|
||||
input=json.dumps({"chrome": str(browser_runtime["chrome_binary"]), "url": server_url, "filename": filename}),
|
||||
env={**os.environ, "NODE_PATH": browser_runtime["node_path"]},
|
||||
text=True,
|
||||
capture_output=True,
|
||||
@@ -115,14 +234,16 @@ const config = JSON.parse(require('node:fs').readFileSync(0, 'utf8'));
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def agent_server(installed_opencode, browser_runtime):
|
||||
def agent_server(installed_opencode, browser_runtime, request):
|
||||
port = get_free_port()
|
||||
url = f"http://localhost:{port}"
|
||||
mode, subdomains = getattr(request, "param", ("safe-onedomain-nojsreplay", False))
|
||||
base_url = f"http://archivebox.localhost:{port}" if subdomains else f"http://localhost:{port}"
|
||||
url = f"http://admin.archivebox.localhost:{port}" if subdomains else base_url
|
||||
config = installed_opencode.config
|
||||
_set_archivebox_config(
|
||||
config.data_dir,
|
||||
f"BASE_URL={url}",
|
||||
"SERVER_SECURITY_MODE=safe-onedomain-nojsreplay",
|
||||
f"BASE_URL={base_url}",
|
||||
f"SERVER_SECURITY_MODE={mode}",
|
||||
)
|
||||
user = run_archivebox_cmd(
|
||||
[
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
"""Exercise automatic server addressing through real HTTP login pages."""
|
||||
|
||||
import re
|
||||
|
||||
import requests
|
||||
|
||||
from .conftest import cli_env, get_free_port, run_archivebox_cmd, start_archivebox_server, stop_archivebox_process
|
||||
|
||||
|
||||
def test_safe_single_domain_login_does_not_require_base_url(tmp_path):
|
||||
port = get_free_port()
|
||||
env = cli_env(
|
||||
disable_extractors=True,
|
||||
BASE_URL="",
|
||||
SERVER_SECURITY_MODE="safe-onedomain-nojsreplay",
|
||||
ADMIN_USERNAME="automatic-url-test",
|
||||
ADMIN_PASSWORD="Automatic-url-test-password-93!",
|
||||
ALLOWED_HOSTS="*",
|
||||
)
|
||||
result = run_archivebox_cmd(["init", "--quick"], cwd=tmp_path, env=env, timeout=60)
|
||||
assert result.returncode == 0, result.stderr or result.stdout
|
||||
process = start_archivebox_server(tmp_path, port=port, env=env, daemonize=False, log_name="server.log")
|
||||
try:
|
||||
for hostname in ("localhost", "archivebox.localhost", "admin.archivebox.localhost", "192.168.1.20", "100.100.10.20"):
|
||||
session = requests.Session()
|
||||
response = session.get(
|
||||
f"http://127.0.0.1:{port}/admin/login/",
|
||||
headers={"Host": f"{hostname}:{port}"},
|
||||
timeout=15,
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert response.status_code == 200, (hostname, response.status_code)
|
||||
assert 'name="password"' in response.text, hostname
|
||||
assert "base_url not set" not in response.text.lower(), hostname
|
||||
assert "archivebox-setup-wizard" not in response.text, hostname
|
||||
csrf = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', response.text)
|
||||
assert csrf, hostname
|
||||
login = session.post(
|
||||
f"http://127.0.0.1:{port}/admin/login/",
|
||||
headers={"Host": f"{hostname}:{port}"},
|
||||
data={
|
||||
"username": env["ADMIN_USERNAME"],
|
||||
"password": env["ADMIN_PASSWORD"],
|
||||
"csrfmiddlewaretoken": csrf[1],
|
||||
"next": "/admin/",
|
||||
},
|
||||
timeout=15,
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert login.status_code == 302, (hostname, login.status_code)
|
||||
admin = session.get(
|
||||
f"http://127.0.0.1:{port}/admin/",
|
||||
headers={"Host": f"{hostname}:{port}"},
|
||||
timeout=15,
|
||||
allow_redirects=False,
|
||||
)
|
||||
assert admin.status_code == 200, (hostname, admin.status_code)
|
||||
assert "base_url not set" not in admin.text.lower(), hostname
|
||||
assert "archivebox-setup-wizard" not in admin.text, hostname
|
||||
finally:
|
||||
stop_archivebox_process(process)
|
||||
@@ -127,6 +127,10 @@ def test_persona_admin_add_view_renders_import_ui(admin_client):
|
||||
assert b"auth.json" in response.content
|
||||
assert b"Plugin Config" in response.content
|
||||
assert b'name="plugin_config__wget__WGET_TIMEOUT"' in response.content
|
||||
assert b'<fieldset id="plugin-config" class="module aligned wide persona-plugin-config">' in response.content
|
||||
assert b'href="https://archivebox.github.io/archivebox-browser-extension/"' in response.content
|
||||
assert b"import cookies into this persona from another browser" in response.content
|
||||
assert "wide" in response.context["adminform"].fieldsets[0][1]["classes"]
|
||||
|
||||
|
||||
def test_import_persona_from_source_copies_profile_without_browser_export(admin_user):
|
||||
|
||||
@@ -230,11 +230,14 @@ assert_writable_dir "$DATA_DIR/logs"
|
||||
assert_writable_dir "$DATA_DIR/archive"
|
||||
assert_writable_dir "$PERSONAS_DIR/Default/chrome_profile"
|
||||
|
||||
# check if novnc x11 $DISPLAY is available
|
||||
export DISPLAY="${DISPLAY:-"novnc:0.0"}"
|
||||
if ! xdpyinfo > /dev/null 2>&1; then
|
||||
# cant connect to x11 display, unset it so that chrome doesn't try to connect to it and hang indefinitely
|
||||
unset DISPLAY
|
||||
# Preserve an explicit DISPLAY (including an empty value to disable X11).
|
||||
# Only probe the implicit noVNC default: a missing probe or unavailable server
|
||||
# must not silently discard the user's display configuration.
|
||||
if [[ -z "${DISPLAY+x}" ]]; then
|
||||
export DISPLAY="novnc:0.0"
|
||||
if ! xdpyinfo > /dev/null 2>&1; then
|
||||
unset DISPLAY
|
||||
fi
|
||||
fi
|
||||
|
||||
# Active browser processes do not survive container restarts, but their lock
|
||||
@@ -250,6 +253,9 @@ find /tmp "$TMP_DIR" -maxdepth 1 -type d -name "archivebox-chrome-profile.*" -mm
|
||||
|
||||
|
||||
ensure_dir "/home/$ARCHIVEBOX_USER"
|
||||
# A nested read-only browser-profile mount can create this parent as root.
|
||||
# OpenCode's installer needs to create a sibling config directory as archivebox.
|
||||
ensure_dir "${XDG_CONFIG_HOME:-/home/$ARCHIVEBOX_USER/.config}"
|
||||
ensure_small_runtime_tree "$ABXBUS_CACHE_DIR"
|
||||
ensure_small_runtime_tree "$ABXBUS_CACHE_DIR/semaphores"
|
||||
ensure_small_runtime_tree "$UV_CACHE_DIR"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<footer class="abx-footer" aria-label="ArchiveBox ecosystem">
|
||||
<div class="abx-footer-intro"><div><a class="abx-brand" href="https://archivebox.io/"><svg class="abx-logo" viewBox="0 0 40 40" aria-hidden="true"><rect width="40" height="40" rx="10" fill="#9b2854"/><path d="M10 14h20v17H10z" fill="#fff4ed"/><path d="M8 9h24v6H8z" fill="#fff4ed"/><path d="M16 19h8v3h-8z" fill="#9b2854"/><path d="M12 31V17" stroke="#9b2854" stroke-width="2"/></svg><span>ArchiveBox</span></a><p class="abx-tagline">Open-source tools for keeping a lasting copy of the web.<br>Your data. Your devices. Your archive.</p></div><p class="abx-footer-motto">A home for the web<br>you want to keep.</p></div>
|
||||
<div class="abx-footer-grid"><section class="abx-footer-column"><h2>Apps & tools</h2><ul><li><a href="https://archivebox.io/">Self-hosted Web Archive</a><a class="abx-source" href="https://github.com/ArchiveBox/ArchiveBox" aria-label="Self-hosted Web Archive source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#get-started">iOS App for iPhone & iPad</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="iOS App for iPhone & iPad source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#your-server-your-choice">macOS App + Server App</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="macOS App + Server App source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/archivebox-browser-extension/">Browser Extensions</a><a class="abx-source" href="https://github.com/ArchiveBox/archivebox-browser-extension" aria-label="Browser Extensions source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-dl/">Command-line Downloader</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-dl" aria-label="Command-line Downloader source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-plugins/">Plugins & Extractors</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-plugins" aria-label="Plugins & Extractors source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 Line truncated
|
||||
<div class="abx-footer-grid"><section class="abx-footer-column"><h2>Apps & tools</h2><ul><li><a href="https://archivebox.io/">ArchiveBox Server</a><a class="abx-source" href="https://github.com/ArchiveBox/ArchiveBox" aria-label="ArchiveBox Server source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#get-started">ArchiveBox for macOS & iOS</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="ArchiveBox for macOS & iOS source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a class="abx-source" href="https://github.com/ArchiveBox/archivebox-browser-extension" aria-label="ArchiveBox Browser Extension source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-plugins" aria-label="ArchiveBox Plugin Library source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-dl/">One-shot abx-dl CLI</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-dl" aria-label="One-shot abx-dl CLI source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#your-server-your-choice">ArchiveBox Server.app</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="ArchiveBox Server.app source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 1Line truncated
|
||||
|
||||
<div class="abx-footer-bottom"><p>Built in the open. Supported by our community.</p><p><a href="https://github.com/ArchiveBox">GitHub organization</a> · <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Security-Overview">Security & privacy</a> · <a href="https://archivebox.io">ArchiveBox.io ↗</a></p></div>
|
||||
</footer>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<header class="abx-header">
|
||||
<a class="abx-brand" href="https://archivebox.io/"><svg class="abx-logo" viewBox="0 0 40 40" aria-hidden="true"><rect width="40" height="40" rx="10" fill="#9b2854"/><path d="M10 14h20v17H10z" fill="#fff4ed"/><path d="M8 9h24v6H8z" fill="#fff4ed"/><path d="M16 19h8v3h-8z" fill="#9b2854"/><path d="M12 31V17" stroke="#9b2854" stroke-width="2"/></svg><span>ArchiveBox</span><span class="abx-subsite">UI Screenshots</span></a>
|
||||
<nav class="abx-nav" aria-label="Main navigation">
|
||||
<details class="abx-apps"><summary>Apps</summary><div class="abx-app-links"><a href="https://archivebox.io/">ArchiveBox Server</a><a href="https://archivebox.github.io/ios-archivebox/">ArchiveBox for macOS & iOS</a><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a href="https://archivebox.github.io/abx-dl/">One-shot <code>abx-dl</code> CLI</a><a href="https://github.com/ArchiveBox">More on Github...</a></div></details>
|
||||
<details class="abx-apps"><summary>Apps</summary><div class="abx-app-links"><a href="https://archivebox.io/">ArchiveBox Server</a><a href="https://archivebox.github.io/ios-archivebox/">ArchiveBox for macOS & iOS</a><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a href="https://archivebox.github.io/abx-dl/"><span>One-shot <code>abx-dl</code> CLI</span></a><a href="https://github.com/ArchiveBox">More on Github...</a></div></details>
|
||||
<a href="https://archivebox.io/screenshots/">Screenshots</a><a href="https://github.com/ArchiveBox/ArchiveBox/wiki">Docs</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox">GitHub ↗</a>
|
||||
<a class="abx-cta" href="https://archivebox.io/#install">Get started</a>
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
# Real Compose regression checks. Build the image under test first, then run:
|
||||
# IMAGE=archivebox/archivebox:issue-1872 ./bin/validate_docker_display.sh
|
||||
set -Eeuo pipefail
|
||||
|
||||
export IMAGE="${IMAGE:-archivebox/archivebox:dev}"
|
||||
validation_dir="$(mktemp -d "${TMPDIR:-/tmp}/archivebox-display.XXXXXX")"
|
||||
compose=(docker compose --project-name "archivebox-display-$$" --file "$validation_dir/compose.yml")
|
||||
cleanup() {
|
||||
"${compose[@]}" down --volumes --remove-orphans
|
||||
echo "Validation files: $validation_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
cat > "$validation_dir/compose.yml" <<'YAML'
|
||||
services:
|
||||
archivebox:
|
||||
image: ${IMAGE}
|
||||
volumes:
|
||||
- ./data:/data
|
||||
- ./data/personas:/data/personas
|
||||
- tmp:/tmp/archivebox
|
||||
shm_size: 1gb
|
||||
novnc:
|
||||
image: theasp/novnc:latest
|
||||
environment:
|
||||
DISPLAY_WIDTH: 1280
|
||||
DISPLAY_HEIGHT: 800
|
||||
RUN_XTERM: "no"
|
||||
healthcheck:
|
||||
test: ["CMD", "xdpyinfo", "-display", ":0"]
|
||||
interval: 2s
|
||||
timeout: 2s
|
||||
retries: 10
|
||||
volumes:
|
||||
tmp:
|
||||
YAML
|
||||
|
||||
"${compose[@]}" up -d --wait novnc
|
||||
|
||||
# Check the real runtime dependency as well as successful X11 connectivity.
|
||||
"${compose[@]}" run --rm archivebox sh -ec '
|
||||
command -v xdpyinfo
|
||||
test "$DISPLAY" = novnc:0.0
|
||||
xdpyinfo >/dev/null
|
||||
'
|
||||
"${compose[@]}" run --rm -e DISPLAY=novnc:0.0 archivebox sh -ec '
|
||||
test "$DISPLAY" = novnc:0.0
|
||||
xdpyinfo >/dev/null
|
||||
'
|
||||
|
||||
# Explicit values belong to the caller, even when X11 is unavailable.
|
||||
"${compose[@]}" run --rm -e DISPLAY=unavailable:0 archivebox sh -ec '
|
||||
test "$DISPLAY" = unavailable:0
|
||||
'
|
||||
# An explicit empty value disables automatic display discovery.
|
||||
"${compose[@]}" run --rm -e DISPLAY= archivebox sh -ec '
|
||||
test "${DISPLAY+x}" = x
|
||||
test -z "$DISPLAY"
|
||||
'
|
||||
|
||||
"${compose[@]}" stop novnc
|
||||
"${compose[@]}" run --rm archivebox sh -ec '
|
||||
test "${DISPLAY+x}" != x
|
||||
'
|
||||
"${compose[@]}" run --rm -e DISPLAY=novnc:0.0 archivebox sh -ec '
|
||||
test "$DISPLAY" = novnc:0.0
|
||||
'
|
||||
echo 'PASS: Compose DISPLAY discovery, explicit override, empty opt-out, and headless fallback'
|
||||
@@ -149,6 +149,22 @@ ssh -N -L 8080:127.0.0.1:8080 user@your-server
|
||||
|
||||
4. Open a page and confirm you can view it while logged in. For a new persona, log in to the sites you want to archive. Then follow [Save and check the page](#3-save-and-check-the-page), selecting the same persona.
|
||||
|
||||
#### One-off Compose setup
|
||||
|
||||
To set up a persona without starting the ArchiveBox server, enable the same `novnc` service and healthy `depends_on` block, then run:
|
||||
|
||||
```bash
|
||||
docker compose up -d --wait novnc
|
||||
docker compose run --rm archivebox persona create personal
|
||||
docker compose run --rm -e DISPLAY=novnc:0.0 archivebox persona open personal
|
||||
```
|
||||
|
||||
Connect at <http://localhost:8080/vnc.html>, log in, and close the browser when finished. The persona remains in `data/personas/personal` across one-off containers.
|
||||
|
||||
`persona open` resolves the installed Chromium binary automatically. Do not hard-code `/data/lib/env/bin/chromium` or a versioned Playwright cache path: the browser location varies by image version and architecture.
|
||||
|
||||
An explicitly set `DISPLAY` is preserved. When it is unset, ArchiveBox probes `novnc:0.0` and falls back to headless operation if unavailable. Set `DISPLAY=` to disable this automatic display selection.
|
||||
|
||||
## Troubleshooting Chromium Install
|
||||
|
||||
<a name="more-info--troubleshooting"></a>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "archivebox",
|
||||
"version": "0.9.35rc473",
|
||||
"version": "0.9.35rc517",
|
||||
"repository": "github:ArchiveBox/ArchiveBox",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,11 @@
|
||||
# Integration brand icons
|
||||
|
||||
Original brand artwork used to identify tools and services.
|
||||
|
||||
- [google-drive.svg](https://raw.githubusercontent.com/homarr-labs/dashboard-icons/main/svg/google-drive.svg)
|
||||
- [n8n.svg](https://raw.githubusercontent.com/homarr-labs/dashboard-icons/main/svg/n8n.svg)
|
||||
- [slack.svg](https://raw.githubusercontent.com/homarr-labs/dashboard-icons/main/svg/slack.svg)
|
||||
- [ldap.png](https://www.tenfold-security.com/wp-content/uploads/LDAP.png)
|
||||
- [codex.svg](https://raw.githubusercontent.com/lobehub/lobe-icons/master/packages/static-svg/icons/codex.svg)
|
||||
- [claude-code.svg](https://raw.githubusercontent.com/lobehub/lobe-icons/master/packages/static-svg/icons/claudecode-color.svg)
|
||||
- [aws-s3-wordmark.svg](https://cdn.worldvectorlogo.com/logos/amazon-s3.svg): original AWS S3 wordmark, with its SVG viewBox focused on the S3 lettering for readability at icon size.
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="430 38 160 104" width="160" height="104"><style>.st0{fill:#252f3e}.st1{fill:#f90}</style><title>AS3Logo</title><path class="st0" d="M84.7 65.3c-.1 3 .3 6 1.1 8.9.9 2.5 2 4.9 3.2 7.2.4.7.7 1.5.7 2.3-.1 1.2-.8 2.4-1.9 3l-6.3 4.2c-.8.5-1.7.9-2.6.9-1.1-.1-2.2-.6-3-1.4-1.3-1.4-2.6-3-3.6-4.7-1-1.7-2-3.6-3.1-5.9-7.8 9.2-17.6 13.8-29.4 13.8-8.4 0-15.1-2.4-20-7.2s-7.4-11.2-7.4-19.2c0-8.5 3-15.4 9.1-20.6s14.2-7.8 24.5-7.8c3.5 0 7.1.3 10.6.8 3.7.5 7.5 1.3 11.5 2.2v-7.3c0-7.6-1.6-12.9-4.7-16s-8.6-4.6-16.3-4.6c-3.6 0-7.3.4-10.8 1.3-3.7.9-7.3 2-10.8 3.4-1.1.5-2.3.9-3.5 1.3-.5.2-1.1.3-1.6.3-1.4 0-2.1-1-2.1-3.1v-4.9c-.1-1.2.2-2.4.7-3.5.8-.9 1.7-1.6 2.8-2.1 4-2 8.2-3.5 12.6-4.5C39.5.8 44.8.2 50 .2c11.9 0 20.6 2.7 26.2 8.1s8.3 13.6 8.3 24.6v32.4h.2zM44.1 80.5c3.5 0 7-.6 10.3-1.8 3.7-1.3 6.9-3.5 9.5-6.4 1.6-1.8 2.8-4 3.4-6.4.7-2.8 1-5.8 1-8.7V53c-3-.7-6.1-1.3-9.2-1.7-3.1-.4-6.3-.6-9.4-.6-6.7 0-11.6 1.3-14.9 4s-4.9 6.5-4.9 11.5c0 4.7 1.2 8.2 3.7 10.6s5.9 3.7 10.5 3.7zm80.3 10.8c-1.3.1-2.7-.2-3.8-1-1-1.1-1.8-2.4-2.1-3.9L95 9.1c-.5-1.3-.8-2.6-.9-4-.1-1.2.7-2.3 1.9-2.5h10.4c1.9 0 3.2.3 3.9 1s1.4 2 2 3.9L129 73.7l15.6-66.2c.5-2 1.1-3.3 1.9-3.9 1.2-.7 2.6-1.1 4-1h8c1.9 0 3.2.3 4 1 1 1.1 1.7 2.4 1.9 3.9l15.8 67 17.3-67c.3-1.5 1-2.8 2-3.9 1.2-.7 2.5-1.1 3.9-1h9.3c1.2-.2 2.3.7 2.5 1.9v.6c0 .5-.1 1.1-.2 1.6-.2.9-.4 1.7-.7 2.5l-24.1 77.3c-.6 2-1.3 3.3-2.1 3.9-1.1.7-2.5 1.1-3.8 1h-8.6c-1.9 0-3.2-.3-4-1-1-1.1-1.7-2.5-1.9-4l-15.5-64.5-15.4 64.4c-.2 1.5-.9 2.9-1.9 4-1.2.8-2.6 1.1-4 1h-8.6zM252.9 94c-5.2 0-10.4-.6-15.4-1.8-5-1.2-8.9-2.5-11.5-4-1.3-.6-2.4-1.6-3.1-2.8-.4-.9-.6-1.8-.6-2.8v-5.1c0-2.1.8-3.1 2.3-3.1.6 0 1.2.1 1.8.3.6.2 1.5.6 2.5 1 3.5 1.6 7.2 2.7 11 3.5 3.9.8 7.9 1.2 11.9 1.2 6.3 0 11.2-1.1 14.6-3.3 3.3-2 5.3-5.6 5.2-9.5.1-2.6-.9-5.1-2.7-7-1.8-1.9-5.2-3.6-10.1-5.2l-14.5-4.5c-7.3-2.3-12.7-5.7-16-10.2-3.2-4.2-5-9.2-5-14.5-.1-3.9.8-7.7 2.7-11.1 1.8-3.2 4.2-6 7.2-8.2 3.1-2.4 6.6-4.1 10.4-5.2 4.1-1.2 8.3-1.8 12.6-1.7 2.2 0 4.5.1 6.7.4 2.3.3 4.4.7 6.5 1.1s3.9 1 5.7 1.6c1.5.5 2.9 1.1 4.2 1.8 1.2.6 2.2 1.4 3 2.5.7 1 1 2.1.9 3.3v4.7c0 2.1-.8 3.2-2.3 3.2-1.3-.2-2.6-.6-3.8-1.2-6-2.7-12.6-4-19.2-3.9-5.7 0-10.2.9-13.3 2.8s-4.7 4.8-4.7 8.9c-.1 2.7 1 5.3 3 7.1 2 1.9 5.7 3.8 11 5.5l14.2 4.5c7.2 2.3 12.4 5.5 15.5 9.6 3.1 4 4.7 9 4.6 14 .1 4-.8 8-2.6 11.6-1.8 3.4-4.3 6.4-7.3 8.8-3.3 2.6-7.1 4.5-11.1 5.6-4.6 1.4-9.4 2.1-14.3 2.1z"/><path class="st1" d="M271.8 142.6c-32.9 24.3-80.7 37.2-121.8 37.2-57.6 0-109.5-21.3-148.7-56.7-3.1-2.8-.3-6.6 3.4-4.4 42.4 24.6 94.7 39.5 148.8 39.5 39-.2 77.6-8.1 113.5-23.2 5.5-2.5 10.2 3.6 4.8 7.6z"/><path class="st1" d="M285.5 127c-4.2-5.4-27.8-2.6-38.5-1.3-3.2.4-3.7-2.4-.8-4.5 18.8-13.2 49.7-9.4 53.3-5 3.6 4.4-1 35.4-18.6 50.2-2.7 2.3-5.3 1.1-4.1-1.9 4-9.9 12.9-32.2 8.7-37.5z"/><path class="st0" d="M460.6 112.4c1 2 2.5 3.7 4.3 5 1.9 1.3 4 2.3 6.3 2.8 2.4.6 4.9.9 7.4.9 1.9 0 3.7-.2 5.6-.4 1.9-.3 3.8-.8 5.6-1.7 1.7-.8 3.2-2 4.3-3.4 1.2-1.6 1.8-3.5 1.7-5.5.1-2.2-.8-4.3-2.3-5.8-1.7-1.6-3.8-2.8-6-3.7-2.7-1.1-5.5-1.9-8.4-2.6-3.1-.7-6.3-1.6-9.5-2.5-3.3-.8-6.5-1.8-9.7-3-3-1.1-5.9-2.7-8.4-4.7-2.5-1.9-4.5-4.3-6-7.1-1.6-3.2-2.4-6.7-2.3-10.3-.1-4.1.9-8.2 3-11.8 1.9-3.3 4.5-6.2 7.6-8.4 3.2-2.3 6.8-3.9 10.6-5 3.9-1.1 7.9-1.6 11.9-1.6 4.5 0 8.9.5 13.3 1.5 4.1.9 7.9 2.6 11.3 5 3.3 2.3 6 5.3 7.9 8.8 2 4 3 8.5 2.9 13h-18.8c-.1-2.3-.7-4.5-1.7-6.5-.9-1.7-2.2-3.1-3.8-4.1-1.7-1-3.5-1.7-5.4-2.1-2.2-.4-4.4-.6-6.6-.6-1.6 0-3.2.2-4.7.5s-3 .9-4.3 1.7c-1.3.8-2.3 1.9-3.1 3.1-.9 1.4-1.3 3-1.2 4.7-.1 1.5.3 2.9 1 4.2 1 1.4 2.3 2.4 3.9 3 2.6 1.1 5.3 2 8 2.7 3.4.9 7.9 2.1 13.4 3.5 1.6.3 3.9.9 6.9 1.8 3.1.9 6 2.3 8.7 4.1 3 2 5.6 4.5 7.5 7.5 2.1 3.2 3.2 7.2 3.2 12.2 0 3.9-.8 7.7-2.4 11.3-1.6 3.5-4 6.6-7 9-3.4 2.7-7.3 4.7-11.5 5.9-5.2 1.5-10.5 2.2-15.9 2.1-4.8 0-9.5-.6-14.2-1.8-4.4-1.1-8.5-3-12.1-5.7-3.5-2.6-6.4-5.9-8.4-9.8-2.2-4.4-3.2-9.2-3-14.1H459c-.1 2.9.5 5.5 1.6 7.9zM551.8 82.5c2.1-.1 4.1-.6 6-1.4 1.8-.7 3.4-1.9 4.6-3.4 1.3-1.7 1.9-3.8 1.8-5.9 0-3.7-1.2-6.6-3.7-8.5-2.4-2-5.4-3-8.5-3-4.5 0-7.8 1.5-10.1 4.4-2.4 3.2-3.5 7.1-3.3 11.1h-16.7c.1-4.2.9-8.3 2.4-12.2 1.4-3.5 3.4-6.8 6.1-9.5 2.7-2.7 5.8-4.8 9.3-6.1 3.9-1.5 8-2.2 12.1-2.2 3.5 0 7 .5 10.4 1.5 3.4 1 6.5 2.6 9.3 4.6 2.7 2 5 4.6 6.7 7.5 1.8 3.1 2.7 6.7 2.6 10.3.1 3.9-1 7.8-3 11.1-2.1 3.3-5.3 5.6-9.1 6.6v.3c4.4.9 8.4 3.3 11.2 6.9 2.8 3.7 4.2 8.2 4.1 12.7.1 4.2-.8 8.4-2.6 12.1-1.7 3.5-4.1 6.5-7.1 8.9-3.1 2.4-6.5 4.3-10.3 5.4-3.9 1.2-8 1.9-12.1 1.9-4.5.1-9-.7-13.3-2.1-3.8-1.3-7.3-3.4-10.2-6.1-2.9-2.8-5.1-6.1-6.5-9.9-1.6-4.3-2.3-8.8-2.2-13.4h16.7c.1 2.2.4 4.5 1.1 6.6.6 2 1.6 3.8 2.9 5.5 1.3 1.5 2.8 2.8 4.6 3.6 2.1 1 4.3 1.4 6.6 1.4 3.7.1 7.3-1.2 10-3.6 2.7-2.4 4.1-5.8 4.1-10 0-3.3-.6-5.8-1.9-7.5-1.2-1.7-2.9-3-4.9-3.8-2.1-.8-4.3-1.2-6.5-1.3-2.4-.1-4.6-.2-6.7-.2V82.5c2 .2 4.1.2 6.1 0zM375.4 1.9h7v176h-7z"/></svg>
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#569A31" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Amazon S3</title><path d="M20.913 13.147l.12-.895c.947.576 1.258.922 1.354 1.071-.16.031-.562.046-1.474-.176zm-2.174 7.988a.547.547 0 0 0-.005.073c0 .084-.207.405-1.124.768a10.28 10.28 0 0 1-1.438.432c-1.405.325-3.128.504-4.853.504-4.612 0-7.412-1.184-7.412-1.704a.547.547 0 0 0-.005-.073L1.81 5.602c.135.078.28.154.432.227.042.02.086.038.128.057.134.062.272.122.417.18l.179.069c.154.058.314.114.478.168.043.013.084.029.13.043.207.065.423.127.646.187l.176.044c.175.044.353.087.534.127a23.414 23.414 0 0 0 .843.17l.121.023c.252.045.508.085.768.122.071.011.144.02.216.03.2.027.4.053.604.077l.24.027c.245.026.49.05.74.07l.081.009c.275.022.552.04.83.056l.233.012c.21.01.422.018.633.025a33.088 33.088 0 0 0 2.795-.026l.232-.011c.278-.016.555-.034.83-.056l.08-.008c.25-.02.497-.045.742-.072l.238-.026c.205-.024.408-.05.609-.077.07-.01.141-.019.211-.03.261-.037.519-.078.772-.122l.111-.02c.215-.04.427-.082.634-.125l.212-.047c.186-.041.368-.085.546-.13l.166-.042c.225-.06.444-.122.654-.189.04-.012.077-.026.115-.038a10.6 10.6 0 0 0 .493-.173c.058-.021.114-.044.17-.066.15-.06.293-.12.43-.185.038-.017.079-.034.116-.052.153-.073.3-.15.436-.228l-.976 7.245c-2.488-.78-5.805-2.292-7.311-3a1.09 1.09 0 0 0-1.088-1.085c-.6 0-1.088.489-1.088 1.088 0 .6.488 1.089 1.088 1.089.196 0 .378-.056.537-.148 1.72.812 5.144 2.367 7.715 3.15zm-7.42-20.047c5.677 0 9.676 1.759 9.75 2.736l-.014.113c-.01.033-.031.067-.048.101-.015.028-.026.057-.047.087-.024.033-.058.068-.09.102-.028.03-.051.06-.084.09-.038.035-.087.07-.133.105-.04.03-.074.06-.119.091-.053.036-.116.071-.177.107-.05.03-.095.06-.15.09-.068.036-.147.073-.222.11-.059.028-.114.057-.177.085-.084.038-.177.074-.268.111-.068.027-.13.054-.203.082-.097.036-.205.072-.31.107-.075.026-.148.053-.228.079-.111.035-.233.069-.35.103-.085.024-.165.05-.253.073-.124.034-.258.065-.389.098-.093.022-.181.046-.278.068-.139.032-.287.061-.433.091-.098.02-.191.041-.293.06-.155.03-.32.057-.482.084-.1.018-.198.036-.302.052-.166.026-.342.048-.515.072-.11.014-.213.03-.325.044-.181.023-.372.041-.56.06-.11.012-.218.025-.332.036-.188.016-.386.029-.58.043-.122.009-.24.02-.364.028-.207.012-.422.02-.635.028-.12.005-.234.012-.354.016a35.605 35.605 0 0 1-2.069 0c-.12-.004-.234-.011-.352-.016-.214-.008-.43-.016-.637-.028-.122-.008-.238-.02-.36-.027-.195-.015-.394-.028-.584-.044-.11-.01-.215-.024-.324-.035-.19-.02-.384-.038-.568-.06l-.315-.044c-.176-.024-.355-.046-.525-.073-.1-.015-.192-.033-.29-.05-.167-.028-.335-.055-.494-.086-.096-.018-.183-.038-.276-.056-.151-.032-.305-.062-.45-.095-.09-.02-.173-.043-.26-.064-.138-.034-.277-.067-.407-.102-.082-.022-.157-.046-.235-.069a11.75 11.75 0 0 1-.368-.108c-.075-.024-.141-.049-.213-.073-.11-.037-.223-.075-.325-.113-.067-.025-.125-.051-.188-.077-.096-.038-.195-.076-.282-.115-.06-.027-.11-.054-.166-.08-.08-.039-.162-.077-.233-.116-.052-.028-.094-.055-.142-.084-.063-.038-.13-.075-.185-.113-.043-.029-.075-.058-.113-.086-.048-.037-.098-.073-.139-.11-.032-.029-.054-.057-.08-.087-.033-.035-.069-.07-.093-.104-.02-.03-.031-.058-.046-.086-.018-.035-.039-.068-.049-.102l-.015-.113c.076-.977 4.074-2.736 9.748-2.736zm12.182 12.124c-.118-.628-.84-1.291-2.31-2.128l.963-7.16a.531.531 0 0 0 .005-.073C22.16 1.581 16.447 0 11.32 0 6.194 0 .482 1.581.482 3.851a.58.58 0 0 0 .005.072L2.819 21.25c.071 2.002 5.236 2.75 8.5 2.75 1.805 0 3.615-.188 5.098-.531.598-.138 1.133-.3 1.592-.48 1.18-.467 1.789-1.053 1.813-1.739l.945-7.018c.557.131 1.016.197 1.389.197.54 0 .902-.137 1.134-.413a.956.956 0 0 0 .21-.804Z"/></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@@ -0,0 +1 @@
|
||||
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude Code</title><path clip-rule="evenodd" d="M20.998 10.949H24v3.102h-3v3.028h-1.487V20H18v-2.921h-1.487V20H15v-2.921H9V20H7.488v-2.921H6V20H4.487v-2.921H3V14.05H0V10.95h3V5h17.998v5.949zM6 10.949h1.488V8.102H6v2.847zm10.51 0H18V8.102h-1.49v2.847z" fill="#D97757" fill-rule="evenodd"></path></svg>
|
||||
|
After Width: | Height: | Size: 425 B |
@@ -0,0 +1 @@
|
||||
<svg fill="currentColor" fill-rule="evenodd" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Codex</title><path clip-rule="evenodd" d="M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><path d="m38.7 419.3 22.6 39c4.7 8.2 11.4 14.7 19.4 19.4l80.6-139.6H0c0 9.1 2.3 18.2 7 26.4z" style="fill:#0066da"/><path d="M256 173.9 175.4 34.3c-7.9 4.7-14.7 11.1-19.4 19.4L7 311.7c-4.6 8-7 17.1-7 26.4h161.3z" style="fill:#00ac47"/><path d="M431.4 477.7c7.9-4.7 14.7-11.1 19.4-19.4l9.4-16.1 44.9-77.7c4.7-8.2 7-17.3 7-26.4H350.7l34.3 67.4z" style="fill:#ea4335"/><path d="m256 173.9 80.6-139.6c-7.9-4.7-17-7-26.4-7H201.8c-9.4 0-18.5 2.6-26.4 7z" style="fill:#00832d"/><path d="M350.7 338.1H161.3L80.6 477.7c7.9 4.7 17 7 26.4 7h298c9.4 0 18.5-2.6 26.4-7z" style="fill:#2684fc"/><path d="M430.5 182.7 356 53.7c-4.7-8.2-11.4-14.7-19.4-19.4L256 173.9l94.7 164.2h161c0-9.1-2.3-18.2-7-26.4z" style="fill:#ffba00"/></svg>
|
||||
|
After Width: | Height: | Size: 801 B |
|
After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 121.3 512.1 269.6"><path d="M458.1 229.1c-25.1 0-46.2-17.2-52.2-40.4h-61.8c-13.2 0-24.4 9.5-26.6 22.5l-2.2 13.3c-2 12.2-8.2 23.4-17.5 31.6 9.3 8.2 15.5 19.3 17.5 31.6l2.2 13.3c2.2 13 13.4 22.5 26.6 22.5h7.9c6-23.2 27.1-40.4 52.2-40.4 29.8 0 53.9 24.1 53.9 53.9s-24.1 53.9-53.9 53.9c-25.1 0-46.2-17.2-52.2-40.4h-7.9c-26.3 0-48.8-19-53.2-45l-2.2-13.3c-2.2-13-13.4-22.5-26.6-22.5h-21.4c-6 23.2-27.1 40.4-52.2 40.4s-46.2-17.2-52.2-40.4H106c-6 23.2-27.1 40.4-52.2 40.4C24.1 309.9 0 285.8 0 256s24.1-53.9 53.9-53.9c25.1 0 46.2 17.2 52.2 40.4h30.3c6-23.2 27.1-40.4 52.2-40.4s46.2 17.2 52.2 40.4h21.4c13.2 0 24.4-9.5 26.6-22.5l2.2-13.3c4.3-26 26.8-45 53.2-45H406c6-23.2 27.1-40.4 52.2-40.4 29.8 0 53.9 24.1 53.9 53.9s-24.2 53.9-54 53.9m0-27c14.9 0 26.9-12.1 26.9-26.9s-12.1-26.9-26.9-26.9-26.9 12.1-26.9 26.9 12 26.9 26.9 26.9M53.9 282.9c14.9 0 26.9-12.1 26.9-26.9s-12.1-26.9-26.9-26.9-27 12-27 26.9 12.1 26.9 27 26.9M215.6 256c0 14.9-12.1 26.9-26.9 26.9s-26.9-12.1-26.9-26.9 12.1-26.9 26.9-26.9 26.9 12 26.9 26.9m215.6 80.8c0 14.9-12.1 26.9-26.9 26.9-14.9 0-26.9-12.1-26.9-26.9s12.1-26.9 26.9-26.9 26.9 12.1 26.9 26.9" style="fill-rule:evenodd;clip-rule:evenodd;fill:#ea4b71"/></svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="49.13 2.23 413.74 507.44"><linearGradient id="a" x1="-659.761" x2="-640.696" y1="769.342" y2="769.342" gradientTransform="matrix(21.1429 0 0 -21.1429 14003.722 16522.121)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#729fcf"/><stop offset=".316" style="stop-color:#babdb6"/><stop offset="1" style="stop-color:#3465a4"/></linearGradient><linearGradient id="b" x1="131.24" x2="589.471" y1="310.846" y2="310.846" gradientTransform="matrix(.9013 0 0 -1.1095 -68.802 600.87)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#729fcf"/><stop offset="1" style="stop-color:#204a87"/></linearGradient><path d="M254.3 12.8C147 12.8 59.7 51.1 59.7 98.1v315.7c0 47.1 87.3 85.3 194.6 85.3s198-38.3 198-85.3V98.1c0-47-90.7-85.3-198-85.3z" style="fill:url(#a);stroke:url(#b);stroke-width:21.1429;stroke-miterlimit:10"/><linearGradient id="c" x1="-655.123" x2="-638.939" y1="779.44" y2="746.331" gradientTransform="matrix(21.1429 0 0 -21.1429 14003.722 16522.121)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#3977c3"/><stop offset="1" style="stop-color:#89aedc;stop-opacity:0"/></linearGradient><path d="M254.4 23.4C154.3 23.4 73 59.1 73 103v302.1c0 43.9 81.4 79.6 181.4 79.6S439 449 439 405.1V103c0-43.9-84.6-79.6-184.6-79.6z" style="opacity:.5443;fill:none;stroke:url(#c);stroke-width:21.1429;stroke-miterlimit:10"/><linearGradient id="d" x1="-651.29" x2="-651.29" y1="775.963" y2="778.151" gradientTransform="matrix(21.9314 0 0 -20.1834 14538.794 15792.006)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#fff"/><stop offset="1" style="stop-color:#729fcf"/></linearGradient><path d="M437.2 97c0 39.6-81.5 71.7-182.1 71.7S73 136.6 73 97s81.5-71.7 182.1-71.7S437.2 57.4 437.2 97z" style="fill:#3465a4;stroke:url(#d);stroke-width:1.0049;stroke-miterlimit:10"/><linearGradient id="e" x1="-654.544" x2="-654.729" y1="774.918" y2="768.138" gradientTransform="matrix(21.1429 0 0 -21.1429 14000.701 16577.998)" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#fff"/><stop offset="1" style="stop-color:#fff;stop-opacity:0"/></linearGradient><path d="m113.7 160.4 4.9 229.2 62.4 17.6-2-228.3s28.3 0 74.1-2.9c-71.2-3.2-152.7-33.8-180.4-53.6 19.4 28.5 41 38 41 38" style="opacity:.4937;fill:url(#e)"/></svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 512 512"><path d="M107.9 323.6c0 29.7-24 53.8-53.8 53.8S.3 353.4.3 323.6c0-29.7 24-53.8 53.8-53.8h53.8zm26.9 0c0-29.7 24-53.8 53.8-53.8s53.8 24 53.8 53.8V458c0 29.7-24 53.8-53.8 53.8s-53.8-24-53.8-53.8z" style="fill:#e01e5a"/><path d="M188.6 107.7c-29.7 0-53.8-24-53.8-53.8S158.8.1 188.6.1s53.8 24 53.8 53.8v53.8zm0 27.3c29.7 0 53.8 24 53.8 53.8s-24 53.8-53.8 53.8H53.8C24 242.6 0 218.5 0 188.8S24 135 53.8 135z" style="fill:#36c5f0"/><path d="M404.1 188.8c0-29.7 24-53.8 53.8-53.8s53.8 24 53.8 53.8-24 53.8-53.8 53.8h-53.8zm-26.9 0c0 29.7-24 53.8-53.8 53.8-29.7 0-53.8-24-53.8-53.8V54c0-29.7 24-53.8 53.8-53.8s53.8 24 53.8 53.8z" style="fill:#2eb67d"/><path d="M323.4 404.3c29.7 0 53.8 24 53.8 53.8 0 29.7-24 53.8-53.8 53.8-29.7 0-53.8-24-53.8-53.8v-53.8zm0-26.9c-29.7 0-53.8-24-53.8-53.8s24-53.8 53.8-53.8h134.8c29.7 0 53.8 24 53.8 53.8 0 29.7-24 53.8-53.8 53.8z" style="fill:#ecb22e"/></svg>
|
||||
|
After Width: | Height: | Size: 969 B |
@@ -0,0 +1,14 @@
|
||||
# Plugin brand icons
|
||||
|
||||
Original brand artwork used to identify supported tools. SVG fills use the brand colors.
|
||||
|
||||
- [chrome.svg](https://raw.githubusercontent.com/devicons/devicon/master/icons/chrome/chrome-original.svg)
|
||||
- [ublock.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/ublockorigin.svg)
|
||||
- [github.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/github.svg)
|
||||
- [archive-org.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/internetarchive.svg)
|
||||
- [claude.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/claude.svg)
|
||||
- [webrecorder.svg](https://webrecorder.net/favicon.svg)
|
||||
- [singlefile.png](https://raw.githubusercontent.com/gildas-lormeau/SingleFile/master/src/ui/resources/icon_128.png)
|
||||
- [youtube.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/youtube.svg)
|
||||
- [tailscale.svg](https://raw.githubusercontent.com/simple-icons/simple-icons/develop/icons/tailscale.svg)
|
||||
- [tlsnotary.svg](https://tlsnotary.org/img/logo/tlsn-logo-blue.svg)
|
||||
@@ -0,0 +1 @@
|
||||
<svg fill="#333333" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Internet Archive</title><path d="M22.667 22.884V24H1.333v-1.116zm-.842-1.675v1.396H2.175v-1.396zM4.233 6.14l.234.118.118 1.882.117 3.058v2.941l-.117 3.666-.02 2.47-.332.098H3.062l-.352-.098-.136-2.47-.118-3.646v-2.941l.118-3.078.107-1.892.244-.107zm16.842 0l.235.118.117 1.882.117 3.058v2.941l-.117 3.666-.02 2.47-.332.098h-1.171l-.352-.098-.137-2.47-.117-3.646v-2.941l.117-3.078.108-1.892.244-.107zm-11.79 0l.235.118.117 1.882.117 3.058v2.941l-.117 3.666-.02 2.47-.331.098H8.114l-.352-.098-.136-2.47-.117-3.646v-2.941l.117-3.078.107-1.892.244-.107zm6.457 0l.234.118.117 1.882.118 3.058v2.941l-.118 3.666-.019 2.47-.332.098H14.57l-.351-.098-.137-2.47-.117-3.646v-2.941l.117-3.078.108-1.892.244-.107zm6.083-2.511V5.58H2.175V3.628zM11.798 0l10.307 2.347-.413.723H1.951l-.618-.587Z"/></svg>
|
||||
|
After Width: | Height: | Size: 881 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><circle fill="#fff" cx="64.149" cy="64.236" r="60.999"/><path fill-opacity=".1" d="M102.966 75.327c0-21.439-17.379-38.819-38.817-38.819s-38.818 17.38-38.818 38.819h11.09c0-15.314 12.415-27.727 27.727-27.727 15.313 0 27.727 12.413 27.727 27.727"/><circle fill-opacity=".1" cx="66.922" cy="71.999" r="21.072"/><linearGradient id="chrome-original-a" gradientUnits="userSpaceOnUse" x1="395.191" y1="484.168" x2="395.191" y2="484.723" gradientTransform="matrix(82 0 0 82 -32341.5 -39660.313)"><stop offset="0" stop-color="#81B4E0"/><stop offset="1" stop-color="#0C5A94"/></linearGradient><circle fill="url(#chrome-original-a)" cx="64.149" cy="64.235" r="22.736"/><linearGradient id="chrome-original-b" gradientUnits="userSpaceOnUse" x1="-608.91" y1="-597.648" x2="-608.91" y2="-547.185" gradientTransform="translate(675 599.775)"><stop offset="0" stop-color="#F06B59"/><stop offset="1" stop-color="#DF2227"/></linearGradient><path fill="url(#chrome-original-b)" d="M119.602 36.508C104.336 5.792 67.06-6.732 36.343 8.534A62.105 62.105 0 0012.578 29.3l24.955 43.253c-4.597-14.606 3.521-30.174 18.127-34.77a27.676 27.676 0 017.935-1.274"/><linearGradient id="chrome-original-c" gradientUnits="userSpaceOnUse" x1="-657.835" y1="-491.393" x2="-632.327" y2="-533.537" gradientTransform="translate(675 599.775)"><stop offset="0" stop-color="#388B41"/><stop offset="1" stop-color="#4CB749"/></linearGradient><path fill="url(#chrome-original-c)" d="M12.578 29.3c-19.1 28.492-11.486 67.071 17.005 86.171a62.133 62.133 0 0029.575 10.319l26.063-44.363c-9.745 11.811-27.22 13.486-39.032 3.74a27.717 27.717 0 01-8.657-12.613"/><linearGradient id="chrome-original-d" gradientUnits="userSpaceOnUse" x1="-572.385" y1="-486.91" x2="-599.557" y2="-552.345" gradientTransform="translate(675 599.775)"><stop offset="0" stop-color="#E4B022"/><stop offset=".3" stop-color="#FCD209"/></linearGradient><path fill="url(#chrome-original-d)" d="M59.158 125.791c34.204 2.585 64.027-23.047 66.613-57.25a62.097 62.097 0 00-6.17-32.031H63.595c15.312.07 27.67 12.541 27.598 27.854a27.725 27.725 0 01-5.972 17.064"/><linearGradient id="chrome-original-e" gradientUnits="userSpaceOnUse" x1="-649.391" y1="-528.885" x2="-649.391" y2="-573.247" gradientTransform="translate(675 599.775)"><stop offset="0" stop-opacity=".15"/><stop offset=".3" stop-opacity=".06"/><stop offset="1" stop-opacity=".03"/></linearGradient><path fill="url(#chrome-original-e)" d="M12.578 29.3l24.955 43.253a27.725 27.725 0 011.107-18.854L13.686 27.636"/><linearGradient id="chrome-original-f" gradientUnits="userSpaceOnUse" x1="-588.158" y1="-514.559" x2="-618.657" y2="-483.505" gradientTransform="translate(675 599.775)"><stop offset="0" stop-opacity=".15"/><stop offset=".3" stop-opacity=".06"/><stop offset="1" stop-opacity=".03"/></linearGradient><path fill="url(#chrome-original-f)" d="M59.158 125.791l26.063-44.363a27.731 27.731 0 01-16.082 9.426l-11.091 34.937"/><linearGradient id="chrome-original-g" gradientUnits="userSpaceOnUse" x1="-588.6" y1="-505.621" x2="-584.163" y2="-549.431" gradientTransform="translate(675 599.775)"><stop offset="0" stop-opacity=".15"/><stop offset=".3" stop-opacity=".06"/><stop offset="1" stop-opacity=".03"/></linearGradient><path fill="url(#chrome-original-g)" d="M119.602 36.508H63.595a27.727 27.727 0 0121.626 10.537l35.491-8.873"/></svg>
|
||||
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#D97757" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#181717" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
|
||||
|
After Width: | Height: | Size: 838 B |
|
After Width: | Height: | Size: 2.7 KiB |
@@ -0,0 +1 @@
|
||||
<svg fill="#242424" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Tailscale</title><path d="M24 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0zm-9 9a3 3 0 1 1-6 0 3 3 0 0 1 6 0zm0-9a3 3 0 1 1-6 0 3 3 0 0 1 6 0zm6-6a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5zM3 24a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5zm18 .5a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5zM6 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0zm9-9a3 3 0 1 1-6 0 3 3 0 0 1 6 0zm-3 2.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5zM6 3a3 3 0 1 1-6 0 3 3 0 0 1 6 0zM3 5.5a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/></svg>
|
||||
|
After Width: | Height: | Size: 646 B |
@@ -0,0 +1,11 @@
|
||||
<svg width="529" height="548" viewBox="0 0 529 548" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M153.581 4.41505C153.581 1.08579 157.014 -1.04229 159.856 0.525709L202.517 24.065C203.907 24.8316 204.774 26.3268 204.774 27.9544V58.7885H226.105C228.461 58.7885 230.371 60.7624 230.371 63.1974V133.741L217.573 124.923V72.0154H204.774V504.359C204.774 505.115 204.586 505.859 204.227 506.519L182.897 545.751C181.266 548.75 177.089 548.75 175.458 545.751L154.128 506.519C153.769 505.859 153.581 505.115 153.581 504.359V4.41505Z"
|
||||
fill="#243f5f" />
|
||||
<path d="M127.984 160.194V477.639H76.7903V213.102H0V160.194H127.984Z" fill="#243f5f" />
|
||||
<path d="M383.952 477.639H435.145V213.102H460.742V477.639H511.935V160.194H383.952V477.639Z"
|
||||
fill="#243f5f" />
|
||||
<path
|
||||
d="M230.371 160.194H358.355V213.102H281.565V292.463H358.355V477.639H230.371V424.732H307.161V345.37H230.371V160.194Z"
|
||||
fill="#243f5f" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 943 B |
@@ -0,0 +1 @@
|
||||
<svg fill="#800000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>uBlock Origin</title><path d="M12 0C7.502 3 6.002 3 1.5 3c0 15.002 0 15.002 10.5 21 10.5-5.998 10.5-5.998 10.5-21-4.498 0-5.998 0-10.5-3zM5.956 7.472h1.512v4.536c0 1.322.19 1.508 1.512 1.508 1.323 0 1.512-.19 1.512-1.512V7.472H12v.767a3.75 3.75 0 012.268-.767 3.79 3.79 0 013.776 3.78 3.79 3.79 0 01-3.78 3.775 3.765 3.764 0 01-2.684-1.133c-.464.77-1.315 1.133-2.6 1.133-2.079 0-3.024-.944-3.024-3.023zm8.308 1.512A2.254 2.254 0 0012 11.252a2.254 2.254 0 002.268 2.264 2.254 2.254 0 002.264-2.268 2.254 2.254 0 00-2.268-2.264z"/></svg>
|
||||
|
After Width: | Height: | Size: 629 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 8 8"><style>.b{fill:#088eaf}.g{fill:#4d7c0f}@media (prefers-color-scheme:dark){.b{fill:#0aaed7}.g{fill:#65a414}}</style><path d="M1.415 2.819a1.324 1.324 0 0 0 .82 2.364h1.147c.731 0 1.324-.593 1.324-1.324V3.55q.001-.037.026-.063a.1.1 0 0 1 .063-.025h.618a.088.088 0 0 1 .088.088v.309a2.12 2.12 0 0 1-2.119 2.118H2.235A2.12 2.12 0 0 1 .851 2.255l-.439-.439a.04.04 0 0 1-.009-.049.04.04 0 0 1 .04-.027h1.439c.024 0 .044.02.044.044v1.439a.04.04 0 0 1-.028.04.05.05 0 0 1-.048-.009z" class="b"/><path d="M6.497 4.899a1.325 1.325 0 0 0-.82-2.364H4.53c-.731 0-1.324.593-1.324 1.324v.309a.1.1 0 0 1-.026.062.1.1 0 0 1-.063.026h-.618a.09.09 0 0 1-.088-.088v-.309A2.12 2.12 0 0 1 4.53 1.74h1.147a2.12 2.12 0 0 1 1.384 3.723l.439.439a.05.05 0 0 1 .01.048.04.04 0 0 1-.041.027H6.031a.044.044 0 0 1-.045-.044V4.495q.001-.029.028-.041a.04.04 0 0 1 .048.01z" class="g"/></svg>
|
||||
|
After Width: | Height: | Size: 938 B |
@@ -0,0 +1 @@
|
||||
<svg fill="#FF0000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>YouTube</title><path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/></svg>
|
||||
|
After Width: | Height: | Size: 475 B |
@@ -20,7 +20,8 @@
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="./shadcn-theme.css">
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
<link rel="stylesheet" href="./styles.css?v=integration-icons-v1">
|
||||
<script src="./install.js" defer></script>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
@@ -49,7 +50,7 @@
|
||||
<header class="abx-header">
|
||||
<a class="abx-brand" href="https://archivebox.io/"><svg class="abx-logo" viewBox="0 0 40 40" aria-hidden="true"><rect width="40" height="40" rx="10" fill="#9b2854"/><path d="M10 14h20v17H10z" fill="#fff4ed"/><path d="M8 9h24v6H8z" fill="#fff4ed"/><path d="M16 19h8v3h-8z" fill="#9b2854"/><path d="M12 31V17" stroke="#9b2854" stroke-width="2"/></svg><span>ArchiveBox</span><span class="abx-subsite">Web Archive</span></a>
|
||||
<nav class="abx-nav" aria-label="Main navigation">
|
||||
<details class="abx-apps"><summary>Apps</summary><div class="abx-app-links"><a href="https://archivebox.io/">ArchiveBox Server</a><a href="https://archivebox.github.io/ios-archivebox/">ArchiveBox for macOS & iOS</a><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a href="https://archivebox.github.io/abx-dl/">One-shot <code>abx-dl</code> CLI</a><a href="https://github.com/ArchiveBox">More on Github...</a></div></details>
|
||||
<details class="abx-apps"><summary>Apps</summary><div class="abx-app-links"><a href="https://archivebox.io/">ArchiveBox Server</a><a href="https://archivebox.github.io/ios-archivebox/">ArchiveBox for macOS & iOS</a><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a href="https://archivebox.github.io/abx-dl/"><span>One-shot <code>abx-dl</code> CLI</span></a><a href="https://github.com/ArchiveBox">More on Github...</a></div></details>
|
||||
<a href="#use-cases">Use cases</a><a href="#configuration">Configuration</a><a href="#layout-security">Layout & security</a><a href="https://github.com/ArchiveBox/ArchiveBox/wiki">Docs</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox">GitHub ↗</a>
|
||||
<a class="abx-cta" href="#install">Get started</a>
|
||||
@@ -64,7 +65,7 @@
|
||||
<h1><span class="hero-mainline">Preserve the web.</span><span class="hero-subline">On infrastructure you control.</span></h1>
|
||||
<p class="lede">ArchiveBox saves websites, bookmarks, RSS feeds, social posts, media, source code, and research material in durable files like HTML, PDF, PNG, TXT, JSON, WARC, MP4, and SQLite.</p>
|
||||
<div class="hero-actions" aria-label="Primary actions">
|
||||
<a class="button primary" href="#install">Run with Docker Compose</a>
|
||||
<a class="button primary" href="#install">Get ArchiveBox</a>
|
||||
<a class="button secondary" href="./screenshots/">View screenshots</a>
|
||||
</div>
|
||||
<br/>
|
||||
@@ -100,7 +101,11 @@
|
||||
<span class="ab-prompt">$</span> <span class="ab-cursor" aria-hidden="true"> </span></pre>
|
||||
</div>
|
||||
</div>
|
||||
<img class="product-shot" src="https://github.com/ArchiveBox/ArchiveBox/assets/511499/e8e0b6f8-8fdf-4b7f-8124-c10d8699bdb2" alt="ArchiveBox snapshot list in the admin web interface">
|
||||
<div class="device-showcase">
|
||||
<a class="device-desktop" href="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" aria-label="Enlarge the ArchiveBox Web UI screenshot"><img class="product-shot" src="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" width="1600" height="1000" alt="ArchiveBox Web UI showing saved pages with thumbnails and capture formats"></a>
|
||||
<a class="device-phone" href="https://archivebox.github.io/ios-archivebox/" aria-label="Explore ArchiveBox for iPhone"><img src="https://archivebox.github.io/ios-archivebox/docs/screenshots/home-iphone.png" width="1500" height="3000" alt="ArchiveBox on iPhone, with its collection, tags, and server connection inside an iPhone frame"></a>
|
||||
</div>
|
||||
<p class="device-caption">Browse and save from any device.<br>Free, self-hosted, 0 analytics.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -113,38 +118,55 @@
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox#archive-layout">Filesystem access</a>
|
||||
</section>
|
||||
|
||||
<section class="section split">
|
||||
<div>
|
||||
<section class="section features-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Why ArchiveBox</p>
|
||||
<h2>Designed for useful archives, not proprietary silos.</h2>
|
||||
<h2>Designed to make your archived data useful <em>today.</em></h2>
|
||||
</div>
|
||||
<div class="feature-grid">
|
||||
<article>
|
||||
<h3>Readable for decades</h3>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="7" rx="2"/><rect x="3" y="14" width="18" height="7" rx="2"/><path d="M7 6.5h.01M7 17.5h.01M11 6.5h6M11 17.5h6"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/06-admin-dashboard-desktop.png"><img src="https://archivebox.io/screenshots/06-admin-dashboard-desktop.png" width="1600" height="1000" loading="lazy" alt="Self-hosted ArchiveBox dashboard"></a>
|
||||
</div>
|
||||
<h3>Own all your data</h3>
|
||||
<p>Run it as a Docker web app, use one-off CLI commands, or automate with APIs while keeping private and public data neatly separated.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v12m-5-5 5 5 5-5M4 16v5h16v-5"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/20-crawl-schedules-desktop.png"><img src="https://archivebox.io/screenshots/20-crawl-schedules-desktop.png" width="1600" height="1000" loading="lazy" alt="Scheduled archive imports"></a>
|
||||
</div>
|
||||
<h3>Import URLs from anywhere</h3>
|
||||
<p>Import URLs from <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Quickstart#2-get-your-list-of-urls-to-archive">bookmarks, browser history, feeds, and bookmarking apps</a>, or <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">text files</a>. Save links with our <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#browser-extension-usage">browser extension</a>, <a href="https://archivebox.github.io/ios-archivebox/">Mac and iPhone share menus, Siri, and Shortcuts</a>.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m12 3 10 5-10 5L2 8l10-5Zm-10 9 10 5 10-5M2 16l10 5 10-5"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/50-snapshot-view-pdf-desktop.png"><img src="https://archivebox.io/screenshots/50-snapshot-view-pdf-desktop.png" width="1600" height="1000" loading="lazy" alt="Saved page with multiple capture formats"></a>
|
||||
</div>
|
||||
<h3>Capture changes over time</h3>
|
||||
<p>ArchiveBox can <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Scheduled-Archiving">import new URLs and capture snapshots on a schedule</a>. Compare snapshots over time to see how sites have changed.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z"/><path d="M3 9h18"/></svg></span>
|
||||
<a class="card-thumbnail" href="./assets/archive-files-finder.png"><img src="./assets/archive-files-finder.png" width="1044" height="492" loading="lazy" alt="Archived HTML and folders in Finder"></a>
|
||||
</div>
|
||||
<h3>Designed to last 100yr+</h3>
|
||||
<p>Snapshots are stored as ordinary files and folders, with metadata in SQLite and JSON. You can browse the collection without depending on a hosted service.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Multiple captures per URL</h3>
|
||||
<p>ArchiveBox can save rendered HTML, screenshots, PDFs, WARC files, article text, headers, favicons, media, subtitles, and source repositories.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Bring your sources</h3>
|
||||
<p>Import one URL, pipe text into the CLI, upload exported bookmarks, or schedule recurring pulls from RSS feeds and other text-based source lists.</p>
|
||||
</article>
|
||||
<article>
|
||||
<h3>Self-hosted by default</h3>
|
||||
<p>Run it as a Docker web app, use one-off CLI commands, or automate with APIs while keeping private and public material under your own policy.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="use-cases" class="section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Who it is for</p>
|
||||
<h2>Archiving workflows for individuals, professionals, and institutions.</h2>
|
||||
<h2>Powerful features for individuals, professionals, and institutions.</h2>
|
||||
</div>
|
||||
<div class="audience-grid">
|
||||
<article class="audience-card">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M6 3h12v18l-6-4-6 4V3Z"/></svg></span>
|
||||
<h3>Personal archivists and self-hosters</h3>
|
||||
<p>Save bookmarks, browser history, RSS feeds, social media, form content, videos, podcasts, music, photos, and personal knowledge collections.</p>
|
||||
<ul>
|
||||
@@ -152,17 +174,21 @@
|
||||
<li>Use the browser extension, CLI, Web UI, and scheduled imports together.</li>
|
||||
<li>Export static HTML or browse the filesystem directly.</li>
|
||||
</ul>
|
||||
<figure class="card-shot phone-pair"><a href="https://archivebox.github.io/ios-archivebox/" aria-label="See the ArchiveBox iPhone app and Safari extension"><img src="https://archivebox.github.io/ios-archivebox/docs/screenshots/share-iphone.png" width="1500" height="3000" loading="lazy" alt="iPhone share sheet confirming a URL was saved with tags"><img src="https://archivebox.github.io/ios-archivebox/docs/screenshots/extension-iphone.png?v=2" width="1500" height="3000" loading="lazy" alt="ArchiveBox’s Safari extension inside an iPhone frame"></a></figure>
|
||||
</article>
|
||||
<article class="audience-card">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v18M5 21h14M3 7h18M6 7l-4 8h8L6 7Zm12 0-4 8h8l-4-8Z"/></svg></span>
|
||||
<h3>Lawyers and journalists</h3>
|
||||
<p>Capture web pages, articles, source material, and public records while preserving reviewable copies outside of volatile platforms.</p>
|
||||
<p>Keep copies of articles, source material, and public records, even after the original pages change or disappear.</p>
|
||||
<ul>
|
||||
<li>Store screenshots, PDFs, headers, WARC files, and text extraction.</li>
|
||||
<li>Tag and review sources through the self-hosted web interface.</li>
|
||||
<li>Tune privacy, authentication, and publishing settings for casework.</li>
|
||||
<li>Use ZK proofs with <a href="https://tlsnotary.zervice.io/">TLSNotary</a> to prove content authenticity.</li>
|
||||
</ul>
|
||||
<figure class="card-shot"><a href="https://archivebox.io/screenshots/58-snapshot-view-tlsnotary-desktop.png"><img src="https://archivebox.io/screenshots/58-snapshot-view-tlsnotary-desktop.png" width="1600" height="1000" loading="lazy" alt="TLSNotary output verifying an archived response on the snapshot details page"></a></figure>
|
||||
</article>
|
||||
<article class="audience-card">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 5v16M12 5C9 2 5 2 2 3v16c3-1 7-1 10 2 3-3 7-3 10-2V3c-3-1-7-1-10 2Z"/></svg></span>
|
||||
<h3>Researchers and institutions</h3>
|
||||
<p>Support OSINT, social media research, AI-powered research agents, libraries, governments, and collection-building teams.</p>
|
||||
<ul>
|
||||
@@ -170,75 +196,171 @@
|
||||
<li>Keep machine-readable metadata in JSON and SQLite.</li>
|
||||
<li>Extend extraction pipelines through the ArchiveBox ecosystem.</li>
|
||||
</ul>
|
||||
<figure class="card-shot card-shot--crawl-options"><a href="https://archivebox.io/screenshots/05-add-urls-tablet.png"><img src="https://archivebox.io/screenshots/05-add-urls-tablet.png" width="1024" height="1366" loading="lazy" alt="Archive depth, domain and subpath scope, URL allowlist, and URL denylist options on the Add page"></a></figure>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="install" class="section install-section">
|
||||
<div class="install-copy">
|
||||
<p class="eyebrow">Recommended install</p>
|
||||
<h2>Start with Docker Compose.</h2>
|
||||
<p>Docker Compose is the recommended ArchiveBox setup for the easiest install and update path, better isolation, and bundled archiving dependencies like Chrome, wget, yt-dlp, SingleFile, and readability tools.</p>
|
||||
<div class="mini-links">
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Install#option-a-docker--docker-compose-setup-%EF%B8%8F">Docker install guide</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Docker">Docker usage wiki</a>
|
||||
<a href="https://raw.githubusercontent.com/ArchiveBox/ArchiveBox/dev/docker-compose.yml">docker-compose.yml</a>
|
||||
<section id="install" class="section install-section" aria-labelledby="install-title">
|
||||
<div class="section-heading"><p class="eyebrow">Get ArchiveBox</p><h2 id="install-title">Quickstart</h2><p>Choose how you want to run your archive. Docker Compose is recommended for most installs.</p></div>
|
||||
<div class="install-window">
|
||||
<div class="install-window-bar">
|
||||
<div class="install-window-controls" aria-hidden="true"><span></span><span></span><span></span></div>
|
||||
<span class="install-window-title">ArchiveBox — Quickstart</span>
|
||||
</div>
|
||||
<div class="install-tabs" aria-label="Installation methods">
|
||||
<a class="install-tab" id="install-tab-macos" href="#install-macos"><img src="https://archivebox.github.io/ios-archivebox/docs/icons/apple.svg" width="28" height="28" alt=""><span>macOS app</span></a>
|
||||
<a class="install-tab" id="install-tab-electron" href="#install-electron"><img src="./assets/install/archivebox-server.png" width="28" height="28" alt=""><span>Windows/Linux app</span></a>
|
||||
<a class="install-tab" data-group-start id="install-tab-compose" href="#install-compose"><img src="https://user-images.githubusercontent.com/511499/117447182-29758200-af0b-11eb-97bd-58723fee62ab.png" width="28" height="28" alt=""><span>Docker Compose</span></a>
|
||||
<a class="install-tab" id="install-tab-docker" href="#install-docker"><img src="https://user-images.githubusercontent.com/511499/117447182-29758200-af0b-11eb-97bd-58723fee62ab.png" width="28" height="28" alt=""><span>Docker</span></a>
|
||||
<a class="install-tab" data-group-start id="install-tab-uv" href="#install-uv"><img src="https://user-images.githubusercontent.com/511499/117447613-ba4c5d80-af0b-11eb-8f89-1d98e31b6a79.png" width="28" height="28" alt=""><span>pip / uv</span></a>
|
||||
<a class="install-tab" id="install-tab-apt" href="#install-apt"><img src="https://user-images.githubusercontent.com/511499/117448075-49597580-af0c-11eb-91ba-f34fff10096b.png" width="28" height="28" alt=""><span>apt</span></a>
|
||||
<a class="install-tab" id="install-tab-brew" href="#install-brew"><img src="https://user-images.githubusercontent.com/511499/117447803-f2ec3700-af0b-11eb-87d3-671d114f011d.png" width="28" height="28" alt=""><span>Homebrew</span></a>
|
||||
<a class="install-tab" id="install-tab-community" href="#install-community"><img src="https://user-images.githubusercontent.com/511499/118077361-f0616580-b381-11eb-973c-ee894a3349fb.png" width="28" height="28" alt=""><span>Other packages</span></a>
|
||||
<a class="install-tab" data-group-start id="install-tab-script" href="#install-script"><img src="https://user-images.githubusercontent.com/511499/117456282-08665e80-af16-11eb-91a1-8102eff54091.png" width="28" height="28" alt=""><span>curl | sh</span></a>
|
||||
<a class="install-tab" id="install-tab-platforms" href="#install-platforms"><img src="https://github.com/ArchiveBox/ArchiveBox/assets/511499/0c46e949-00fe-49c8-a613-ee14501c014c" width="28" height="28" alt=""><span>Self-hosting</span></a>
|
||||
<a class="install-tab" id="install-tab-hosting" href="#install-hosting"><img src="https://user-images.githubusercontent.com/511499/117448723-1663b180-af0d-11eb-837f-d43959227810.png" width="28" height="28" alt=""><span>Cloud hosting</span></a>
|
||||
<a class="install-tab" data-group-start id="install-tab-extension" href="#install-extension"><img src="./assets/install/browser-extension.png" width="28" height="28" alt=""><span>Browser Extension</span></a>
|
||||
</div>
|
||||
<div class="install-panel" id="install-compose" aria-labelledby="install-tab-compose">
|
||||
<figure class="install-art install-art--container"><div class="install-art-stage"><div class="install-art-route"><div class="install-art-tile"><img src="./assets/install/docker-desktop.png" alt="" class="" loading="lazy"><span>Docker Compose</span></div><span class="install-art-arrow" aria-hidden="true">+</span><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><a class="install-art-shot" href="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" aria-label="Enlarge ArchiveBox web interface"><img src="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" alt="ArchiveBox web interface" class="" loading="lazy"></a><span class="install-art-file">docker-compose.yml</span></div><figcaption>Recommended</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Create a directory and get the config</h4><p><a href="https://docs.docker.com/get-docker/">Install Docker</a> first.</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>mkdir -p ~/archivebox/data && cd ~/archivebox
|
||||
curl -fsSL 'https://docker-compose.archivebox.io' > docker-compose.yml</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Start ArchiveBox</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>docker compose pull
|
||||
docker compose up -d --wait</code></pre></div></div><p>A new collection initializes automatically.</p></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Finish setup and archive your first page</h4><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>docker compose exec archivebox archivebox add 'https://example.com'</code></pre></div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="command-card">
|
||||
<div class="step">
|
||||
<span>1</span>
|
||||
<div>
|
||||
<h3>Create a data directory</h3>
|
||||
<div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><span class="ab-prompt">$</span> <span class="ab-cmd">mkdir -p ~/archivebox/data && cd ~/archivebox</span></pre></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span>2</span>
|
||||
<div>
|
||||
<h3>Download Docker Compose config</h3>
|
||||
<div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><span class="ab-prompt">$</span> <span class="ab-cmd">curl -fsSL 'https://docker-compose.archivebox.io' > docker-compose.yml</span></pre></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span>3</span>
|
||||
<div>
|
||||
<h3>Start ArchiveBox (initializes automatically)</h3>
|
||||
<div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><span class="ab-prompt">$</span> <span class="ab-cmd">docker compose up -d --wait</span></pre></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span>4</span>
|
||||
<div>
|
||||
<h3>Add your first URL</h3>
|
||||
<div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><span class="ab-prompt">$</span> <span class="ab-cmd">docker compose exec archivebox archivebox add 'https://example.com'</span></pre></div></div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-macos" aria-labelledby="install-tab-macos">
|
||||
<figure class="install-art install-art--macos"><div class="install-art-stage"><div class="install-drag-card"><a class="install-art-tile" href="https://github.com/ArchiveBox/ios-archivebox/releases/latest/download/ArchiveBox.app.zip" style="color: inherit" aria-label="Download ArchiveBox.app for macOS"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox.app</span></a><span class="install-art-arrow" aria-hidden="true">→</span><div class="install-art-tile"><img src="./assets/install/applications-folder.png" alt="" class="" loading="lazy"><span>Applications</span></div></div><a class="install-art-shot" href="https://archivebox.github.io/ios-archivebox/docs/screenshots/server-mac.png" aria-label="Enlarge ArchiveBox Server on macOS"><img src="https://archivebox.github.io/ios-archivebox/docs/screenshots/server-mac.png" alt="ArchiveBox Server on macOS" class="" loading="lazy"></a></div><figcaption>macOS 26+ · Apple Silicon</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Download and open the app</h4><a class="button primary install-download" href="https://github.com/ArchiveBox/ios-archivebox/releases/latest/download/ArchiveBox.app.zip"><svg width="30" height="40" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 7.3.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2026 Fonticons, Inc. --><path fill="currentColor" d="M319.1 268.7c-.2-36.7 16.4-64.4 50-84.8-18.8-26.9-47.2-41.7-84.7-44.6-35.5-2.8-74.3 20.7-88.5 20.7-15 0-49.4-19.7-76.4-19.7-55.8 .9-115.1 44.5-115.1 133.2 0 26.2 4.8 53.3 14.4 81.2 12.8 36.7 59 126.7 107.2 125.2 25.2-.6 43-17.9 75.8-17.9 31.8 0 48.3 17.9 76.4 17.9 48.6-.7 90.4-82.5 102.6-119.3-65.2-30.7-61.7-90-61.7-91.9zM262.5 104.5c27.3-32.4 24.8-61.9 24-72.5-24.1 1.4-52 16.4-67.9 34.9-17.5 19.8-27.8 44.3-25.6 71.9 26.1 2 49.9-11.4 69.5-34.3z"/></svg><span>Download ArchiveBox.app</span><svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12m-5-5 5 5 5-5M5 16v4h14v-4"/></svg></a><p>Move it to Applications, and open it.</p></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Follow the setup guide</h4><p>The app’s setup wizard helps you start a server on your Mac or connect to an existing one.</p></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Connect your apps</h4><p>Use the <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#ui-usage">Web UI</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-up-Authentication#rest-api">REST API</a>, or <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#cli-usage">CLI</a>. Connect the <a href="https://archivebox.github.io/ios-archivebox/">mobile app</a>, <a href="https://archivebox.github.io/archivebox-browser-extension/">browser extension</a>, and other clients using your server URL and API key.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-docker" aria-labelledby="install-tab-docker">
|
||||
<figure class="install-art install-art--container"><div class="install-art-stage"><div class="install-art-route"><div class="install-art-tile"><img src="./assets/install/docker-desktop.png" alt="" class="" loading="lazy"><span>Docker</span></div><span class="install-art-arrow" aria-hidden="true">+</span><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><a class="install-art-shot" href="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" aria-label="Enlarge ArchiveBox web interface"><img src="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" alt="ArchiveBox web interface" class="" loading="lazy"></a></div><figcaption>One container. Your archive.</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Create a collection and start the server</h4><p><a href="https://docs.docker.com/get-docker/">Install Docker</a> first.</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>mkdir -p ~/archivebox/data && cd ~/archivebox/data
|
||||
docker run -d --name archivebox -v "$PWD:/data" -p 8000:8000 archivebox/archivebox:dev</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Finish setup</h4><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Archive your first page</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>docker exec archivebox archivebox add 'https://example.com'</code></pre></div></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-script" aria-labelledby="install-tab-script">
|
||||
<figure class="install-art install-art--script"><div class="install-art-stage"><div class="install-script-card"><span class="install-script-prompt">$</span><code>curl <span>get.archivebox.io</span><br> | sh</code><div class="install-script-progress" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></div></div><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><figcaption>One command to get started</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Run the setup script</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>curl -fsSL 'https://get.archivebox.io' | bash</code></pre></div></div><p>You can <a href="https://github.com/ArchiveBox/ArchiveBox/blob/dev/bin/setup.sh">read the script</a> before running it.</p></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Follow the prompts and finish setup</h4><p>Follow the installer’s instructions to start using your collection.</p><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-uv" aria-labelledby="install-tab-uv">
|
||||
<figure class="install-art install-art--package"><div class="install-art-stage"><div class="install-package-card"><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/117447613-ba4c5d80-af0b-11eb-8f89-1d98e31b6a79.png" alt="" class="" loading="lazy"><span>pip / uv</span></div><span class="install-package-line" aria-hidden="true"></span><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><div class="install-art-chips"><span>HTML</span><span>PDF</span><span>PNG</span><span>WARC</span></div></div><figcaption>Python package</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Install the Python package</h4><p><a href="https://docs.astral.sh/uv/getting-started/installation/">Install uv</a> first.</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>uv tool install --python 3.13 --prerelease explicit --upgrade 'archivebox>=0.9.0rc0,<0.10'
|
||||
archivebox version</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Create a collection and start the server</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>mkdir -p ~/archivebox/data && cd ~/archivebox/data
|
||||
archivebox init
|
||||
archivebox install
|
||||
archivebox server 0.0.0.0:8000</code></pre></div></div></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Finish setup</h4><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-apt" aria-labelledby="install-tab-apt">
|
||||
<figure class="install-art install-art--package"><div class="install-art-stage"><div class="install-package-card"><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/117448075-49597580-af0c-11eb-91ba-f34fff10096b.png" alt="" class="" loading="lazy"><span>apt</span></div><span class="install-package-line" aria-hidden="true"></span><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><div class="install-art-chips"><span>HTML</span><span>PDF</span><span>PNG</span><span>WARC</span></div></div><figcaption>Ubuntu / Debian</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Add the repository and install</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>echo 'deb [trusted=yes] https://archivebox.github.io/debian-archivebox dev main' | sudo tee /etc/apt/sources.list.d/archivebox.list
|
||||
sudo apt update
|
||||
sudo apt install archivebox
|
||||
(cd /tmp && archivebox version)</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Create a collection and start the server</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>mkdir -p ~/archivebox/data && cd ~/archivebox/data
|
||||
archivebox init
|
||||
sudo archivebox install
|
||||
archivebox server 0.0.0.0:8000</code></pre></div></div></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Finish setup</h4><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-brew" aria-labelledby="install-tab-brew">
|
||||
<figure class="install-art install-art--package"><div class="install-art-stage"><div class="install-package-card"><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/117447803-f2ec3700-af0b-11eb-87d3-671d114f011d.png" alt="" class="" loading="lazy"><span>Homebrew</span></div><span class="install-package-line" aria-hidden="true"></span><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div><div class="install-art-chips"><span>HTML</span><span>PDF</span><span>PNG</span><span>WARC</span></div></div><figcaption>macOS / Linux</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Install from the ArchiveBox tap</h4><p><a href="https://brew.sh/#install">Install Homebrew</a> first. Run these commands as your normal user, without sudo.</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>brew tap archivebox/archivebox
|
||||
brew trust archivebox/archivebox
|
||||
brew install archivebox
|
||||
archivebox version</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Create a collection and start the server</h4><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>mkdir -p ~/archivebox/data && cd ~/archivebox/data
|
||||
archivebox init
|
||||
archivebox install
|
||||
archivebox server 0.0.0.0:8000</code></pre></div></div></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Finish setup</h4><p>Open <a href="http://admin.archivebox.localhost:8000/admin/">the admin UI</a> to create your first admin account and finish the setup wizard. On a remote server, open <code>/admin/</code> on its hostname or IP instead.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-community" aria-labelledby="install-tab-community">
|
||||
<figure class="install-art install-art--community"><div class="install-art-stage"><div class="install-art-platforms"><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/118077361-f0616580-b381-11eb-973c-ee894a3349fb.png" alt="" class="" loading="lazy"><span>Arch Linux</span></div><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/118077946-29e6a080-b383-11eb-94f0-d4871da08c3f.png" alt="" class="" loading="lazy"><span>FreeBSD</span></div><div class="install-art-tile"><img src="https://user-images.githubusercontent.com/511499/118077861-002d7980-b383-11eb-86a7-5936fad9190f.png" alt="" class="" loading="lazy"><span>Nix</span></div><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div></div></div><figcaption>Community packages</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Choose your platform</h4><p>Community packages may lag behind the Docker and Python releases.</p><p><a href="https://aur.archlinux.org/packages/archivebox/">Arch Linux (AUR)</a></p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>yay -S archivebox</code></pre></div></div><p>FreeBSD (uv shortcut)</p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>curl -fsSL 'https://get.archivebox.io' | bash</code></pre></div></div><p><a href="https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/misc/archivebox/default.nix">Nix</a></p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>nix-env --install archivebox</code></pre></div></div><p><a href="https://packages.guix.gnu.org/packages/archivebox/">Guix</a></p><div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><code>guix install archivebox</code></pre></div></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Set up your collection</h4><p>Follow your package’s setup instructions, then use the <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#cli-usage">CLI usage guide</a> to initialize and manage your archive.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-electron" aria-labelledby="install-tab-electron">
|
||||
<figure class="install-art install-art--desktop"><div class="install-art-stage"><div class="install-desktop-base"><div class="install-art-tile"><img src="./assets/install/docker-desktop.png" alt="" class="" loading="lazy"><span>Docker Desktop</span></div></div><a class="install-desktop-shot" href="https://github.com/ArchiveBox/ArchiveBox/assets/511499/575ef92f-bb3e-4a7c-a4ba-986c1fd76ecf"><img src="https://github.com/ArchiveBox/ArchiveBox/assets/511499/575ef92f-bb3e-4a7c-a4ba-986c1fd76ecf" alt="ArchiveBox desktop app running, with its menu and Add URLs window" class="" loading="lazy"></a></div><figcaption>Windows / Linux · Desktop app preview</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Install Docker Desktop</h4><p><a href="https://www.docker.com/products/docker-desktop/">Download Docker Desktop</a> and start it on your computer.</p></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Download or build the app</h4><p>Follow the <a href="https://github.com/ArchiveBox/electron-archivebox#quickstart">Windows / Linux app setup instructions</a>.</p><p>This is an alpha project; contributors are welcome.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-platforms" aria-labelledby="install-tab-platforms">
|
||||
<figure class="install-art install-art--server"><div class="install-art-stage"><svg class="install-server-rack" viewBox="0 0 160 180" aria-hidden="true"><rect x="18" y="12" width="124" height="156" rx="12"/><rect x="32" y="28" width="96" height="34" rx="5"/><rect x="32" y="73" width="96" height="34" rx="5"/><rect x="32" y="118" width="96" height="34" rx="5"/><path d="M47 45h43m-43 45h43m-43 45h43"/><circle cx="111" cy="45" r="4"/><circle cx="111" cy="90" r="4"/><circle cx="111" cy="135" r="4"/></svg><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div><div class="install-art-chips"><span>NAS</span><span>Home server</span></div></div><figcaption>On your own hardware</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Choose your platform</h4><p>Community integrations may lag behind the Docker and Python releases.</p><div class="mini-links"><a href="https://unraid.net/community/apps?q=archivebox#r">Unraid</a><a href="https://community-scripts.github.io/ProxmoxVE/scripts?id=archivebox">Proxmox</a><a href="https://github.com/YunoHost-Apps/archivebox_ynh">YunoHost</a><a href="https://www.cloudron.io/store/io.archivebox.cloudronapp.html">Cloudron</a><a href="https://docs.saltbox.dev/sandbox/apps/archivebox/">Saltbox</a><a href="https://portainer-templates.as93.net/archivebox">Portainer</a><a href="https://runtipi.io/docs/apps-available">Runtipi</a></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Install and open ArchiveBox</h4><p>Follow the platform’s installation guide, configure persistent storage, then open the app to finish setup.</p><p>For TrueNAS, see the <a href="https://github.com/ArchiveBox/ArchiveBox#quickstart">README’s platform notes</a> before choosing an integration.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-hosting" aria-labelledby="install-tab-hosting">
|
||||
<figure class="install-art install-art--cloud"><div class="install-art-stage"><svg class="install-cloud" viewBox="0 0 240 160" aria-hidden="true"><path d="M62 125a40 40 0 0 1-5-80 62 62 0 0 1 117-5 43 43 0 0 1 9 85Z"/><path d="M120 128v26m-58 0h116"/></svg><div class="install-art-tile"><img src="./assets/install/archivebox-server.png" alt="" class="" loading="lazy"><span>ArchiveBox</span></div><div class="install-art-chips"><span>Your server</span><span>Anywhere</span></div></div><figcaption>Cloud hosting / VPS</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Choose a provider</h4><div class="mini-links"><a href="https://elest.io/open-source/archivebox">Elest.io</a><a href="https://www.stellarhosted.com/archivebox/">StellarHosted</a><a href="https://www.pikapods.com/pods?run=archivebox">PikaPods</a></div><p>Check the provider’s current plans, supported versions, and storage options.</p></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Deploy and finish setup</h4><p>Use the provider’s ArchiveBox deployment flow, then open your instance to create an admin account. For an unmanaged VPS, follow the Docker Compose quickstart on your server.</p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="install-panel" id="install-extension" aria-labelledby="install-tab-extension">
|
||||
<figure class="install-art install-art--extension"><div class="install-art-stage"><a class="install-art-shot" href="https://archivebox.github.io/archivebox-browser-extension/screenshots/saved-urls-desktop.png" aria-label="Enlarge ArchiveBox browser extension saved URLs"><img src="https://archivebox.github.io/archivebox-browser-extension/screenshots/saved-urls-desktop.png" alt="ArchiveBox browser extension saved URLs" class="" loading="lazy"></a><div class="install-art-route"><div class="install-art-tile"><img src="./assets/install/browser-extension.png" alt="" class="" loading="lazy"><span>Save from your browser</span></div></div></div><figcaption>Chrome · Firefox · Edge · Safari</figcaption></figure>
|
||||
<div class="command-card">
|
||||
<div class="step"><span>1</span><div><h4>Install the browser extension</h4><div class="mini-links"><a href="https://chrome.google.com/webstore/detail/habonpimjphpdnmcfkaockjnffodikoj">Chrome / Brave</a><a href="https://addons.mozilla.org/firefox/addon/archivebox-exporter/">Firefox</a><a href="https://microsoftedge.microsoft.com/addons/detail/archivebox/dmlljpjhnfjgchbkcgheebcffocgooeh">Edge</a><a href="https://archivebox.github.io/ios-archivebox/">Safari / iOS</a></div></div></div>
|
||||
<div class="step"><span>2</span><div><h4>Connect your ArchiveBox server</h4><p>Open the extension’s Configuration page, enter your server URL and API key, then test the connection. Use one of the server install tabs if you don’t have a server yet.</p></div></div>
|
||||
<div class="step"><span>3</span><div><h4>Save a page</h4><p>Open a page, click the ArchiveBox extension, and add your tags. You can also import bookmarks and history from the extension’s options.</p><p><a href="https://archivebox.github.io/archivebox-browser-extension/">Extension guide ↗</a></p></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section compact-docs" aria-labelledby="other-installs-title">
|
||||
<h2 id="other-installs-title">Other install paths</h2>
|
||||
<p>ArchiveBox can also run with plain Docker, pip, brew, deb packages, or the optional setup script. Docker Compose remains the default recommendation, especially when you want bundled dependencies and clean upgrades.</p>
|
||||
<div class="doc-link-grid">
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Install">Bare metal install</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox#quickstart">README quickstart</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#cli-usage">CLI usage</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration">Configuration</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="configuration" class="section deep-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Configuration</p>
|
||||
<h2>Configure ArchiveBox with powerful options.</h2>
|
||||
<p>ArchiveBox can be configured with environment variables, the <code>archivebox config</code> CLI, or by editing <code>./ArchiveBox.conf</code>. The same configuration model works in Docker, Docker Compose, bare-metal installs, scheduled jobs, and one-off CLI runs.</p>
|
||||
<div class="section-heading configuration-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Configuration</p>
|
||||
<h2>50+ plugins & flexible configuration options.</h2>
|
||||
<p><a href="https://abx-plugins.archivebox.io/"><strong>Browse plugins and extractors ↗</strong></a></p>
|
||||
</div>
|
||||
<ul class="plugin-stack" aria-label="Featured plugins">
|
||||
<li><a href="https://abx-plugins.archivebox.io/#chrome" aria-label="Chrome plugin" title="Chrome"><img src="./assets/plugins/chrome.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#ublock" aria-label="uBlock Origin plugin" title="uBlock Origin"><img src="./assets/plugins/ublock.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#git" aria-label="GitHub / Git plugin" title="GitHub / Git"><img src="./assets/plugins/github.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#archivedotorg" aria-label="Internet Archive plugin" title="Internet Archive"><img src="./assets/plugins/archive-org.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#claudecode" aria-label="Claude / Anthropic plugin" title="Claude / Anthropic"><img src="./assets/plugins/claude.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#archivewebpage" aria-label="Webrecorder plugin" title="Webrecorder"><img src="./assets/plugins/webrecorder.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#singlefile" aria-label="SingleFile plugin" title="SingleFile"><img src="./assets/plugins/singlefile.png" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://abx-plugins.archivebox.io/#ytdlp" aria-label="YouTube / yt-dlp plugin" title="YouTube / yt-dlp"><img src="./assets/plugins/youtube.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://tailscale.com/" aria-label="Tailscale" title="Tailscale"><img src="./assets/plugins/tailscale.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://tlsnotary.zervice.io/" aria-label="TLSNotary" title="TLSNotary"><img src="./assets/plugins/tlsnotary.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
</ul>
|
||||
<p class="configuration-description">ArchiveBox can be configured via the admin UI, CLI, <code>ArchiveBox.conf</code>, or by importing config and cookies from Chrome / other browsers. The same configuration model works in Docker, Docker Compose, bare-metal installs, scheduled jobs, and one-off CLI runs.</p>
|
||||
</div>
|
||||
<div class="prose-grid">
|
||||
<article>
|
||||
<h3>Common settings people search for</h3>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M4 3v7m0 4v7M12 3v11m0 4v3M20 3v3m0 4v11M1 10h6m2 8h6m2-12h6"/></svg></span>
|
||||
<h3>Adjust how pages are captured</h3>
|
||||
<p>Use <code>TIMEOUT</code> for slow networks, <code>CHECK_SSL_VALIDITY</code> for sites with broken certificates, <code>PUBLIC_INDEX</code>, <code>PUBLIC_SNAPSHOTS</code>, and <code>PUBLIC_ADD_VIEW</code> for publishing policy, and browser user-agent settings for sites that block obvious bots.</p>
|
||||
<p>For authenticated or difficult sites, review <code>CHROME_USER_DATA_DIR</code>, <code>COOKIES_FILE</code>, <code>CHROME_USER_AGENT</code>, <code>WGET_USER_AGENT</code>, and <code>CURL_USER_AGENT</code>. Public archive operators should also configure instance branding and contact details with settings like <code>FOOTER_INFO</code> and <code>CUSTOM_TEMPLATES_DIR</code>.</p>
|
||||
<div class="ab-terminal">
|
||||
<div class="ab-terminal__bar">
|
||||
<div class="ab-terminal__dots"><span class="ab-terminal__dot" aria-hidden="true"> </span><span class="ab-terminal__dot" aria-hidden="true"> </span><span class="ab-terminal__dot" aria-hidden="true"> </span></div>
|
||||
@@ -254,6 +376,7 @@
|
||||
</div>
|
||||
</article>
|
||||
<article>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M8 3v5m8-5v5M6 8h12v4a6 6 0 0 1-12 0V8Zm6 10v4"/></svg></span>
|
||||
<h3>Dependencies and extractors</h3>
|
||||
<p>ArchiveBox uses standard tools like Chrome or Chromium, wget, curl, yt-dlp, git, SingleFile, Readability, and article parsers. Docker bundles these dependencies for easier upgrades and better isolation; non-Docker installs can run <code>archivebox install</code> and <code>archivebox --version</code> to check what is available.</p>
|
||||
<ul class="readme-list">
|
||||
@@ -269,22 +392,45 @@
|
||||
</section>
|
||||
|
||||
<section class="section data-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Inputs and outputs</p>
|
||||
<h2>Feed it URLs from any source. Save redundant, portable captures.</h2>
|
||||
<div class="section-heading integration-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Inputs and outputs</p>
|
||||
<h2>Integrate with tools you already use.</h2>
|
||||
</div>
|
||||
<ul class="plugin-stack integration-stack" aria-label="Tools and integrations">
|
||||
<li><a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone" aria-label="Google Drive" title="Google Drive"><img src="./assets/integrations/google-drive.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://n8n.io/" aria-label="n8n" title="n8n"><img src="./assets/integrations/n8n.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://openai.com/codex/" aria-label="Codex" title="Codex"><img src="./assets/integrations/codex.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://claude.com/product/claude-code" aria-label="Claude Code" title="Claude Code"><img src="./assets/integrations/claude-code.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://slack.com/" aria-label="Slack" title="Slack"><img src="./assets/integrations/slack.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone" aria-label="AWS S3" title="AWS S3"><img src="./assets/integrations/aws-s3-wordmark.svg" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
<li><a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ldap_enabled" aria-label="LDAP" title="LDAP"><img src="./assets/integrations/ldap.png" width="44" height="44" loading="lazy" alt=""></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="data-grid">
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v12m-5-5 5 5 5-5M4 16v5h16v-5"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/05-add-urls-desktop.png"><img src="https://archivebox.io/screenshots/05-add-urls-desktop.png" width="1600" height="1000" loading="lazy" alt="Add URLs to ArchiveBox"></a>
|
||||
</div>
|
||||
<h3>Inputs</h3>
|
||||
<p>Archive one URL at a time or schedule imports from bookmarks, browser history, RSS, JSON, CSV, TXT, SQL, HTML, Markdown, Pocket, Pinboard, Instapaper, Shaarli, Wallabag, and more.</p>
|
||||
<p>Archive <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-single-url">one URL at a time</a> or <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Scheduled-Archiving">schedule imports</a> from <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Quickstart#2-get-your-list-of-urls-to-archive">bookmarks</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-list-of-links-from-browser-history">browser history</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">RSS</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">JSON</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">CSV</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">TXT</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">SQL</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">HTML</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#import-a-list-of-urls-from-a-text-file">Markdown</a>, <a href="https://support.mozilla.org/en-US/kb/exporting-your-pocket-list">Pocket</a>, <a href="https://pinboard.in/export/">Pinboard</a>, <a href="https://www.instapaper.com/user">Instapaper</a>, <a href="https://github.com/shaarli/Shaarli/blob/master/doc/md/Usage.md#importexport">Shaarli</a>, <a href="https://doc.wallabag.org/user/import/wallabagv2/">Wallabag</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Quickstart#2-get-your-list-of-urls-to-archive">and more</a>.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M14 2H5v20h14V7l-5-5Zm0 0v5h5M8 12h8m-8 4h6"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/11-snapshot-files-desktop.png"><img src="https://archivebox.io/screenshots/11-snapshot-files-desktop.png" width="1600" height="1000" loading="lazy" alt="Files saved for an archived page"></a>
|
||||
</div>
|
||||
<h3>Outputs</h3>
|
||||
<p>Each snapshot can include original HTML, rendered single-file HTML, PDF, screenshot PNG, WARC, title, article text, favicon, headers, media, subtitles, metadata, thumbnails, and git clones.</p>
|
||||
<p>Each snapshot can include <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#wget_enabled">original HTML</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#singlefile_enabled">rendered single-file HTML</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#pdf_enabled">PDF</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#screenshot_enabled">screenshot PNG</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#wget_enabled">WARC</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#title_enabled">title</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#readability_enabled">article text</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#favicon_enabled">favicon</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#headers_enabled">headers</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ytdlp_enabled">media</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ytdlp_enabled">subtitles</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#disk-layout">metadata</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ytdlp_enabled">thumbnails</a>, and <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#git_enabled">git clones</a>.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8m-4-4v4"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png"><img src="https://archivebox.io/screenshots/09-snapshots-grid-desktop.png" width="1600" height="1000" loading="lazy" alt="Browse an archive in the Web UI"></a>
|
||||
</div>
|
||||
<h3>Access</h3>
|
||||
<p>Manage the same collection through the Web UI, CLI, REST API, Python API, SQLite, or the data folder itself. The tools are complementary, not separate products.</p>
|
||||
<p>Manage the same collection through the <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#ui-usage">Web UI</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#cli-usage">CLI</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-up-Authentication#rest-api">REST API</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#python-api-usage">Python API</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#sql-shell-usage">SQLite</a>, or the <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#disk-layout">data folder</a> itself. Use whichever fits your workflow.</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
@@ -292,35 +438,21 @@
|
||||
<section id="layout-security" class="section deep-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Disk layout, exporting, and security</p>
|
||||
<h2>A normal folder, a SQLite index, and files you can inspect without ArchiveBox.</h2>
|
||||
<p>All ArchiveBox state for a collection lives in one data folder: the SQLite database, configuration, logs, and archived content. Snapshots are organized on disk as ordinary files and folders so they can be backed up, searched, published carefully, or browsed by hand.</p>
|
||||
<h2>Browse your captures as normal files without needing ArchiveBox.</h2>
|
||||
<p>Your captures are ordinary HTML, images, PDFs, and media files. Open them from Finder, search them with any filesystem search tools, let AI agents browse them directly, and back them up as regular files.</p>
|
||||
</div>
|
||||
<div class="prose-grid prose-grid--wide">
|
||||
<article>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7Z"/><path d="M3 9h18"/></svg></span>
|
||||
<h3>Archive layout</h3>
|
||||
<div class="ab-terminal">
|
||||
<div class="ab-terminal__bar">
|
||||
<div class="ab-terminal__dots"><span class="ab-terminal__dot" aria-hidden="true"> </span><span class="ab-terminal__dot" aria-hidden="true"> </span><span class="ab-terminal__dot" aria-hidden="true"> </span></div>
|
||||
<span>~/archivebox/data</span>
|
||||
</div>
|
||||
<div class="ab-terminal__body">
|
||||
<pre><span class="ab-out">data/</span>
|
||||
<span class="ab-out"> index.sqlite3</span> <span class="ab-dim"># main metadata database</span>
|
||||
<span class="ab-out"> ArchiveBox.conf</span> <span class="ab-dim"># collection configuration</span>
|
||||
<span class="ab-out"> archive/</span>
|
||||
<span class="ab-out"> 1617687755/</span>
|
||||
<span class="ab-out"> index.html</span>
|
||||
<span class="ab-out"> index.json</span>
|
||||
<span class="ab-out"> screenshot.png</span>
|
||||
<span class="ab-out"> output.pdf</span>
|
||||
<span class="ab-out"> warc/1617687755.warc.gz</span>
|
||||
<span class="ab-out"> media/some_video.mp4</span>
|
||||
<span class="ab-out"> git/somerepo.git</span></pre>
|
||||
</div>
|
||||
</div>
|
||||
<p>Each snapshot folder includes static <code>index.html</code> and <code>index.json</code> metadata plus extractor outputs such as HTML, PDFs, screenshots, WARC files, media, subtitles, headers, favicons, article text, and git repositories.</p>
|
||||
<p>Each snapshot has a folder for every capture method. HTML lives in folders such as <code>dom/</code> and <code>singlefile/</code>; images, PDFs, and media have their own folders too.</p>
|
||||
<p>Snapshot metadata is saved alongside the outputs. Your collection’s database and configuration live outside the individual snapshot folders.</p>
|
||||
<figure class="finder-shot">
|
||||
<a href="./assets/archive-files-finder.png"><img src="./assets/archive-files-finder.png" width="1044" height="492" loading="lazy" alt="macOS Finder with the date, news.ycombinator.com, and snapshot folders expanded down to dom/output.html, with the saved HTML file selected"></a>
|
||||
</figure>
|
||||
</article>
|
||||
<article>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M14 2H5v20h14V7l-5-5Zm0 0v5h5M8 12h8m-8 4h6"/></svg></span>
|
||||
<h3>Static exports and publishing</h3>
|
||||
<p>You can export the archive index as static HTML, JSON, or CSV with <code>archivebox list</code> so collections can be reviewed without running the web server. Keep generated exports next to the <code>archive/</code> folder so relative snapshot paths continue to work.</p>
|
||||
<div class="ab-terminal ab-terminal--inline"><div class="ab-terminal__body"><pre><span class="ab-prompt">$</span> <span class="ab-cmd">archivebox list --html --with-headers > index.html</span>
|
||||
@@ -337,79 +469,52 @@
|
||||
|
||||
<div class="notice-grid">
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="4" y="10" width="16" height="12" rx="2"/><path d="M8 10V6a4 4 0 0 1 8 0v4m-4 5v3"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/02-login-desktop.png"><img src="https://archivebox.io/screenshots/02-login-desktop.png" width="1600" height="1000" loading="lazy" alt="ArchiveBox sign-in page"></a>
|
||||
</div>
|
||||
<h3>Private content</h3>
|
||||
<p>If you archive private URLs, paywalled pages, unlisted media, Google Docs, or browser sessions, assume snapshot viewers may see private URLs, cookies, session tokens, headers, and page content unless you configure access carefully.</p>
|
||||
<p>Restrict public access with <code>PUBLIC_INDEX=False</code>, <code>PUBLIC_SNAPSHOTS=False</code>, and <code>PUBLIC_ADD_VIEW=False</code>, then create authenticated users with <code>archivebox manage createsuperuser</code>.</p>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Security-Overview">Read the security overview</a>
|
||||
<p>Archive private URLs, paywalled pages, unlisted media, and Google Docs using an <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Chromium-Install#setting-up-a-chromium-user-profile">imported Chrome profile</a> or a <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Chromium-Install#non-docker-setup-local-host">dedicated browser persona</a>. Choose which captures stay private and who can access them.</p>
|
||||
<p>Restrict public access with <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#public_index"><code>PUBLIC_INDEX=False</code></a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#permissions"><code>PERMISSIONS=private</code></a>, and <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#public_add_view"><code>PUBLIC_ADD_VIEW=False</code></a>, then create authenticated users with <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-up-Authentication#username--password-the-default"><code>archivebox manage createsuperuser</code></a>.</p>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Security-Overview#publishing">Read the security overview</a>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="m7 5-6 7 6 7m10-14 6 7-6 7M14 3l-4 18"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/49-snapshot-view-dom-desktop.png"><img src="https://archivebox.io/screenshots/49-snapshot-view-dom-desktop.png" width="1600" height="1000" loading="lazy" alt="Archived page rendered from saved HTML"></a>
|
||||
</div>
|
||||
<h3>Archived JavaScript</h3>
|
||||
<p>Archived pages that execute JavaScript can make requests from the same domain as the web UI when viewed. If this risk matters for your collection, review the publishing guidance and consider disabling extractor outputs that execute archived JS when opened.</p>
|
||||
<p><code>archivebox config --set SAVE_WGET=False SAVE_DOM=False</code></p>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/issues/239">Read Issue #239</a>
|
||||
<p>ArchiveBox uses a <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Chromium-Install#chrome--chromium-setup">Chrome browser</a> during archiving to run JavaScript and capture the rendered page.</p>
|
||||
<p><a href="https://archiveweb.page/guide">ArchiveWeb.page</a> records pages for replay, including their scripts and network responses. Replay captured pages with JavaScript using <a href="https://replayweb.page/docs/user-guide/">ReplayWeb.page</a>, Webrecorder’s archive viewer.</p>
|
||||
</article>
|
||||
<article>
|
||||
<div class="card-media">
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 4 18 4 18 0V5M3 12c0 4 18 4 18 0"/></svg></span>
|
||||
<a class="card-thumbnail" href="https://archivebox.io/screenshots/10-snapshot-admin-detail-desktop.png"><img src="https://archivebox.io/screenshots/10-snapshot-admin-detail-desktop.png" width="1600" height="1000" loading="lazy" alt="Snapshot details and saved archive size"></a>
|
||||
</div>
|
||||
<h3>Storage requirements</h3>
|
||||
<p>ArchiveBox can use roughly 1 GB to 50 GB per 1,000 snapshots depending on media, video, audio, and extractor settings. Tune <code>YTDLP_ENABLED</code> and <code>YTDLP_MAX_SIZE</code> for media-heavy collections.</p>
|
||||
<p>Keep <code>index.sqlite3</code> on local storage or SSD when possible. Large <code>archive/</code> folders can live on NFS, SMB, FUSE, S3-backed, or HDD storage, but Docker and fileshare setups may need ownership and root-squash adjustments. Avoid older filesystems like EXT3 or FAT for very large archives.</p>
|
||||
<p>ArchiveBox can use roughly 1 GB to 50 GB per 1,000 snapshots depending on media, video, audio, and extractor settings. Tune <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ytdlp_enabled"><code>YTDLP_ENABLED</code></a> and <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration#ytdlp_max_size"><code>YTDLP_MAX_SIZE</code></a> for media-heavy collections.</p>
|
||||
<p>Keep <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#supported-remote-filesystems"><code>index.sqlite3</code></a> on local storage or SSD when possible. Large <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#supported-remote-filesystems"><code>archive/</code></a> folders can live on <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone">NFS</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone">SMB</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone">FUSE</a>, <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#rclone">S3-backed</a>, or <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#supported-local-filesystems">HDD storage</a>, but Docker and fileshare setups may need <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#nfs">ownership and root-squash adjustments</a>. Avoid older filesystems like <a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-Up-Storage#ext2-ext3-fat32-exfat">EXT3 or FAT</a> for very large archives.</p>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage#large-archives">Plan for large archives</a>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="ecosystem" class="section ecosystem">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Ecosystem</p>
|
||||
<h2>Core projects that make ArchiveBox extensible.</h2>
|
||||
</div>
|
||||
<div class="project-grid">
|
||||
<article>
|
||||
<h3>abx-plugins</h3>
|
||||
<p>Extractor and plugin packages used to preserve more types of content.</p>
|
||||
<div>
|
||||
<a href="https://github.com/ArchiveBox/abx-plugins">GitHub</a>
|
||||
<a href="https://archivebox.github.io/abx-plugins/">Docs</a>
|
||||
</div>
|
||||
</article>
|
||||
<article>
|
||||
<h3>abx-dl</h3>
|
||||
<p>Download and extraction tooling for saving web content and media.</p>
|
||||
<div>
|
||||
<a href="https://github.com/ArchiveBox/abx-dl">GitHub</a>
|
||||
</div>
|
||||
</article>
|
||||
<article>
|
||||
<h3>abxpkg</h3>
|
||||
<p>Runtime package management for dependencies used by ArchiveBox and plugins.</p>
|
||||
<div>
|
||||
<a href="https://github.com/ArchiveBox/abxpkg">GitHub</a>
|
||||
<a href="https://archivebox.github.io/abxpkg/">Docs</a>
|
||||
</div>
|
||||
</article>
|
||||
<article>
|
||||
<h3>abxbus</h3>
|
||||
<p>Event bus infrastructure for ArchiveBox automation and integrations.</p>
|
||||
<div>
|
||||
<a href="https://github.com/ArchiveBox/abxbus">GitHub</a>
|
||||
<a href="https://abxbus.archivebox.io">Site</a>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="background" class="section deep-section">
|
||||
<div class="section-heading">
|
||||
<p class="eyebrow">Background and motivation</p>
|
||||
<h2>Built for decentralized preservation.</h2>
|
||||
<h2>Keep a copy of the web you care about.</h2>
|
||||
<p>ArchiveBox exists because link rot, platform churn, censorship, and disappearing media routinely erase useful knowledge. The project aims to make the web content you care about viewable with common software in 50 to 100 years, without requiring ArchiveBox or a hosted replay service to understand your files.</p>
|
||||
</div>
|
||||
<div class="prose-grid">
|
||||
<article>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="7" rx="2"/><rect x="3" y="14" width="18" height="7" rx="2"/><path d="M7 6.5h.01M7 17.5h.01M11 6.5h6M11 17.5h6"/></svg></span>
|
||||
<h3>Why self-host?</h3>
|
||||
<p>Centralized public archives are essential, but not every page belongs in a global public service. ArchiveBox lets individuals and organizations save public or private material they can access, keep it locally or within their institution, and decide what to publish case by case.</p>
|
||||
<p>The project differentiates itself by combining a comprehensive CLI, a self-hosted web UI, API surfaces, scheduled imports, standard output formats, and a simple on-disk data layout that remains useful without the app running.</p>
|
||||
<p>Use the Web UI for browsing, the CLI and API for automation, and ordinary files for backups and exports.</p>
|
||||
</article>
|
||||
<article>
|
||||
<span class="card-icon" aria-hidden="true"><svg viewBox="0 0 24 24"><path d="M12 3v18M5 21h14M3 7h18M6 7l-4 8h8L6 7Zm12 0-4 8h8l-4-8Z"/></svg></span>
|
||||
<h3>Ethical and legal context</h3>
|
||||
<p>Responsible archiving depends on your jurisdiction, your use case, and your publishing policy. ArchiveBox is a tool; operators remain responsible for handling private data, copyright, DMCA or GDPR requests, and local legal requirements.</p>
|
||||
<p>Public instances should publish contact and removal information, avoid monetizing copied content, and review the security and publishing documentation before exposing snapshots to anonymous viewers.</p>
|
||||
@@ -417,7 +522,7 @@
|
||||
</div>
|
||||
<div class="alternatives-band">
|
||||
<h3>Related web archiving tools and communities</h3>
|
||||
<p>ArchiveBox is a broad, self-hosted archive manager. For specialized crawling, replay, bookmark management, or research workflows, the wider web archiving ecosystem is worth knowing.</p>
|
||||
<p>Looking for specialized crawling, replay, or bookmark management? Explore these other web archiving projects.</p>
|
||||
<div class="doc-link-grid">
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Web-Archiving-Community#web-archiving-projects">Web archiving projects</a>
|
||||
<a href="https://archiveweb.page">ArchiveWeb.page</a>
|
||||
@@ -431,37 +536,12 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section docs-band">
|
||||
<div>
|
||||
<p class="eyebrow">Documentation</p>
|
||||
<h2>Further Reading.</h2>
|
||||
<p>The README and wiki cover supported sources, outputs, scheduled archiving, storage backends, authentication, security, publishing, Chrome setup, upgrades, troubleshooting, API usage, development, and the broader web archiving community.</p>
|
||||
</div>
|
||||
<div class="doc-link-grid">
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Quickstart">Quickstart</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Install">Install</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Docker">Docker</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Usage">Usage</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Configuration">Configuration</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki#can-save-these-things-for-each-site">Supported outputs</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Scheduled-Archiving">Scheduled archiving</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-up-Storage">Storage backends</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Setting-up-Authentication">Authentication</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Security-Overview">Security overview</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Chromium-Install">Chromium setup</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Troubleshooting">Troubleshooting</a>
|
||||
<a href="https://docs.archivebox.io">API docs</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/issues">Issue tracker</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/wiki/Roadmap">Roadmap</a>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/releases">Changelog</a>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<!-- BEGIN ARCHIVEBOX FOOTER — generated by monorepo/site-chrome/sync.py -->
|
||||
<footer class="abx-footer" aria-label="ArchiveBox ecosystem">
|
||||
<div class="abx-footer-intro"><div><a class="abx-brand" href="https://archivebox.io/"><svg class="abx-logo" viewBox="0 0 40 40" aria-hidden="true"><rect width="40" height="40" rx="10" fill="#9b2854"/><path d="M10 14h20v17H10z" fill="#fff4ed"/><path d="M8 9h24v6H8z" fill="#fff4ed"/><path d="M16 19h8v3h-8z" fill="#9b2854"/><path d="M12 31V17" stroke="#9b2854" stroke-width="2"/></svg><span>ArchiveBox</span></a><p class="abx-tagline">Open-source tools for keeping a lasting copy of the web.<br>Your data. Your devices. Your archive.</p></div><p class="abx-footer-motto">A home for the web<br>you want to keep.</p></div>
|
||||
<div class="abx-footer-grid"><section class="abx-footer-column"><h2>Apps & tools</h2><ul><li><a href="https://archivebox.io/">Self-hosted Web Archive</a><a class="abx-source" href="https://github.com/ArchiveBox/ArchiveBox" aria-label="Self-hosted Web Archive source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#get-started">iOS App for iPhone & iPad</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="iOS App for iPhone & iPad source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#your-server-your-choice">macOS App + Server App</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="macOS App + Server App source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/archivebox-browser-extension/">Browser Extensions</a><a class="abx-source" href="https://github.com/ArchiveBox/archivebox-browser-extension" aria-label="Browser Extensions source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-dl/">Command-line Downloader</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-dl" aria-label="Command-line Downloader source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-plugins/">Plugins & Extractors</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-plugins" aria-label="Plugins & Extractors source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 Line truncated
|
||||
<div class="abx-footer-grid"><section class="abx-footer-column"><h2>Apps & tools</h2><ul><li><a href="https://archivebox.io/">ArchiveBox Server</a><a class="abx-source" href="https://github.com/ArchiveBox/ArchiveBox" aria-label="ArchiveBox Server source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#get-started">ArchiveBox for macOS & iOS</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="ArchiveBox for macOS & iOS source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/archivebox-browser-extension/">ArchiveBox Browser Extension</a><a class="abx-source" href="https://github.com/ArchiveBox/archivebox-browser-extension" aria-label="ArchiveBox Browser Extension source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-plugins/">ArchiveBox Plugin Library</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-plugins" aria-label="ArchiveBox Plugin Library source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/abx-dl/">One-shot abx-dl CLI</a><a class="abx-source" href="https://github.com/ArchiveBox/abx-dl" aria-label="One-shot abx-dl CLI source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 12 .75Z"/></svg></a></li><li><a href="https://archivebox.github.io/ios-archivebox/#your-server-your-choice">ArchiveBox Server.app</a><a class="abx-source" href="https://github.com/ArchiveBox/ios-archivebox" aria-label="ArchiveBox Server.app source on GitHub" title="View source on GitHub"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 .75a11.25 11.25 0 0 0-3.56 21.92c.56.1.77-.24.77-.54v-2.1c-3.14.68-3.8-1.33-3.8-1.33-.51-1.3-1.25-1.65-1.25-1.65-1.02-.7.08-.69.08-.69 1.13.08 1.73 1.16 1.73 1.16 1 1.72 2.63 1.22 3.27.93.1-.73.39-1.22.71-1.5-2.5-.28-5.13-1.25-5.13-5.56 0-1.23.44-2.23 1.16-3.02-.12-.28-.5-1.43.11-2.98 0 0 .95-.3 3.1 1.15a10.8 10.8 0 0 1 5.64 0c2.15-1.46 3.1-1.15 3.1-1.15.62 1.55.23 2.7.12 2.98.72.79 1.16 1.8 1.16 3.02 0 4.32-2.64 5.27-5.15 5.55.4.35.76 1.03.76 2.08v3.11c0 .3.2.65.77.54A11.25 11.25 0 0 0 1Line truncated
|
||||
<div class="abx-footer-local"><p>Open-source self-hosted web archiving. MIT licensed, nonprofit-supported, and built for durable collections.</p>
|
||||
<div>
|
||||
<a href="https://github.com/ArchiveBox/ArchiveBox/blob/dev/LICENSE">License</a>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
(() => {
|
||||
const tablist = document.querySelector('.install-tabs');
|
||||
const tabs = Array.from(tablist.querySelectorAll('.install-tab'));
|
||||
const panels = tabs.map(tab => document.querySelector(tab.getAttribute('href')));
|
||||
|
||||
function selectTab(index) {
|
||||
tabs.forEach((tab, i) => {
|
||||
tab.setAttribute('aria-selected', String(i === index));
|
||||
tab.tabIndex = i === index ? 0 : -1;
|
||||
panels[i].hidden = i !== index;
|
||||
});
|
||||
}
|
||||
|
||||
tablist.setAttribute('role', 'tablist');
|
||||
tabs.forEach((tab, index) => {
|
||||
tab.setAttribute('role', 'tab');
|
||||
tab.setAttribute('aria-controls', panels[index].id);
|
||||
panels[index].setAttribute('role', 'tabpanel');
|
||||
panels[index].tabIndex = 0;
|
||||
tab.addEventListener('click', event => {
|
||||
event.preventDefault();
|
||||
selectTab(index);
|
||||
});
|
||||
tab.addEventListener('keydown', event => {
|
||||
let next;
|
||||
if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;
|
||||
else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;
|
||||
else if (event.key === 'Home') next = 0;
|
||||
else if (event.key === 'End') next = tabs.length - 1;
|
||||
else if (event.key === ' ') next = index;
|
||||
else return;
|
||||
event.preventDefault();
|
||||
selectTab(next);
|
||||
tabs[next].focus();
|
||||
});
|
||||
});
|
||||
|
||||
function selectHash() {
|
||||
const index = panels.findIndex(panel => `#${panel.id}` === location.hash);
|
||||
if (index !== -1) selectTab(index);
|
||||
}
|
||||
|
||||
selectTab(0);
|
||||
selectHash();
|
||||
window.addEventListener('hashchange', selectHash);
|
||||
})();
|
||||
@@ -20,6 +20,7 @@
|
||||
.abx-apps[open] > summary::before { transform: rotate(90deg); }
|
||||
.abx-header .abx-app-links { position: absolute; right: 0; top: calc(100% + 12px); width: 305px; max-height: min(70vh, 580px); overflow-y: auto; padding: 10px; border: 1px solid #e9e2e3; border-radius: 14px; background: #fcfaf7; box-shadow: 0 16px 48px #2d152522; }
|
||||
.abx-header .abx-app-links a { display: flex; min-height: 42px; padding: 9px 12px; border-radius: 7px; white-space: normal; }
|
||||
.abx-header .abx-app-links code { display: inline; vertical-align: baseline; font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 1em; font-weight: inherit; line-height: inherit; margin: 0 .3em; padding: 0; border: 0; background: transparent; color: inherit; }
|
||||
.abx-header .abx-app-links a:hover { background: #f2e8ed; }
|
||||
.abx-footer { position: relative; z-index: 1; display: block; width: 100%; max-width: none; margin: 72px 0 0; padding: 60px max(24px, calc((100% - 1280px) / 2)) 24px; border: 0; border-top: 3px solid #7e284a; background: radial-gradient(ellipse at 12% 0, #54243b55, transparent 48%), linear-gradient(120deg, #201923, #14151b 75%); color: #ddd2dd; color-scheme: dark; }
|
||||
.abx-footer .abx-footer-intro { display: flex; align-items: flex-start; justify-content: space-between; gap: 32px; margin: 0 0 42px; }
|
||||
|
||||
@@ -432,11 +432,184 @@ h3 {
|
||||
|
||||
.product-shot {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.device-showcase {
|
||||
position: relative;
|
||||
padding: 24px 58px 42px 0;
|
||||
}
|
||||
|
||||
.device-desktop {
|
||||
display: block;
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.device-phone {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 0;
|
||||
width: 31%;
|
||||
max-width: 170px;
|
||||
transform: rotate(5deg);
|
||||
filter: drop-shadow(0 12px 16px #21192126);
|
||||
}
|
||||
|
||||
.device-phone img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.device-caption {
|
||||
margin: 0;
|
||||
color: var(--muted-text);
|
||||
font-size: 0.9rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
display: inline-flex;
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid hsl(var(--primary) / 0.14);
|
||||
border-radius: 12px;
|
||||
background: hsl(var(--primary) / 0.06);
|
||||
color: var(--brand);
|
||||
}
|
||||
|
||||
.card-icon svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.6;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.features-section .section-heading {
|
||||
max-width: 960px;
|
||||
}
|
||||
|
||||
.features-section h2 em {
|
||||
color: var(--brand);
|
||||
}
|
||||
|
||||
.features-section .feature-grid {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.card-shot {
|
||||
margin: 24px 0 0;
|
||||
}
|
||||
|
||||
.card-shot > a {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--soft);
|
||||
}
|
||||
|
||||
.card-shot img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.card-media {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.card-media .card-icon {
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.card-thumbnail {
|
||||
display: block;
|
||||
width: 112px;
|
||||
height: 70px;
|
||||
overflow: hidden;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 6px;
|
||||
background: var(--soft);
|
||||
}
|
||||
|
||||
.card-thumbnail img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.card-thumbnail:hover,
|
||||
.card-thumbnail:focus-visible {
|
||||
outline: 2px solid var(--brand);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.audience-card .card-shot {
|
||||
margin-top: auto;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.audience-card .card-shot > a {
|
||||
height: 230px;
|
||||
}
|
||||
|
||||
.audience-card .card-shot img {
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: top left;
|
||||
}
|
||||
|
||||
.audience-card .card-shot--crawl-options > a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.audience-card .card-shot--crawl-options img {
|
||||
max-width: 340px;
|
||||
object-position: center bottom;
|
||||
}
|
||||
|
||||
.audience-card .phone-pair > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 8px;
|
||||
background: linear-gradient(135deg, #f4e8ed, #edf1e8);
|
||||
}
|
||||
|
||||
.audience-card .phone-pair img {
|
||||
width: calc(50% - 4px);
|
||||
object-fit: contain;
|
||||
object-position: center;
|
||||
}
|
||||
|
||||
.finder-shot {
|
||||
max-width: 400px;
|
||||
margin: 20px 0 0;
|
||||
}
|
||||
|
||||
.finder-shot img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.trust-strip {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@@ -510,6 +683,109 @@ h3 {
|
||||
margin-bottom: 34px;
|
||||
}
|
||||
|
||||
.configuration-heading,
|
||||
.integration-heading {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 320px;
|
||||
align-items: center;
|
||||
gap: 20px 40px;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.configuration-heading .configuration-description {
|
||||
grid-column: 1 / -1;
|
||||
max-width: 780px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.plugin-stack {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 54px);
|
||||
justify-content: center;
|
||||
gap: 12px 0;
|
||||
margin: 0;
|
||||
padding: 12px 20px 12px 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.integration-stack {
|
||||
grid-template-columns: repeat(4, 54px);
|
||||
}
|
||||
|
||||
.integration-stack li:nth-child(n + 5) a {
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.plugin-stack li:nth-child(4n + 1) { --tilt: -10deg; }
|
||||
.plugin-stack li:nth-child(4n + 2) { --tilt: 6deg; }
|
||||
.plugin-stack li:nth-child(4n + 3) { --tilt: -5deg; }
|
||||
.plugin-stack li:nth-child(4n) { --tilt: 10deg; }
|
||||
|
||||
.plugin-stack a {
|
||||
position: relative;
|
||||
display: grid;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
place-items: center;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 20px;
|
||||
background: #fff;
|
||||
box-shadow: 0 7px 18px #21192114;
|
||||
transform: rotate(var(--tilt));
|
||||
}
|
||||
|
||||
.plugin-stack li:nth-child(n + 6) a {
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.plugin-stack a:hover,
|
||||
.plugin-stack a:focus-visible {
|
||||
z-index: 1;
|
||||
outline: 2px solid var(--brand);
|
||||
outline-offset: 3px;
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
|
||||
.plugin-stack img {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.configuration-heading,
|
||||
.integration-heading {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.plugin-stack {
|
||||
grid-template-columns: repeat(10, 26px);
|
||||
justify-content: start;
|
||||
padding: 10px 0 16px;
|
||||
}
|
||||
|
||||
.integration-stack {
|
||||
grid-template-columns: repeat(7, 38px);
|
||||
}
|
||||
|
||||
.plugin-stack a {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.plugin-stack li:nth-child(n + 6) a,
|
||||
.integration-stack li:nth-child(n + 5) a {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.plugin-stack img {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
.audience-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
@@ -522,7 +798,7 @@ h3 {
|
||||
}
|
||||
|
||||
.audience-card ul {
|
||||
margin: auto 0 0;
|
||||
margin: 0 0 20px;
|
||||
padding-left: 19px;
|
||||
color: var(--muted-text);
|
||||
}
|
||||
@@ -532,15 +808,478 @@ h3 {
|
||||
}
|
||||
|
||||
.install-section {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.72fr) minmax(360px, 1fr);
|
||||
gap: 34px;
|
||||
align-items: start;
|
||||
scroll-margin-top: 100px;
|
||||
}
|
||||
|
||||
.install-copy {
|
||||
position: sticky;
|
||||
top: 112px;
|
||||
.install-window {
|
||||
overflow: hidden;
|
||||
border: 1px solid #51483c;
|
||||
border-radius: var(--radius);
|
||||
background: #14110d;
|
||||
color: #ece4d0;
|
||||
box-shadow: 0 18px 45px rgb(28 24 20 / 18%), 0 2px 6px rgb(28 24 20 / 12%);
|
||||
}
|
||||
|
||||
.install-window-bar {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-height: 42px;
|
||||
padding: 10px 16px;
|
||||
border-bottom: 1px solid #3a352c;
|
||||
background: linear-gradient(#373129, #2b261f);
|
||||
}
|
||||
|
||||
.install-window-controls {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.install-window-controls span {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #ff5f57;
|
||||
box-shadow: inset 0 0 0 1px rgb(0 0 0 / 12%);
|
||||
}
|
||||
|
||||
.install-window-controls span:nth-child(2) {
|
||||
background: #febc2e;
|
||||
}
|
||||
|
||||
.install-window-controls span:nth-child(3) {
|
||||
background: #28c840;
|
||||
}
|
||||
|
||||
.install-window-title {
|
||||
color: #c8bfae;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.install-tab[data-group-start] {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.install-tabs {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
padding: 10px 10px 0;
|
||||
background: #24201a;
|
||||
scrollbar-color: #6e6254 #24201a;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
.install-tab {
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 13px 18px;
|
||||
border: 1px solid transparent;
|
||||
border-bottom: 1px solid #3a352c;
|
||||
border-radius: 7px 7px 0 0;
|
||||
color: #b9b0a0;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.install-tab img {
|
||||
flex-shrink: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 2px;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.install-tab:hover {
|
||||
background: #302a22;
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.install-tab[aria-selected="true"] {
|
||||
border-color: #3a352c;
|
||||
border-bottom-color: #14110d;
|
||||
background: #14110d;
|
||||
color: #fff;
|
||||
box-shadow: inset 0 2px #d59aae;
|
||||
}
|
||||
|
||||
.install-tab:focus-visible,
|
||||
.install-panel:focus-visible {
|
||||
outline: 2px solid #d59aae;
|
||||
outline-offset: -4px;
|
||||
}
|
||||
|
||||
.install-panel {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 0.55fr) minmax(360px, 1fr);
|
||||
gap: 32px;
|
||||
padding: 32px;
|
||||
align-items: start;
|
||||
scroll-margin-top: 100px;
|
||||
}
|
||||
|
||||
.install-panel[hidden] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.install-panel + .install-panel {
|
||||
margin-top: 34px;
|
||||
}
|
||||
|
||||
.install-tabs[role="tablist"] ~ .install-panel {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.install-art {
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.install-art-stage {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24px;
|
||||
min-height: 310px;
|
||||
padding: 26px 18px;
|
||||
border-radius: 12px;
|
||||
background: radial-gradient(ellipse at 50% 25%, #494151, #242126 75%);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.install-art figcaption {
|
||||
margin-top: 14px;
|
||||
color: #b9b0a0;
|
||||
text-align: center;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.install-art-tile {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.install-art-tile img {
|
||||
width: 76px;
|
||||
height: 76px;
|
||||
object-fit: contain;
|
||||
border-radius: 16px;
|
||||
filter: drop-shadow(0 6px 9px #0003);
|
||||
}
|
||||
|
||||
.install-art-tile span {
|
||||
font-size: 0.74rem;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.install-art-route,
|
||||
.install-drag-card {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) 30px minmax(0, 1fr);
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.install-art-arrow {
|
||||
font-size: 2rem;
|
||||
color: #d0c4d8;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.install-drag-card {
|
||||
padding: 22px 12px;
|
||||
background: linear-gradient(135deg, #fff, #e9e7ee);
|
||||
border-radius: 9px;
|
||||
box-shadow: 0 10px 24px #0004;
|
||||
color: #302b36;
|
||||
}
|
||||
|
||||
.install-drag-card .install-art-arrow {
|
||||
color: #aaa4b2;
|
||||
}
|
||||
|
||||
.install-drag-card .install-art-tile img {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.install-art-shot {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 12px 24px #0005;
|
||||
}
|
||||
|
||||
.install-art-shot img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.install-art--macos .install-art-stage {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.install-art--macos .install-art-shot {
|
||||
transform: rotate(-2deg);
|
||||
}
|
||||
|
||||
.install-art--desktop .install-art-stage {
|
||||
height: 365px;
|
||||
background: radial-gradient(ellipse at 70% 30%, #4b5871, #222631 75%);
|
||||
}
|
||||
|
||||
.install-desktop-base {
|
||||
position: absolute;
|
||||
bottom: 22px;
|
||||
left: 24px;
|
||||
width: 160px;
|
||||
padding: 24px 12px;
|
||||
background: #e5f1ff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 12px;
|
||||
color: #194268;
|
||||
transform: rotate(-10deg);
|
||||
box-shadow: 0 14px 28px #0005;
|
||||
}
|
||||
|
||||
.install-desktop-shot {
|
||||
position: absolute;
|
||||
top: 26px;
|
||||
right: 22px;
|
||||
width: 75%;
|
||||
height: 215px;
|
||||
overflow: hidden;
|
||||
border: 5px solid #eeeaf0;
|
||||
border-radius: 10px;
|
||||
transform: rotate(6deg);
|
||||
box-shadow: 0 12px 24px #0006;
|
||||
}
|
||||
|
||||
.install-desktop-shot img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position: top;
|
||||
}
|
||||
|
||||
.install-art-file,
|
||||
.install-art-chips span {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid #81748b;
|
||||
border-radius: 6px;
|
||||
background: #302837;
|
||||
color: #ece4f1;
|
||||
font: 0.7rem var(--font-mono);
|
||||
}
|
||||
|
||||
.install-art-file {
|
||||
transform: rotate(3deg);
|
||||
margin-top: -40px;
|
||||
}
|
||||
|
||||
.install-package-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
width: 78%;
|
||||
padding: 24px;
|
||||
border: 1px solid #84758c;
|
||||
border-radius: 14px;
|
||||
background: linear-gradient(145deg, #504256, #2e2633);
|
||||
transform: rotate(-4deg);
|
||||
box-shadow: 12px 12px 0 -4px #332d3a, 12px 12px 0 -3px #65596f, 0 18px 28px #0004;
|
||||
}
|
||||
|
||||
.install-package-line {
|
||||
height: 24px;
|
||||
border-left: 2px dashed #b7a4c1;
|
||||
}
|
||||
|
||||
.install-art-chips {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.install-art-platforms {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.install-art-platforms .install-art-tile {
|
||||
padding: 18px 8px;
|
||||
border: 1px solid #776880;
|
||||
border-radius: 12px;
|
||||
background: #ffffff0a;
|
||||
}
|
||||
|
||||
.install-script-card {
|
||||
width: 100%;
|
||||
padding: 24px 18px;
|
||||
border: 1px solid #76667f;
|
||||
border-radius: 10px;
|
||||
background: #19161d;
|
||||
transform: rotate(-4deg);
|
||||
box-shadow: 0 14px 24px #0005;
|
||||
}
|
||||
|
||||
.install-script-card code {
|
||||
font-size: clamp(0.65rem, 1.1vw, 0.85rem);
|
||||
}
|
||||
|
||||
.install-script-prompt,
|
||||
.install-script-card code span {
|
||||
color: #c5e4b1;
|
||||
}
|
||||
|
||||
.install-script-progress {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.install-script-progress i {
|
||||
height: 5px;
|
||||
flex: 1;
|
||||
border-radius: 3px;
|
||||
background: #8ca976;
|
||||
}
|
||||
|
||||
.install-server-rack {
|
||||
width: 155px;
|
||||
height: 175px;
|
||||
fill: #353847;
|
||||
stroke: #9eadd0;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.install-server-rack circle {
|
||||
fill: #a7cf96;
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.install-art--server .install-art-tile,
|
||||
.install-art--cloud .install-art-tile {
|
||||
margin-top: -65px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.install-cloud {
|
||||
width: 230px;
|
||||
height: 160px;
|
||||
fill: #5e5573;
|
||||
stroke: #bdb0d2;
|
||||
stroke-width: 2;
|
||||
}
|
||||
|
||||
.install-art--extension .install-art-route {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.install-art--extension .install-art-shot {
|
||||
transform: rotate(-3deg);
|
||||
}
|
||||
|
||||
.install-panel .eyebrow {
|
||||
color: #b9b0a0;
|
||||
}
|
||||
|
||||
.install-panel a {
|
||||
color: #e9adc2;
|
||||
}
|
||||
|
||||
.install-panel .install-download {
|
||||
width: 100%;
|
||||
gap: 18px;
|
||||
margin-bottom: 18px;
|
||||
padding: 22px 24px;
|
||||
color: var(--brand-text);
|
||||
font-size: clamp(1.5rem, 2.5vw, 2rem);
|
||||
line-height: 1.2;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.install-download svg {
|
||||
flex: 0 0 auto;
|
||||
width: 0.95em;
|
||||
height: 1.25em;
|
||||
}
|
||||
|
||||
.install-download:focus-visible {
|
||||
outline: 3px solid #e9adc2;
|
||||
outline-offset: 4px;
|
||||
}
|
||||
|
||||
.install-panel .command-card {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
background: #3a352c;
|
||||
}
|
||||
|
||||
.install-panel .step {
|
||||
grid-template-columns: 26px minmax(0, 1fr);
|
||||
gap: 14px;
|
||||
padding: 20px 0;
|
||||
background: #14110d;
|
||||
}
|
||||
|
||||
.install-panel .step:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.install-panel .step:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.install-panel .step > span {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
background: #302a22;
|
||||
color: #e9adc2;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.install-panel .ab-terminal {
|
||||
background: #1c1915;
|
||||
}
|
||||
|
||||
.install-panel h4 {
|
||||
margin: 0 0 12px;
|
||||
font-size: 1.08rem;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.install-panel .ab-terminal + p {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.install-panel .step p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.command-card {
|
||||
@@ -754,10 +1493,14 @@ h3 {
|
||||
}
|
||||
|
||||
@media (max-width: 980px) {
|
||||
.features-section .feature-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.site-header,
|
||||
.hero,
|
||||
.split,
|
||||
.install-section,
|
||||
.install-panel,
|
||||
.docs-band,
|
||||
.site-footer {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -795,12 +1538,20 @@ h3 {
|
||||
}
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.section,
|
||||
.trust-strip,
|
||||
.site-footer {
|
||||
width: min(358px, calc(100vw - 32px));
|
||||
margin-left: 16px;
|
||||
margin-right: 16px;
|
||||
.features-section .feature-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.install-panel {
|
||||
padding: 22px 16px;
|
||||
}
|
||||
|
||||
.install-panel .step {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.install-panel .step > span {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.section {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "archivebox"
|
||||
version = "0.9.35rc473"
|
||||
version = "0.9.35rc517"
|
||||
requires-python = ">=3.13"
|
||||
description = "Self-hosted internet archiving solution."
|
||||
authors = [{name = "Nick Sweeting", email = "pyproject.toml@archivebox.io"}]
|
||||
@@ -78,9 +78,9 @@ dependencies = [
|
||||
### Extractor dependencies (runtime binaries resolved through abxpkg)
|
||||
### Binary/Package Management
|
||||
"abxbus==2.5.56", # direct imports only; version constrained by abx-dl -> abx-plugins
|
||||
"abxpkg==1.12.118", # direct imports only; version constrained by abx-dl -> abx-plugins
|
||||
"abx-plugins[opencode]==1.12.252", # optional AI runtime clients are owned by the plugin
|
||||
"abx-dl==1.12.289", # shared ArchiveBox downloader package
|
||||
"abxpkg==1.12.125", # direct imports only; version constrained by abx-dl -> abx-plugins
|
||||
"abx-plugins[opencode]==1.12.278", # optional AI runtime clients are owned by the plugin
|
||||
"abx-dl==1.12.315", # shared ArchiveBox downloader package
|
||||
### UUID7 backport for Python <3.14
|
||||
"uuid7>=0.1.0; python_version < '3.14'", # provides the uuid_extensions module on Python 3.13
|
||||
"browser-cookie3>=0.20.1",
|
||||
@@ -342,7 +342,7 @@ Donate = "https://github.com/ArchiveBox/ArchiveBox/wiki/Donations"
|
||||
|
||||
|
||||
[tool.bumpver]
|
||||
current_version = "v0.9.35rc473"
|
||||
current_version = "v0.9.35rc517"
|
||||
version_pattern = "vMAJOR.MINOR.PATCH[PYTAGNUM]"
|
||||
commit_message = "bump version {old_version} -> {new_version}"
|
||||
tag_message = "{new_version}"
|
||||
|
||||
@@ -13,18 +13,18 @@ supported-markers = [
|
||||
]
|
||||
|
||||
[options]
|
||||
exclude-newer = "2026-09-13T06:06:59.555346705Z"
|
||||
exclude-newer = "2026-09-13T21:41:28.931651087Z"
|
||||
exclude-newer-span = "P5D"
|
||||
|
||||
[options.exclude-newer-package]
|
||||
abxbus = { timestamp = "2026-09-18T06:06:58.555362062Z", span = "PT1S" }
|
||||
abxbus = { timestamp = "2026-09-18T21:41:27.931664943Z", span = "PT1S" }
|
||||
abx-plugins = "2100-01-01T00:00:00Z"
|
||||
abx-dl = "2100-01-01T00:00:00Z"
|
||||
abxpkg = "2100-01-01T00:00:00Z"
|
||||
|
||||
[[package]]
|
||||
name = "abx-dl"
|
||||
version = "1.12.289"
|
||||
version = "1.12.315"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "abx-plugins", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -38,14 +38,14 @@ dependencies = [
|
||||
{ name = "rich", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
{ name = "rich-click", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e3/18/99113fc3117ab0cb272582e2ed66b959fc7f0efcb763f5d1ccc04095b7cc/abx_dl-1.12.289.tar.gz", hash = "sha256:b91ed92fa4d431a01165880054e85e4da00e6ebbd6d24b2472eb4e7b341f2ef5", size = 88248 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/aa/e2/7a565357693e11be91266ff874c1866a74519256b54f9b4d1a9901bd9434/abx_dl-1.12.315.tar.gz", hash = "sha256:74cbb9ebf6f9709db26886a4e6183d85a426c136dc595c780f79b4f2726fdb18", size = 87772 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/af/56/daf1fc30cce421356d6cea1497fa7e3fa31d19b84f4f554c161b50ccf479/abx_dl-1.12.289-py3-none-any.whl", hash = "sha256:bd94d50010470393b5ad6438487d63e9bfb84eb6b26217c1585be81e862cf803", size = 93264 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9a/97/11185dbfa4f241e01737cd0c777c7eda121b2ea6c755b100acfe3f5caf30/abx_dl-1.12.315-py3-none-any.whl", hash = "sha256:126bf06c55c943dc1a54e4caaf8b870826c897535c7ceb06ff771542103664d7", size = 93004 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "abx-plugins"
|
||||
version = "1.12.252"
|
||||
version = "1.12.278"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "abxbus", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -54,9 +54,9 @@ dependencies = [
|
||||
{ name = "rich-click", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
{ name = "uv", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/8c/66d64ce850fbb41b8e941f2b95d79b7ddc9ebd4f7238f447a7bf98fd91d0/abx_plugins-1.12.252.tar.gz", hash = "sha256:dac5a4529fc439e37c2442d5f5a06e17dbafa33fb4a4662123e02147b2e18e41", size = 463016, upload-time = "2026-09-18T05:34:20.338Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fd/3d/f76c93e93712448bdaf5452887b383eec82fa193a7f6702aafe47a806c56/abx_plugins-1.12.278.tar.gz", hash = "sha256:65993dd1290b895d72a503ab5f0e2bfa54d1b5a3e56e5ffad901fe8318ac3ede", size = 344470, upload-time = "2026-09-18T21:02:28.989Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/2d/151511349ff8f2ca6e11c756c98c6797030511fbad95d66461feb07a895a/abx_plugins-1.12.252-py3-none-any.whl", hash = "sha256:1d2a42d055a26d448b3a27664ff6ca80aa01498636377052eda6664e16206afa", size = 629564, upload-time = "2026-09-18T05:34:18.845Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/29/d21f1a129049504cd1f0f68debed779b72659e7425c5d5a29ed0ca32a446/abx_plugins-1.12.278-py3-none-any.whl", hash = "sha256:cf8c0cd1ac8318d16825cbb97fb248dcbdd6ca448e5f3a5ae9e290119727efdd", size = 511364, upload-time = "2026-09-18T21:02:27.128Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
@@ -82,7 +82,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "abxpkg"
|
||||
version = "1.12.118"
|
||||
version = "1.12.125"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "platformdirs", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -90,9 +90,9 @@ dependencies = [
|
||||
{ name = "rich-click", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
{ name = "typing-extensions", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c1/c6/d6d0c7c2481a0525e451230e34ab832c4abc71dcbadd734fdcacac18465f/abxpkg-1.12.118.tar.gz", hash = "sha256:a68b0d72b495142e87a014cd90cfe949524eb7187d981bf0775579454f7c29ef", size = 239381, upload-time = "2026-09-18T05:27:25.739Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/87/fc/cf3f9d370ee93202c2e9239d267ca0b0dece7dc3595d36eebbedf3ab2946/abxpkg-1.12.125.tar.gz", hash = "sha256:14d98f4ff305f5ac84030f4d1f16a2f6c511ff5480ebfb08ba133f367a0770e1", size = 239374, upload-time = "2026-09-18T07:29:21.549Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/67/860d7e3d81e7f15f836d1157f77955b047808237fa8ef8949b21be38adc9/abxpkg-1.12.118-py3-none-any.whl", hash = "sha256:b632be829ae692d35b88da605341bf4d4fd78af6fb7cca2ea1feddf4a39290e0", size = 253748, upload-time = "2026-09-18T05:27:24.028Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bf/5c/dd0d1690e4c1d6241f44a5194a525af6769acdf33dd366a6b4b56f33c2b0/abxpkg-1.12.125-py3-none-any.whl", hash = "sha256:cfef2e06ed01b8774e8bdf0b8de36ab592a0dfa273993c4824628ab17d7d0fd1", size = 253748, upload-time = "2026-09-18T07:29:23.043Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -127,7 +127,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "archivebox"
|
||||
version = "0.9.35rc473"
|
||||
version = "0.9.35rc517"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "abx-dl", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||
@@ -226,10 +226,10 @@ dev = [
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "abx-dl", specifier = "==1.12.289" },
|
||||
{ name = "abx-plugins", extras = ["opencode"], specifier = "==1.12.252" },
|
||||
{ name = "abx-dl", specifier = "==1.12.315" },
|
||||
{ name = "abx-plugins", extras = ["opencode"], specifier = "==1.12.278" },
|
||||
{ name = "abxbus", specifier = "==2.5.56" },
|
||||
{ name = "abxpkg", specifier = "==1.12.118" },
|
||||
{ name = "abxpkg", specifier = "==1.12.125" },
|
||||
{ name = "archivebox", extras = ["sonic", "ldap", "debug"], marker = "extra == 'all'" },
|
||||
{ name = "atomicwrites", specifier = "==1.4.1" },
|
||||
{ name = "base32-crockford", specifier = ">=0.3.0" },
|
||||
|
||||