No description
  • Python 73%
  • JavaScript 26.6%
  • Dockerfile 0.3%
  • Shell 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Dawid Ciepiela e603903117
All checks were successful
CI / markdown (push) Successful in 11s
CI / python (push) Successful in 21m19s
ci(release): the tag input declares its type, which Forgejo's form needs to show it
2026-11-06 11:31:53 +01:00
.forgejo/workflows ci(release): the tag input declares its type, which Forgejo's form needs to show it 2026-11-06 11:31:53 +01:00
appinfo release 0.14.2 2026-11-05 05:15:09 +01:00
docs ci: the release bot's Commitizen configuration, and Conventional Commits from now on 2026-11-05 19:21:22 +01:00
ex_app recipes: Chrome Recorder import and export of the steps (Harvester's own steps as custom steps, credentials never as values), double and right clicks, browser dialogs answered, typing key by key, keys on the page, a wait step for an element shown, gone or holding a text 2026-11-05 00:18:14 +01:00
l10n recipes: Chrome Recorder import and export of the steps (Harvester's own steps as custom steps, credentials never as values), double and right clicks, browser dialogs answered, typing key by key, keys on the page, a wait step for an element shown, gone or holding a text 2026-11-05 00:18:14 +01:00
screenshots screenshots: the job's form with Save to, retaken for 0.14.0 2026-11-04 19:15:56 +01:00
scripts mail: Fetch first (Attachments, Linked files or Both), the other part's options hidden (an option's shown_when, a choice's labels), a job saved before read as it fetched (Source.upgraded, not rewritten); the hint under Pages to the on-demand job without one 2026-11-04 14:41:29 +01:00
tests recipes: Chrome Recorder import and export of the steps (Harvester's own steps as custom steps, credentials never as values), double and right clicks, browser dialogs answered, typing key by key, keys on the page, a wait step for an element shown, gone or holding a text 2026-11-05 00:18:14 +01:00
.cz.toml ci: the release bot's Commitizen configuration, and Conventional Commits from now on 2026-11-05 19:21:22 +01:00
.editorconfig SPDX lines in the Python and JavaScript sources; .editorconfig 2026-11-03 07:26:15 +01:00
.gitignore Harvester: fetch files from websites into Nextcloud by recipes 2026-10-31 17:11:26 +01:00
.markdownlint.yaml markdownlint: 100-character lines, repeated changelog headings under different versions; CHANGELOG.md spaced as it wants 2026-11-02 13:22:22 +01:00
AGENTS.md ci: the release bot's Commitizen configuration, and Conventional Commits from now on 2026-11-05 19:21:22 +01:00
CHANGELOG.md release 0.14.2 2026-11-05 05:15:09 +01:00
Dockerfile media: YouTube's challenges solved (yt-dlp-ejs, pinned by yt-dlp[pin], in the image's Node.js through a wrapper without the app's environment), its formats no longer missing 2026-11-04 23:33:03 +01:00
healthcheck.sh Harvester: fetch files from websites into Nextcloud by recipes 2026-10-31 17:11:26 +01:00
LICENSE Harvester: fetch files from websites into Nextcloud by recipes 2026-10-31 17:11:26 +01:00
pyproject.toml German (de, de_DE) and Polish translations as the PHP apps': the page, the sources' and templates' texts, the admin's settings, the API's plain errors and the notifications (translated by Nextcloud); scripts/l10n.py and tests/test_l10n.py 2026-11-03 10:17:01 +01:00
README.md recipes: Chrome Recorder import and export of the steps (Harvester's own steps as custom steps, credentials never as values), double and right clicks, browser dialogs answered, typing key by key, keys on the page, a wait step for an element shown, gone or holding a text 2026-11-05 00:18:14 +01:00
renovate.json Harvester: fetch files from websites into Nextcloud by recipes 2026-10-31 17:11:26 +01:00
requirements-dev.txt Harvester: fetch files from websites into Nextcloud by recipes 2026-10-31 17:11:26 +01:00
requirements.txt chore(deps): update dependency publicsuffixlist to v1.1.2.20261105 2026-11-05 11:30:32 +00:00
SECURITY.md AGENTS.md and SECURITY.md 2026-11-03 07:26:41 +01:00
start.sh dns: the admin's DNS servers (plain, tls://, https:// with a ClientID) for every lookup of the container through AdGuard's dnsproxy on 127.0.0.1:53, Docker's DNS as an optional fallback, the status in the admin's form, a blocked name told as such 2026-11-04 09:37:36 +01:00

Harvester

A Nextcloud External App (AppAPI, Python) that fetches files into your folders on a schedule and tags them: from websites, mailboxes, feeds, video and gallery sites, file stores and cloud drives, and release pages. It is generic: a website is described by a recipe, recorded in the app's browser or taken from a template, not by code.

  • Jobs: a source, a folder, a schedule in your time zone (or On demand: it fetches the addresses you send it), tags and an account; a progress log of what the runs do (where they look, what each listing found, the files known already, waits and retries, why a listing ended), and a run's outcome counting the known files too (0 downloaded, 37 known).
  • Sources: websites by a recipe, mailbox attachments (IMAP) or the files a message links to, or both (the log names each message of the job and what it takes from it), feeds and podcasts, videos and audio (yt-dlp), galleries (gallery-dl), file stores and cloud drives (rclone), release downloads (GitHub, GitLab, Codeberg, Forgejo, Gitea).
  • Choices: one recipe for every account or contract, every year, every child: the steps after a choice and the listing are gone through for each option of a list.
  • Exports prepared first: after Create export, a job waits (reloading if asked) until the file's link or a ready entry shows, then downloads it.
  • Pages as files: what a site offers as no file of its own: pages saved as PDF, HTML (one file) or Markdown (the main text), such as receipts and articles, also a page you send it; the PDFs and pictures a page only shows (a viewer, an <embed>, a blob:); pictures at their full size.
  • Where the files go: into your files, into Harvester's private library, a hidden space encrypted on the server that no other Nextcloud app sees (a grid or a list, sorted, Recent, files chosen for a ZIP download, a move, labels or deletion, dragged onto a folder; a viewer that goes on to the next file, details with where a file came from, uploads, a password and a recovery key; files and folders moved there from Files, and back out to Files), or into a Cryptomator vault: its inbox, which the vault app empties into the vault, or the vault itself, encrypted on the server; or photos and videos into your Immich account, into an album or the locked folder; tagged with Nextcloud's or Immich's tags, Harvester's own labels, or not at all. Another place or folder may have the files saved before downloaded again into it.
  • Recipes from and for Chrome's Recorder: a recording of Chrome DevTools' Recorder imported as a recipe's steps (its password never kept), a recipe's steps exported for it; double and right clicks, answers to the page's dialogs, waits for an element, typing key by key.
  • Tags from the sites: a page's tag chips, picked in the recorder beside the links or on the page a link opens, and gallery-dl's and yt-dlp's tags become a tag each; every page a job opens gives its title, site, date and language for file names and tags.
  • Versions and duplicates: a file whose content the job saved already from another address is not saved again; a known file that changed (asked cheaply with ETag and Last-Modified) is saved over its own, and Nextcloud keeps the one before as a version.
  • Deleted files back: a file you deleted in Nextcloud (or put in the trash) is downloaded again when the site lists it again; one you moved or renamed stays where you put it.
  • ZIP files unpacked into a folder of their name, if asked, with guards against paths out of the folder, links and zip bombs.
  • Pages watched: a page (or a part of it) compared with the last run's text, a change told in a notification with an excerpt; whitespace alone is no change.
  • Cookie banners answered on their own, "Reject all" else "Only necessary": some twenty consent managers' (OneTrust, Cookiebot, Usercentrics, Didomi, Sourcepoint, CookieYes, …) and banners of such buttons in German, English and Polish, nothing else.
  • Recorder: a browser in the app, shown on the page: sign in and pick the links (or the buttons, rows and cards without an address, which the job clicks, or a listing the page asks for as JSON, also with POST and GraphQL), and the app proposes their patterns, the files' names and tags; it adds the steps of yours (a code from the phone, an approval in an app, a handover); Test the recipe shows what a run would find.
  • Browse and try: the form of a gallery, video, feed or release job finds its page in the app's browser (Browse, Use this address); every other source's form tries its listing once before it is saved (Try the address): what a run would fetch, with the files' names and tags, what is known or left out, a mailbox's messages, or why it failed.
  • Templates for known sites (heise's magazines, podcasts, channels, galleries, releases, a page saved on demand), and recipes to export and import as files.
  • Sign-ins: passwords, one-time codes, codes by e-mail, cookies, OAuth2 for mail; kept sessions; a code from your phone (an SMS), typed on the jobs page while the run waits, or an approval in an app; when a site asks for a person (or a passkey), the job waits for you in its browser.
  • Languages: English, German and Polish: the page (also the progress log and the schedule in words), the admin's settings and the notifications follow each person's language in Nextcloud (others are English).
  • On a phone, by keyboard and with a screen reader: the jobs as cards on a phone and the recorder's screen above its steps; a job's form with the source's essentials, the other options folded into groups; Escape twice takes the keyboard out of a browser's screen; questions in a dialog of the page, errors and a run's outcomes told to screen readers once.
  • DNS servers of the admin's choice: every lookup of the app, its browsers and its helper programs through plain DNS, DNS over TLS or DNS over HTTPS (a filtering AdGuard Home, say); a blocked name is said to be blocked.
  • Careful with sites and with the server: one job per site at a time, the pauses a site asks for, files fetched once, a browser that skips images, fonts and videos while it walks a site; the browsers and downloads reach only public addresses.

Screenshots

The jobs and the progress log A new job: its source or a template
A job's form The recorder picking file links

Requirements

  • Nextcloud 32 to 36 with AppAPI and a deploy daemon (HaRP: the recorder's WebSocket goes through it).
  • Memory for the browsers: each takes some 300-600 MB, up to HARVESTER_BROWSERS (3 by default) at once.

Installing

Register the app with AppAPI on a deploy daemon: its image is ghcr.io/sarumaj/harvester, as appinfo/info.xml names it (also on Forgejo's registry). Then set the numbers of jobs and browsers, the proxy, the network guard and the DNS servers under Administration settings > Additional settings > Harvester. The administrator's guide has the details: the registry, the settings, the proxy, the DNS servers, the guard, disguise and impersonation, and the backup.

Using it

Harvester in Nextcloud's top menu lists your jobs. New job offers a card per source and per template: fill in the form (a folder, a schedule, tags, the account), or for a website record its recipe in the app's browser, test it, and save. A job runs on its schedule or with Run now; the progress log below the jobs shows what it does. The user's guide describes the jobs, the sources, the recipes, the recorder and what a run does.

How it works

The app (ex_app/lib/main.py, FastAPI with nc_py_api) keeps the jobs in SQLite in its persistent storage, and the accounts as the people's sensitive preferences in Nextcloud. Its runners take the queued jobs, one per site at a time; each source lists a site's new items and downloads them, checked, into the person's folder, and tags them. Websites with sign-in steps run in Chromium (Playwright), whose every connection goes through a guard process that lets only public addresses through. The page (ex_app/js/harvester-main.js) drives the recorder's browser over a WebSocket. The developer's guide has the layout, the tests and how a release is made.

Developing

python3 -m venv .venv && URLLIB3_NO_OVERRIDE=1 .venv/bin/pip install --no-binary=urllib3-future \
    -r requirements-dev.txt
.venv/bin/playwright install chromium
.venv/bin/python -m pytest -q
.venv/bin/black --check ex_app tests scripts && .venv/bin/pylint ex_app/lib tests scripts
.venv/bin/python scripts/l10n.py
npx --yes markdownlint-cli2 "*.md" "docs/**/*.md"

More in the developer's guide, also how a text is translated; the changes are in the changelog.

Reporting problems

Open an issue on Forgejo, dawid/nextcloud-harvester, or on its GitHub mirror, sarumaj/nextcloud-harvester. A security problem goes privately, as SECURITY.md says.

Licence

AGPL-3.0-or-later.