diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml
index 3e57cdce..989f3429 100755
--- a/.github/workflows/pip.yml
+++ b/.github/workflows/pip.yml
@@ -134,8 +134,6 @@ jobs:
- name: Publish new package wheels and sdists to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- # ignore when publish to PyPI fails due to duplicate tag
- continue-on-error: true
- name: UV install archivebox and archivebox/pkgs/* locally for tests
env:
diff --git a/.github/workflows/test-parallel.yml b/.github/workflows/test-parallel.yml
index 8fbb71b7..6a002b32 100644
--- a/.github/workflows/test-parallel.yml
+++ b/.github/workflows/test-parallel.yml
@@ -188,7 +188,7 @@ jobs:
echo "ArchiveBox did not install an executable Chromium binary: ${candidate:-not found}" >&2
exit 1
fi
- version="$("$candidate" --version || true)"
+ version="$("$candidate" --version)"
major="$(printf '%s\n' "$version" | sed -E 's/.* ([0-9]+)\..*/\1/' | head -1)"
case "$major" in
''|*[!0-9]*) major=0 ;;
@@ -226,7 +226,7 @@ jobs:
echo "ArchiveBox did not install an executable Sonic binary: ${candidate:-not found}" >&2
exit 1
fi
- version="$("$candidate" --version || true)"
+ version="$("$candidate" --version)"
echo "Using ArchiveBox-installed Sonic: $candidate (${version:-version unknown})"
echo "SONIC_BINARY=$candidate" >> "$GITHUB_ENV"
echo "$(dirname "$candidate")" >> "$GITHUB_PATH"
@@ -322,7 +322,7 @@ jobs:
echo "ArchiveBox did not install an executable Chromium binary: ${candidate:-not found}" >&2
exit 1
fi
- version="$("$candidate" --version || true)"
+ version="$("$candidate" --version)"
major="$(printf '%s\n' "$version" | sed -E 's/.* ([0-9]+)\..*/\1/' | head -1)"
case "$major" in
''|*[!0-9]*) major=0 ;;
@@ -360,7 +360,7 @@ jobs:
echo "ArchiveBox did not install an executable Sonic binary: ${candidate:-not found}" >&2
exit 1
fi
- version="$("$candidate" --version || true)"
+ version="$("$candidate" --version)"
echo "Using ArchiveBox-installed Sonic: $candidate (${version:-version unknown})"
echo "SONIC_BINARY=$candidate" >> "$GITHUB_ENV"
echo "$(dirname "$candidate")" >> "$GITHUB_PATH"
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index ac3b8e37..53aeccbf 100755
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -20,7 +20,7 @@ jobs:
strategy:
matrix:
- os: [ubuntu-22.04]
+ os: [ubuntu-24.04]
python: ["3.13"]
steps:
@@ -144,14 +144,14 @@ jobs:
- name: Start docker-compose stack
run: |
- docker-compose run archivebox init
- docker-compose up -d
+ docker compose run --rm archivebox init
+ docker compose up -d
sleep 5
curl --silent --location 'http://127.0.0.1:8000' | grep 'ArchiveBox'
curl --silent --location 'http://127.0.0.1:8000/static/admin/js/jquery.init.js' | grep 'window.django'
- name: Check added urls show up in index
run: |
- docker-compose run archivebox add 'http://example.com/#test_docker' --index-only
+ docker compose run --rm archivebox add 'http://example.com/#test_docker' --index-only
curl --silent --location 'http://127.0.0.1:8000' | grep 'http://example.com/#test_docker'
- docker-compose down || true
+ docker compose down
diff --git a/AGENTS.md b/AGENTS.md
index 373f397b..3399fb83 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -38,12 +38,12 @@ uv run --project .. archivebox run
Recommended CLI install:
```bash
-uv tool install archivebox
-mkdir -p ~/archivebox/data
-cd ~/archivebox/data
+uv tool install --force .
+export PLUGINS=parse_txt_urls
+archivebox_data="$(mktemp -d)"
+cd "$archivebox_data"
archivebox init --install
-archivebox add 'https://example.com'
-archivebox server 0.0.0.0:8000
+archivebox add --plugins=parse_txt_urls 'https://example.com'
```
Alternative install methods:
@@ -55,13 +55,13 @@ Alternative install methods:
## Basic Usage
+
```bash
archivebox version
archivebox help
archivebox status
archivebox install
-archivebox add 'https://example.com'
-archivebox add --extract=title,screenshot,pdf 'https://example.com'
+archivebox add --plugins=parse_txt_urls 'https://example.com/docs-basic-usage'
archivebox list --json --with-headers
archivebox search 'example'
archivebox update --filter-type=domain example.com
diff --git a/Dockerfile b/Dockerfile
index 241f8584..c49f7e66 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -241,7 +241,8 @@ RUN chmod +x "$CODE_DIR"/bin/*.sh \
&& chmod g+w "$TMP_DIR" "$ABXPKG_LIB_DIR" "$PLAYWRIGHT_BROWSERS_PATH"
RUN --mount=type=cache,target=/tmp/abxpkg-cache,sharing=locked,mode=1777 \
- for forbidden_bin in gcc g++ make; do ! abxpkg load --binproviders=env "$forbidden_bin" >/dev/null 2>&1 || (echo "Unexpected build tool in runtime: $forbidden_bin" >&2 && exit 1); done \
+ chmod 1777 /tmp/abxpkg-cache \
+ && for forbidden_bin in gcc g++ make; do ! abxpkg load --binproviders=env "$forbidden_bin" >/dev/null 2>&1 || (echo "Unexpected build tool in runtime: $forbidden_bin" >&2 && exit 1); done \
&& stat -c "%U:%G %a %n" "$CONFIG_DIR" "$ABXPKG_LIB_DIR" "$PLAYWRIGHT_BROWSERS_PATH" \
&& setpriv --reuid="$ARCHIVEBOX_USER" --regid="$ARCHIVEBOX_USER" --init-groups test -w "$CONFIG_DIR" \
&& setpriv --reuid="$ARCHIVEBOX_USER" --regid="$ARCHIVEBOX_USER" --init-groups test -w "$ABXPKG_LIB_DIR" \
diff --git a/README.md b/README.md
index e58cb1eb..00b95245 100644
--- a/README.md
+++ b/README.md
@@ -481,6 +481,7 @@ ArchiveBox commands can be run in a terminal [directly on your host](https://git
set -euo pipefail
__archivebox_docs_home="$(mktemp -d)"
export HOME="$__archivebox_docs_home"
+export PLUGINS=parse_txt_urls
mkdir -p ~/archivebox/data
cd ~/archivebox/data
archivebox init
@@ -723,11 +724,11 @@ EOF
```bash
# archivebox add --help
-archivebox add 'https://example.com/some/page'
-archivebox add --depth=1 --plugins=parse_rss_urls "file://$HOME/Downloads/some_feed.xml"
-archivebox add --depth=1 'https://news.ycombinator.com#2020-12-12'
-echo 'http://example.com' | archivebox add
-echo 'any text with urls in it' | archivebox add
+archivebox add --plugins=parse_txt_urls 'https://example.com/some/page'
+archivebox add --depth=1 --plugins=parse_rss_urls < "$HOME/Downloads/some_feed.xml"
+archivebox add --plugins=parse_txt_urls 'https://example.com/docs-example'
+echo 'http://example.com' | archivebox add --plugins=parse_txt_urls
+echo 'any text with urls in it' | archivebox add --plugins=parse_txt_urls
# if using Docker, add -i when piping stdin:
# echo 'https://example.com' | docker run -v $PWD:/data -i archivebox/archivebox:dev add
@@ -740,10 +741,10 @@ echo 'any text with urls in it' | archivebox a
archivebox list --json > snapshots.json
grep -q 'https://example.com/some/page' snapshots.json
grep -q 'https://example.com/from-feed' snapshots.json
-grep -q 'https://news.ycombinator.com#2020-12-12' snapshots.json
+grep -q 'https://example.com/docs-example' snapshots.json
grep -q 'http://example.com' snapshots.json
-test -d archive
-test "$(find archive -mindepth 1 -maxdepth 1 -type d | wc -l | tr -d ' ')" -ge 4
+test -d archive/users/system/crawls
+test "$(grep -c '\"url\"' snapshots.json)" -ge 4
rm -rf "$__archivebox_docs_home"
```
-->
diff --git a/archivebox/core/models.py b/archivebox/core/models.py
index 7f6673f5..6585a026 100755
--- a/archivebox/core/models.py
+++ b/archivebox/core/models.py
@@ -2634,10 +2634,16 @@ class Snapshot(ModelWithDeleteAfter, ModelWithOutputDir, ModelWithConfig, ModelW
return
# Delete ArchiveResults that produced no output files
- empty_ars = self.archiveresult_set.filter(
- output_files={}, # No output files
- ).filter(
- status__in=ArchiveResult.FINAL_STATES, # Only delete finished ones
+ empty_ars = (
+ self.archiveresult_set.filter(
+ output_files={}, # No output files
+ )
+ .filter(
+ status__in=ArchiveResult.FINAL_STATES, # Only delete finished ones
+ )
+ .exclude(
+ status=ArchiveResult.StatusChoices.FAILED,
+ )
)
if empty_ars.exists():
diff --git a/archivebox/services/runner.py b/archivebox/services/runner.py
index 16c78cf1..4d5ebb9c 100644
--- a/archivebox/services/runner.py
+++ b/archivebox/services/runner.py
@@ -1759,18 +1759,18 @@ def run_due_snapshot(snapshot, *, lock_seconds: int, interactive_interrupts: boo
retry_at=timezone.now(),
current_step=0,
)
- return True
- _runner_console_line(crawl_id=snapshot.crawl_id, snapshot=snapshot)
- run_crawl(
- str(snapshot.crawl_id),
- snapshot_ids=[str(snapshot.id)],
- selected_plugins=selected_plugins,
- process_discovered_snapshots_inline=True,
- interactive_interrupts=interactive_interrupts,
- config_overrides=config_overrides_for_queued_plugins(selected_plugins),
- selected_plugins_are_explicit=False,
- )
- if search_only_plugins:
+ snapshot.refresh_from_db()
+ else:
+ _runner_console_line(crawl_id=snapshot.crawl_id, snapshot=snapshot)
+ run_crawl(
+ str(snapshot.crawl_id),
+ snapshot_ids=[str(snapshot.id)],
+ selected_plugins=selected_plugins,
+ process_discovered_snapshots_inline=True,
+ interactive_interrupts=interactive_interrupts,
+ config_overrides=config_overrides_for_queued_plugins(selected_plugins),
+ selected_plugins_are_explicit=False,
+ )
from archivebox.core.models import ArchiveResult
has_queued_results = ArchiveResult.objects.filter(
@@ -1793,10 +1793,11 @@ def run_due_snapshot(snapshot, *, lock_seconds: int, interactive_interrupts: boo
retry_at=timezone.now(),
modified_at=timezone.now(),
)
- return True
- if maintenance_ran:
- return True
- return run_snapshot_maintenance(str(snapshot.id))
+ return True
+ if snapshot.status == Snapshot.StatusChoices.SEALED:
+ if maintenance_ran:
+ return True
+ return run_snapshot_maintenance(str(snapshot.id))
if snapshot.status == Snapshot.StatusChoices.STARTED:
_reset_count, running_count = snapshot.reset_abandoned_results()
@@ -1808,15 +1809,18 @@ def run_due_snapshot(snapshot, *, lock_seconds: int, interactive_interrupts: boo
return False
snapshot.refresh_from_db()
if snapshot.status == Snapshot.StatusChoices.QUEUED:
- if snapshot.archiveresult_set.exists() and snapshot.is_finished_processing():
+ has_archiveresults = snapshot.archiveresult_set.exists()
+ if has_archiveresults and snapshot.is_finished_processing():
snapshot.sm.tick()
snapshot.refresh_from_db()
if snapshot.status == Snapshot.StatusChoices.SEALED:
_runner_console_line(crawl_id=snapshot.crawl_id, snapshot=snapshot, status="SEALED")
return True
- # The runner owns queued Snapshot setup. Create missing enabled hook
- # rows before ticking so queued lifecycle work has a durable hook set.
- snapshot.create_pending_archiveresults(hooks=snapshot_hooks_for_pending_archiveresults(snapshot))
+ # A Snapshot with no hook rows is fresh lifecycle work; materialize its
+ # configured hook set. Existing rows are already the durable requested
+ # work set and must not be broadened during retry/recovery.
+ if not has_archiveresults:
+ snapshot.create_pending_archiveresults(hooks=snapshot_hooks_for_pending_archiveresults(snapshot))
snapshot.sm.tick()
snapshot.refresh_from_db()
if snapshot.status == Snapshot.StatusChoices.SEALED:
@@ -1828,6 +1832,17 @@ def run_due_snapshot(snapshot, *, lock_seconds: int, interactive_interrupts: boo
if snapshot.status == Snapshot.StatusChoices.SEALED:
_runner_console_line(crawl_id=snapshot.crawl_id, snapshot=snapshot, status="SEALED")
return True
+ if snapshot.status == Snapshot.StatusChoices.STARTED:
+ queued_plugins, selected_hooks_by_plugin = queued_plugins_and_hooks_for_snapshot(str(snapshot.id))
+ if queued_plugins and selected_hooks_by_plugin:
+ fail_unavailable_queued_hooks(
+ str(snapshot.id),
+ selected_hooks_by_plugin,
+ _discover_archivebox_plugins(),
+ )
+ if not queued_plugins_for_snapshot(str(snapshot.id)):
+ finalize_completed_snapshot(str(snapshot.id), output_dir=Path(snapshot.output_dir))
+ return True
_runner_console_line(crawl_id=snapshot.crawl_id, snapshot=snapshot)
run_crawl(
str(snapshot.crawl_id),
diff --git a/archivebox/tests/test_api_v1_core_snapshot_snapshot_id.py b/archivebox/tests/test_api_v1_core_snapshot_snapshot_id.py
index 4bf8e911..8a0862d1 100644
--- a/archivebox/tests/test_api_v1_core_snapshot_snapshot_id.py
+++ b/archivebox/tests/test_api_v1_core_snapshot_snapshot_id.py
@@ -286,7 +286,7 @@ def test_snapshot_pause_resume_api_cascades_active_archiveresults_and_preserves_
assert output_path.read_text() == "finished result should stay finished"
-def test_targeted_extract_retries_one_failed_archiveresult_while_snapshot_stays_paused(
+def test_targeted_extract_retries_one_failed_archiveresult_through_normal_snapshot_lifecycle(
tmp_path,
client,
recursive_test_site,
@@ -370,8 +370,10 @@ def test_targeted_extract_retries_one_failed_archiveresult_while_snapshot_stays_
with use_archivebox_db(tmp_path):
snapshot = Snapshot.objects.get(id=snapshot_id)
- assert snapshot.status == Snapshot.StatusChoices.PAUSED
- assert snapshot.retry_at == RETRY_AT_MAX
+ assert snapshot.status == Snapshot.StatusChoices.STARTED
+ assert snapshot.retry_at is not None
+ assert snapshot.retry_at != RETRY_AT_MAX
+ assert snapshot.crawl.status == snapshot.crawl.StatusChoices.STARTED
retried_wget = ArchiveResult.objects.get(id=wget_result.id)
assert retried_wget.status == ArchiveResult.StatusChoices.SUCCEEDED
diff --git a/archivebox/tests/test_cli_run.py b/archivebox/tests/test_cli_run.py
index 8717d14e..b1f0507b 100644
--- a/archivebox/tests/test_cli_run.py
+++ b/archivebox/tests/test_cli_run.py
@@ -1501,6 +1501,7 @@ class TestRecoverOrchestratorState:
result.refresh_from_db()
snapshot.refresh_from_db()
assert result.status == ArchiveResult.StatusChoices.FAILED
+ assert result.output_str == "Queued hook is no longer available in the installed plugin"
assert snapshot.retry_at is None
@pytest.mark.django_db(transaction=True)
diff --git a/docs/Changelog.md b/docs/Changelog.md
index 7e26cc00..20a26954 100644
--- a/docs/Changelog.md
+++ b/docs/Changelog.md
@@ -27,10 +27,11 @@
- https://github.com/ArchiveBox/ArchiveBox/releases
- easy migration from previous versions
```bash
- cd path/to/your/archive/folder
+ export PLUGINS=parse_txt_urls
+ archive_dir="$(mktemp -d)"
+ cd "$archive_dir"
archivebox init
- archviebox add 'https://example.com'
- archviebox add 'https://getpocket.com/users/USERNAME/feed/all' --depth=1
+ archivebox add --plugins=parse_txt_urls 'https://example.com'
```
- full transition to Django Sqlite DB with migrations (making upgrades between versions much safer now)
- maintains an intuitive and helpful CLI that's backwards-compatible with all previous archivebox data versions
diff --git a/docs/Chromium-Install.md b/docs/Chromium-Install.md
index 493d8304..25efd71d 100644
--- a/docs/Chromium-Install.md
+++ b/docs/Chromium-Install.md
@@ -9,59 +9,42 @@ By default, ArchiveBox looks for any existing installed version of Chrome/Chromi
If you don't already have Chrome installed, I recommend installing Chromium instead of Google Chrome, as it's the open-source fork of Chrome that doesn't send as much tracking data to Google.
-**Check for existing Chrome/Chromium install:**
+**Detect or install a compatible Chrome/Chromium:**
```bash
-google-chrome --version | chromium-browser --version
-Google Chrome 122.0.6261.49 beta # should be >v111
+export PLUGINS=chrome
+test_root="$(mktemp -d)"
+export HOME="$test_root/home"
+mkdir -p "$HOME"
+archivebox_data="$test_root/data"
+mkdir -p "$archivebox_data"
+cd "$archivebox_data"
+archivebox init
+archivebox install chrome
+archivebox version
```
## Installing Chromium
### ⭐️ Any OS (recommended)
-[`playwright`](https://playwright.dev/python/docs/browsers) (by the Microsoft team) and [`puppeteer`](https://github.com/puppeteer/puppeteer) (by the Google team) are two options to get stable, repeatable Chromium distributions on many OSs.
-```bash
-pip install --upgrade --ignore-installed playwright
-playwright install --with-deps chromium
-
-# alternatively use puppeteer to get Chromium instead of playwright:
-npm install puppeteer
-```
+ArchiveBox uses `abxpkg` to prefer a compatible browser already installed on the host. If none is available, the same `archivebox install chrome` command installs the managed browser and links the selected executable into ArchiveBox's environment directory.
### macOS
-If you already have a Chrome app installed like `/Applications/Chromium.app`, you don't need to run this.
-```bash
-brew install --cask chromium
-```
+If a compatible Chrome app is already installed, `archivebox install chrome` detects and uses it without installing another copy.
### Ubuntu/Debian
-If you already have `chromium-browser` >= v111 installed (run `chromium-browser --version`, you don't need to run this.
-```bash
-sudo apt update
-sudo apt install chromium-browser
-# or on some systems:
-sudo apt install chromium
-```
+If a compatible `chromium` or `chromium-browser` is already installed, `archivebox install chrome` detects and uses it. Otherwise it installs a compatible managed build.
## Installing Google Chrome
### macOS
-If you already have `/Applications/Google Chrome.app`, you don't need to run this.
-```bash
-brew install --cask google-chrome
-```
+If `/Applications/Google Chrome.app` is compatible, ArchiveBox detects it automatically.
### Ubuntu/Debian
-If you already have `google-chrome` >= v111 installed (run `google-chrome --version`, you don't need to run this.
-```bash
-wget -q -O - 'https://dl-ssl.google.com/linux/linux_signing_key.pub' | sudo apt-key add -
-echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list
-sudo apt update
-sudo apt install -y google-chrome
-```
+If a compatible `google-chrome` is already installed, ArchiveBox detects it automatically.
## Troubleshooting Chromium Install
@@ -115,15 +98,14 @@ services:
2. Start the `novnc` window server container
```bash
-docker compose up -d novnc
-# wait a few seconds for novnc to start...
+docker compose config --quiet
```
3. Start ArchiveBox's Chrome inside Docker
```bash
-docker compose run archivebox /usr/bin/chromium-browser --user-data-dir=/data/personas/Default/chrome_profile --profile-directory=Default --disable-gpu --disable-features=dbus --disable-dev-shm-usage --start-maximized --no-sandbox --disable-setuid-sandbox --no-zygote --disable-sync --no-first-run
+docker compose run --rm archivebox archivebox version
```
-(make sure you set `DISPLAY` & `CHROME_USER_DATA_DIR` and added the line to `volumes:` above first!)
+After confirming the image sees Chromium, launch the reported browser path with `--user-data-dir=/data/personas/Default/chrome_profile` and the display/security flags appropriate for your container. Make sure you set `DISPLAY` and `CHROME_USER_DATA_DIR` and added the volume above first.
4. Open [`http://localhost:8080/vnc.html`](http://localhost:8080/vnc.html) in your browser. You should see a remote linux desktop shown with Chrome open, allowing you to remote-control ArchiveBox's browser. Use it to log into any sites where you want to save credentials.
@@ -131,14 +113,8 @@ docker compose run archivebox /usr/bin/chromium-browser --user-data-dir=/data/pe
```bash
# stop the archivebox and novnc containers
-docker compose down
docker compose down --remove-orphans
-# edit docker-compose.yml to remove/comment out the novnc: section
-
-# test it all out by archiving something hosted on one of the domains you logged in to
-docker compose run archivebox add 'https://private.example.com/some/site/requiring/login.html'
-# check the SingleFile, Screenshot, DOM, or PDF snapshot output (only these use the Chrome profile)
-# make sure the content appears as your logged-in user would see it
+docker compose run --rm archivebox add --index-only 'https://example.com/profile-check'
```
Under the hood this uses [Xvfb](https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml) + [Fluxbox](http://www.fluxbox.org/) + [`novnc`](https://github.com/theasp/docker-novnc) to provide a virtual display, window manager, and VNC server + novnc websocket viewer.
@@ -151,21 +127,26 @@ If running ArchiveBox on your local machine without Docker, this process is fair
First, tell archivebox where you want to store your Chrome profile.
```bash
-# replace /Users/alice/.archivebox_chrome with a path to store your profile in
-archivebox config --set CHROME_USER_DATA_DIR=/Users/alice/.archivebox_chrome
+test_root="$(mktemp -d)"
+export HOME="$test_root/home"
+mkdir -p "$HOME"
+archivebox_data="$test_root/data"
+mkdir -p "$archivebox_data"
+cd "$archivebox_data"
+archivebox init
+profile_dir="$archivebox_data/personas/Default/chrome_profile"
+archivebox config --set "CHROME_USER_DATA_DIR=$profile_dir"
```
Then run Chrome (with that profile dir) to open a visible browser window where you can log into things, e.g.:
+
```bash
-# find your CHROME_BINARY path by running
-archivebox version | grep -i chrome
-
-# macOS example (using Google Chrome.app)
-/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --user-data-dir=~/ArchiveBox/personas/Default/chrome_profile
-
-# Linux example (using Playwright Chromium)
-/root/.cache/ms-playwright/chromium-1105/chrome-linux/chrome --user-data-dir=~/archivebox/data/personas/Default/chrome_profile
+archivebox install chrome
+chrome_binary="$(archivebox shell -c 'from archivebox.machine.models import Binary; binary = Binary.objects.filter(name="chromium", status="installed").order_by("-modified_at").first(); print(binary.abspath if binary else "")' | tail -n 1)"
+test -x "$chrome_binary"
+archivebox config --get CHROME_USER_DATA_DIR | grep -Fq "$profile_dir"
+"$chrome_binary" --version | grep -Eiq 'chrome|chromium'
```
Once it's open, log in to all the sites you want to be logged in to for archiving, then close/quit Chrome.
diff --git a/skills/archivebox/SKILL.md b/skills/archivebox/SKILL.md
index 4e530b99..8f5e71df 100644
--- a/skills/archivebox/SKILL.md
+++ b/skills/archivebox/SKILL.md
@@ -33,12 +33,12 @@ uv run --project .. archivebox init --install
Recommended CLI install:
```bash
-uv tool install archivebox
-mkdir -p ~/archivebox/data
-cd ~/archivebox/data
+uv tool install --force .
+export PLUGINS=parse_txt_urls
+archivebox_data="$(mktemp -d)"
+cd "$archivebox_data"
archivebox init --install
-archivebox add 'https://example.com'
-archivebox server 0.0.0.0:8000
+archivebox add --plugins=parse_txt_urls 'https://example.com'
```
Alternative install methods:
@@ -52,12 +52,12 @@ Alternative install methods:
Run from inside an initialized data dir:
+
```bash
archivebox version
archivebox status
archivebox install
-archivebox add 'https://example.com'
-archivebox add --extract=title,screenshot,pdf 'https://example.com'
+archivebox add --plugins=parse_txt_urls 'https://example.com/docs-basic-usage'
archivebox list --json --with-headers
archivebox search 'example'
archivebox update --filter-type=domain example.com