kpihx-web 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kpihx_web-2.2.0/PKG-INFO +275 -0
- kpihx_web-2.2.0/README.md +246 -0
- kpihx_web-2.2.0/pyproject.toml +61 -0
- kpihx_web-2.2.0/src/k_web/__init__.py +8 -0
- kpihx_web-2.2.0/src/k_web/audio.py +65 -0
- kpihx_web-2.2.0/src/k_web/backend.py +277 -0
- kpihx_web-2.2.0/src/k_web/cli.py +794 -0
- kpihx_web-2.2.0/src/k_web/config.py +35 -0
- kpihx_web-2.2.0/src/k_web/diagnostics.py +132 -0
- kpihx_web-2.2.0/src/k_web/documents.py +187 -0
- kpihx_web-2.2.0/src/k_web/help_text.py +252 -0
- kpihx_web-2.2.0/src/k_web/http.py +316 -0
- kpihx_web-2.2.0/src/k_web/images.py +147 -0
- kpihx_web-2.2.0/src/k_web/maps.py +179 -0
- kpihx_web-2.2.0/src/k_web/models.py +42 -0
- kpihx_web-2.2.0/src/k_web/output.py +268 -0
- kpihx_web-2.2.0/src/k_web/research.py +551 -0
- kpihx_web-2.2.0/src/k_web/search_cache.py +44 -0
- kpihx_web-2.2.0/src/k_web/user_config.py +56 -0
kpihx_web-2.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: kpihx-web
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: Private CLI for metasearch, verified retrieval, bounded crawling and media investigation
|
|
5
|
+
License: MIT
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Dist: beautifulsoup4
|
|
10
|
+
Requires-Dist: defusedxml>=0.7.1
|
|
11
|
+
Requires-Dist: fpdf2>=2.8.9
|
|
12
|
+
Requires-Dist: httpx[socks]
|
|
13
|
+
Requires-Dist: lxml
|
|
14
|
+
Requires-Dist: phonenumbers>=9.0.41
|
|
15
|
+
Requires-Dist: picimagesearch
|
|
16
|
+
Requires-Dist: pillow
|
|
17
|
+
Requires-Dist: pypdf
|
|
18
|
+
Requires-Dist: python-docx
|
|
19
|
+
Requires-Dist: regex>=2026.9.29
|
|
20
|
+
Requires-Dist: requests[socks]
|
|
21
|
+
Requires-Dist: rich
|
|
22
|
+
Requires-Dist: typer
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Project-URL: Repository, https://github.com/kpihx-labs/web
|
|
25
|
+
Project-URL: GitLab, https://gitlab.com/kpihx-labs/web
|
|
26
|
+
Project-URL: Issues, https://github.com/kpihx-labs/web/issues
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# web (kpihx-web)
|
|
31
|
+
|
|
32
|
+
Local-first research CLI: discover indexed sources, retrieve content, verify
|
|
33
|
+
evidence and preserve provenance. Python distribution: kpihx-web; executable: web.
|
|
34
|
+
The previous implementation and documentation remain under references/ for audit.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
Use `make install` from a clone, or `uv tool install kpihx-web` then `web setup`.
|
|
39
|
+
Run `make help` for dependency installation guidance, backend health/recovery,
|
|
40
|
+
testing and uninstall/purge targets. uv manages Python dependencies and uv_build
|
|
41
|
+
builds the package. No Hatch backend, paid recognition provider or transcription.
|
|
42
|
+
|
|
43
|
+
Clone either SSH remote, keeping the projects directly under your project root:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
git clone git@github.com:kpihx-labs/web.git
|
|
47
|
+
# Alternative: git clone git@gitlab.com:kpihx-labs/web.git
|
|
48
|
+
make -C web install
|
|
49
|
+
make -C web backend-clone HOST=github # or HOST=gitlab; retains an existing sibling
|
|
50
|
+
make -C web backend-up
|
|
51
|
+
web doctor --live
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Discover the CLI without guessing (2.2)
|
|
55
|
+
|
|
56
|
+
Every command level has a purpose/limits explanation, at least three varied
|
|
57
|
+
examples, and descriptions with examples for every argument and long/short flag.
|
|
58
|
+
The help is offline: it does not query providers, record audio, inspect files or
|
|
59
|
+
purge state. Explore the whole tree, including map's distinct API operations:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
web --help
|
|
63
|
+
web search --help
|
|
64
|
+
web doc --help
|
|
65
|
+
web map --help
|
|
66
|
+
web map search --help
|
|
67
|
+
web map query --help
|
|
68
|
+
web map route --help
|
|
69
|
+
web map request --help
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The recursive help contract and example parser tests fail if a new command ships
|
|
73
|
+
an undocumented option, missing short/long alias, or fewer than three examples.
|
|
74
|
+
Generated help remains English, like the code. Detailed shared descriptions live
|
|
75
|
+
in help_text.py, with explicit references at each Typer declaration.
|
|
76
|
+
|
|
77
|
+
## Search precision, budgets and provenance
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
web search '"Lado Saha" site:lig-membres.imag.fr -annuaire' -e 'google cse' -P 2 -n 30
|
|
81
|
+
web search '("memory scheduling" OR "unified memory") filetype:pdf after:2023' -P 3 -n 0 -f json
|
|
82
|
+
web search @query.txt -X '{"time_range":"year"}' -c science -l en -m 1
|
|
83
|
+
web search 'python logo' -c images -f json
|
|
84
|
+
web engines -r 'google|bing|duck'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Quotes, Boolean operators, exclusions, site:, filetype:, intitle:, inurl: and date
|
|
88
|
+
operators pass through unchanged. Support depends on the selected engine; there
|
|
89
|
+
is no universal Google syntax translator. `-X/--params` accepts arbitrary
|
|
90
|
+
SearXNG JSON or @file, while preserving the query/JSON response contract.
|
|
91
|
+
Unknown engine names fail rather than silently querying defaults. `provider_fields`
|
|
92
|
+
retains raw result metadata, including image URLs and provider-specific fields.
|
|
93
|
+
|
|
94
|
+
`-n 30` is a best-effort collection target: fetch further pages until 30 unique
|
|
95
|
+
filtered candidates, source exhaustion/failure or the page-request budget. Both
|
|
96
|
+
`-p` and legacy `-P` now mean --max-pages (default 3); --start-page/-s is separate.
|
|
97
|
+
This corrects 2.0's confusing -p=start/-P=count distinction. `-n 0` collects within
|
|
98
|
+
the full explicit budget. Output reports actual requests, counts and stop_reason;
|
|
99
|
+
it never pads or invents results when the target cannot be reached.
|
|
100
|
+
Default relevance ranking orders term coverage then SearXNG's numeric aggregate
|
|
101
|
+
score. `-k provider` sorts by that score alone (not API array/arrival order);
|
|
102
|
+
`-k lexical` uses term coverage only. None establishes identity or semantic truth.
|
|
103
|
+
Regex/domain filtering
|
|
104
|
+
precedes the display limit. Regular expressions use a configurable regex_timeout
|
|
105
|
+
budget rather than unbounded backtracking. URL dedup preserves meaningful query/path case.
|
|
106
|
+
SafeSearch `-m 0/1/2` is requested upstream; off does not remove upstream censorship.
|
|
107
|
+
|
|
108
|
+
Repeated identical searches reuse a labelled private snapshot for 300 seconds,
|
|
109
|
+
independent of table/JSON format. --fresh/-F forces live collection and forbids
|
|
110
|
+
stale fallback. --no-save also disables query-cache persistence/reuse. On failure,
|
|
111
|
+
a default request may return a clearly marked stale snapshot up to 24 hours old,
|
|
112
|
+
with partial status and the error; it is never represented as a new live result.
|
|
113
|
+
TTL, max pages, page delay and fallback_engines are plain configurable SETTINGS.
|
|
114
|
+
If defaults stall and a page-request budget remains, keyless Yahoo/Yep/MWMBL are
|
|
115
|
+
queried once as an explicit alternative batch. No IP/account switching, CAPTCHA
|
|
116
|
+
bypass or rate-limit evasion occurs. Explicit -e choices are not silently replaced.
|
|
117
|
+
|
|
118
|
+
The table shows **Sources**, a full contributor list, and folds complete URLs
|
|
119
|
+
without ellipses. Engine coverage distinguishes contributions, CAPTCHA, rate
|
|
120
|
+
limits and no-results-reported; the latter is not proof an engine was queried or
|
|
121
|
+
is healthy. Provider refusal does not recommend restarting Docker/VPN. Search
|
|
122
|
+
reads index snippets; use fetch separately to inspect actual page content.
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
web search 'KAMDEM Ivann' -n 30 -p 5
|
|
126
|
+
web show /tmp/web-results/SEARCH_SNAPSHOT.json -f table
|
|
127
|
+
web show /tmp/web-results/SEARCH_SNAPSHOT.json -f json
|
|
128
|
+
```
|
|
129
|
+
`show` renders exactly the saved snapshot without any network request, allowing
|
|
130
|
+
an honest table/JSON comparison. Different live requests may receive different
|
|
131
|
+
provider responses, even when their query text is identical.
|
|
132
|
+
|
|
133
|
+
## Fetch, inspection, sessions and exact downloads
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
web fetch https://example.org -s 'article h2' -r 'privacy|research' -f json
|
|
137
|
+
web fetch https://example.org/document.pdf -d /tmp/document.pdf
|
|
138
|
+
web fetch https://authorized.example/private -C /private/cookies.txt -H @/private/headers.json
|
|
139
|
+
web crawl https://quotes.toscrape.com -D 3 -n 4 -d /tmp/quotes-pages
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Fetch downloads once, records MIME/byte SHA256 and extracts links from those same
|
|
143
|
+
bytes. Binary responses are not parsed as HTML. `--download` preserves exact
|
|
144
|
+
response bytes; existing files are refused. CSS and regex inspection use the
|
|
145
|
+
retrieved body, without extra requests. HTTP 200 login/registration/challenge
|
|
146
|
+
pages are classified as partial access, not useful source reads. These heuristics
|
|
147
|
+
can miss unusual walls; inspect access_state and content, not status alone.
|
|
148
|
+
|
|
149
|
+
Cookies accept Netscape including HttpOnly comments, browser JSON records or a
|
|
150
|
+
flat dictionary scoped to the seed host. Domain/path/secure/expiry restrictions
|
|
151
|
+
are honored. Custom headers are limited to the original origin across redirects;
|
|
152
|
+
header files avoid leaking tokens in shell history. Never send actual session
|
|
153
|
+
values to agents or paste them into reports. Requests ignore environment proxies;
|
|
154
|
+
`--proxy` explicitly selects HTTP/SOCKS. No TLS verification bypass is provided.
|
|
155
|
+
|
|
156
|
+
Crawl is same-host, paced (`--delay`), depth/page bounded and robots-aware by
|
|
157
|
+
default. `--no-robots` is explicit, not a bypass of authorization or terms.
|
|
158
|
+
Next/rel=next links are prioritized; JS scroll/click/API pagination is not executed.
|
|
159
|
+
`--match` restricts downloads, not traversal. Errors and remaining frontier are
|
|
160
|
+
retained in the manifest. New output directories avoid collisions on reruns.
|
|
161
|
+
Private/local destinations need `--allow-private` for your own services.
|
|
162
|
+
`--exclude` is a URL-frontier regex; its configurable default guards common
|
|
163
|
+
logout/delete/checkout GET links. An explicit empty expression disables it after
|
|
164
|
+
review. This heuristic is not proof GET is side-effect-free: use a dedicated
|
|
165
|
+
authorized session and inspect the frontier before crawling sensitive accounts.
|
|
166
|
+
DNS checks are best effort, not a security sandbox against hostile DNS rebinding.
|
|
167
|
+
|
|
168
|
+
For JS, authenticated DOM or browser challenges, use browser-proxy independently
|
|
169
|
+
with your authorization. A cookie handoff can help ordinary sessions but cannot
|
|
170
|
+
reproduce every browser/TLS fingerprint. This CLI never promises to bypass all
|
|
171
|
+
CAPTCHAs, paywalls, permissions or account login.
|
|
172
|
+
|
|
173
|
+
## Documents, images and audio
|
|
174
|
+
|
|
175
|
+
```sh
|
|
176
|
+
web doc report.pdf --compare other.pdf --ocr --pages 10 --report /tmp/evidence.pdf
|
|
177
|
+
web doc public-report.md --online --samples 3 --limit 5
|
|
178
|
+
web image photo.jpg # local metadata only
|
|
179
|
+
web image https://public.example/logo.png # remote input, still no reverse upload
|
|
180
|
+
web image public-logo.png --online -e yandex,google,bing --text-search
|
|
181
|
+
web audio excerpt.mp3
|
|
182
|
+
web audio --record 12 --mode hum
|
|
183
|
+
web archive https://public.example/report.pdf -P '{"timestamp":"20240101"}'
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Doc is offline by default: --online discloses sampled quotes to search engines.
|
|
187
|
+
PDF/DOCX tables/ODT/PPTX and UTF-8 TXT/MD/CSV/JSON/HTML/XML/RST/TeX are supported;
|
|
188
|
+
unknown binary must be exported, not decoded as garbage. Scanned PDFs require
|
|
189
|
+
explicit OCR and are rendered to temporary images before Tesseract.
|
|
190
|
+
These parsers are not a malware sandbox; use OS isolation for hostile files.
|
|
191
|
+
Page limit 0 selects all pages and can be expensive. Comparisons provide exact byte equality
|
|
192
|
+
and lexical matching spans, NOT semantic equivalence or a plagiarism verdict.
|
|
193
|
+
Online links are candidates; downloaded content is checked separately. A hash
|
|
194
|
+
search result alone is not proof a file leaked. Archive uses Wayback's closest
|
|
195
|
+
snapshot API only; no Archive.today API or exhaustive historical search is claimed.
|
|
196
|
+
|
|
197
|
+
Image uploads require --online and omit original EXIF/GPS. Providers are fragile
|
|
198
|
+
unofficial adapters: failures or empty responses are not proof of absent copies.
|
|
199
|
+
--text-search explicitly discloses local OCR words as a complementary text search;
|
|
200
|
+
those results are not verified visual matches. GPS/device/time are local metadata.
|
|
201
|
+
|
|
202
|
+
Audio uses free SongRec/Shazam; FFmpeg normalizes/records an excerpt. `hum` is a
|
|
203
|
+
qualified best-effort fingerprint attempt and returns partial status: SongRec is
|
|
204
|
+
not a melody recognizer and reliable free humming is not established. ACRCloud,
|
|
205
|
+
paid API logic and credential loading are removed. No transcription is performed.
|
|
206
|
+
|
|
207
|
+
## Hidden networks and limits
|
|
208
|
+
|
|
209
|
+
Tor fetch uses SOCKS5h (managed optional profile: 127.0.0.1:19050; override
|
|
210
|
+
tor_proxy for an existing external daemon, commonly 9050); once selected, redirects do not
|
|
211
|
+
downgrade to direct or resolve through local DNS. I2P fetch requires an actual
|
|
212
|
+
HTTP proxy (default 127.0.0.1:4444). There is no fake I2P search adapter. For
|
|
213
|
+
indexed onion discovery use `web search QUERY -e ahmia -c onions`; coverage and
|
|
214
|
+
uptime depend on the index and Tor. Private/unindexed content has no universal
|
|
215
|
+
search engine. No tool can enumerate your complete digital footprint or prove
|
|
216
|
+
absence of a leak from absent results. No arbitrary third-party kill switch
|
|
217
|
+
compatibility or perfect anonymity is promised.
|
|
218
|
+
|
|
219
|
+
Surface SearXNG startup is independent of Tor. `make -C ../searxng onion-up`
|
|
220
|
+
explicitly starts an isolated optional onion worker; a failed Tor check does not
|
|
221
|
+
crash the surface worker. `web engines -z onion` inspects it. `web search QUERY
|
|
222
|
+
-e bing,ahmia` partitions those engines between backends and reports missing
|
|
223
|
+
coverage rather than losing working surface results. `-z surface,onion` explicitly
|
|
224
|
+
selects both, or use custom `SETTINGS['search_backends']` entries with url/socket
|
|
225
|
+
fields for another SearXNG-compatible backend. Budgets apply per backend, so total
|
|
226
|
+
requests grow with the number of selected backends. Protocols other than SearXNG
|
|
227
|
+
still need an adapter; arbitrary services are not interchangeable by naming them.
|
|
228
|
+
|
|
229
|
+
## Configuration, dependencies and lifecycle
|
|
230
|
+
|
|
231
|
+
`web setup` creates ~/.config/web/config.py only if absent. SETTINGS is plain
|
|
232
|
+
trusted Python, not a loader framework. WEB_CONFIG_DIR and standard XDG roots
|
|
233
|
+
control configuration where supported. Existing xsearch configuration/cache were
|
|
234
|
+
moved, not destroyed; dormant old .env credentials are never loaded. Defaults in
|
|
235
|
+
config.py include response_max_bytes, local_max_bytes, xml_max_bytes and
|
|
236
|
+
max_redirects; put overrides in SETTINGS.
|
|
237
|
+
Set phone_region (for example FR) to validate national-format numbers; without
|
|
238
|
+
a region hint, international numbers are preferred rather than guessing dates.
|
|
239
|
+
Local SearXNG prefers its owner-only
|
|
240
|
+
Unix socket to avoid host VPN TCP routing; remote endpoints remain explicit.
|
|
241
|
+
|
|
242
|
+
Python libraries are resolved with bare uv add and uv.lock, never pip or manual
|
|
243
|
+
dependency arrays. System dependencies are deliberately separate/shared:
|
|
244
|
+
|
|
245
|
+
| Feature | Native dependency / installation guidance |
|
|
246
|
+
| --- | --- |
|
|
247
|
+
| Audio | ffmpeg; SongRec via Cargo: cargo install songrec --no-default-features --features ffmpeg |
|
|
248
|
+
| SongRec source build | Rust/Cargo, pkg-config, Clang/libclang, libsoup-3.0-dev, ALSA/PipeWire development headers as required upstream |
|
|
249
|
+
| PDF OCR | poppler-utils (pdftoppm), tesseract-ocr and desired language data |
|
|
250
|
+
| Unicode PDF report | fontconfig (fc-match), fonts-dejavu-core; fpdf2 is managed by uv |
|
|
251
|
+
| Backend | Docker Engine and Compose plugin; sibling searxng repository documents images/ports/volumes |
|
|
252
|
+
| Tor/I2P | Your own reachable Tor SOCKS5h/I2P HTTP proxy; never silently started |
|
|
253
|
+
|
|
254
|
+
Use upstream package instructions for your OS; dependency install commands evolve.
|
|
255
|
+
`make deps` reports installed native capabilities and guidance rather than a rigid
|
|
256
|
+
root installer. Cold builds need network or cached packages/images. Docker logs
|
|
257
|
+
are bounded by the backend; web has no background daemon or persistent log file.
|
|
258
|
+
JSON evidence is not silently rotated/deleted; /tmp is volatile. Explicit
|
|
259
|
+
download/report destinations are user evidence and not automatically purged.
|
|
260
|
+
|
|
261
|
+
`make uninstall` removes the uv tool only. `make purge` stops the sibling backend,
|
|
262
|
+
trashes owned runtime paths, uninstalls the tool, and retains source/shared native
|
|
263
|
+
tools. `make backend-purge CONFIRM=searxng` backs up named volumes under a private
|
|
264
|
+
/tmp directory (.bak files), then removes only that stack's volumes. Review its
|
|
265
|
+
Make recipe first. Never run global Docker prune. A clone is retained so reinstall
|
|
266
|
+
works from either GitHub or GitLab. `make purge-all CONFIRM=searxng` sequences
|
|
267
|
+
the confirmed backend backup/removal and app purge. Install from PyPI using
|
|
268
|
+
uv tool install kpihx-web.
|
|
269
|
+
|
|
270
|
+
All commands use an action/timestamp/status/data envelope. Formats: table, json,
|
|
271
|
+
jsonl, csv, md; --report creates escaped offline HTML or a real PDF. Autosaves are
|
|
272
|
+
unique 0600 JSON in /tmp/web-results; -S overrides and -N disables. Exit 2 is
|
|
273
|
+
failure, exit 3 is partial/access-wall coverage, exit 0 is completion. Inspect
|
|
274
|
+
non_exhaustive, budgets and source errors before drawing conclusions. Source
|
|
275
|
+
quality, identity attribution and correctness require human corroboration.
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# web (kpihx-web)
|
|
2
|
+
|
|
3
|
+
Local-first research CLI: discover indexed sources, retrieve content, verify
|
|
4
|
+
evidence and preserve provenance. Python distribution: kpihx-web; executable: web.
|
|
5
|
+
The previous implementation and documentation remain under references/ for audit.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Use `make install` from a clone, or `uv tool install kpihx-web` then `web setup`.
|
|
10
|
+
Run `make help` for dependency installation guidance, backend health/recovery,
|
|
11
|
+
testing and uninstall/purge targets. uv manages Python dependencies and uv_build
|
|
12
|
+
builds the package. No Hatch backend, paid recognition provider or transcription.
|
|
13
|
+
|
|
14
|
+
Clone either SSH remote, keeping the projects directly under your project root:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
git clone git@github.com:kpihx-labs/web.git
|
|
18
|
+
# Alternative: git clone git@gitlab.com:kpihx-labs/web.git
|
|
19
|
+
make -C web install
|
|
20
|
+
make -C web backend-clone HOST=github # or HOST=gitlab; retains an existing sibling
|
|
21
|
+
make -C web backend-up
|
|
22
|
+
web doctor --live
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Discover the CLI without guessing (2.2)
|
|
26
|
+
|
|
27
|
+
Every command level has a purpose/limits explanation, at least three varied
|
|
28
|
+
examples, and descriptions with examples for every argument and long/short flag.
|
|
29
|
+
The help is offline: it does not query providers, record audio, inspect files or
|
|
30
|
+
purge state. Explore the whole tree, including map's distinct API operations:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
web --help
|
|
34
|
+
web search --help
|
|
35
|
+
web doc --help
|
|
36
|
+
web map --help
|
|
37
|
+
web map search --help
|
|
38
|
+
web map query --help
|
|
39
|
+
web map route --help
|
|
40
|
+
web map request --help
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The recursive help contract and example parser tests fail if a new command ships
|
|
44
|
+
an undocumented option, missing short/long alias, or fewer than three examples.
|
|
45
|
+
Generated help remains English, like the code. Detailed shared descriptions live
|
|
46
|
+
in help_text.py, with explicit references at each Typer declaration.
|
|
47
|
+
|
|
48
|
+
## Search precision, budgets and provenance
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
web search '"Lado Saha" site:lig-membres.imag.fr -annuaire' -e 'google cse' -P 2 -n 30
|
|
52
|
+
web search '("memory scheduling" OR "unified memory") filetype:pdf after:2023' -P 3 -n 0 -f json
|
|
53
|
+
web search @query.txt -X '{"time_range":"year"}' -c science -l en -m 1
|
|
54
|
+
web search 'python logo' -c images -f json
|
|
55
|
+
web engines -r 'google|bing|duck'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Quotes, Boolean operators, exclusions, site:, filetype:, intitle:, inurl: and date
|
|
59
|
+
operators pass through unchanged. Support depends on the selected engine; there
|
|
60
|
+
is no universal Google syntax translator. `-X/--params` accepts arbitrary
|
|
61
|
+
SearXNG JSON or @file, while preserving the query/JSON response contract.
|
|
62
|
+
Unknown engine names fail rather than silently querying defaults. `provider_fields`
|
|
63
|
+
retains raw result metadata, including image URLs and provider-specific fields.
|
|
64
|
+
|
|
65
|
+
`-n 30` is a best-effort collection target: fetch further pages until 30 unique
|
|
66
|
+
filtered candidates, source exhaustion/failure or the page-request budget. Both
|
|
67
|
+
`-p` and legacy `-P` now mean --max-pages (default 3); --start-page/-s is separate.
|
|
68
|
+
This corrects 2.0's confusing -p=start/-P=count distinction. `-n 0` collects within
|
|
69
|
+
the full explicit budget. Output reports actual requests, counts and stop_reason;
|
|
70
|
+
it never pads or invents results when the target cannot be reached.
|
|
71
|
+
Default relevance ranking orders term coverage then SearXNG's numeric aggregate
|
|
72
|
+
score. `-k provider` sorts by that score alone (not API array/arrival order);
|
|
73
|
+
`-k lexical` uses term coverage only. None establishes identity or semantic truth.
|
|
74
|
+
Regex/domain filtering
|
|
75
|
+
precedes the display limit. Regular expressions use a configurable regex_timeout
|
|
76
|
+
budget rather than unbounded backtracking. URL dedup preserves meaningful query/path case.
|
|
77
|
+
SafeSearch `-m 0/1/2` is requested upstream; off does not remove upstream censorship.
|
|
78
|
+
|
|
79
|
+
Repeated identical searches reuse a labelled private snapshot for 300 seconds,
|
|
80
|
+
independent of table/JSON format. --fresh/-F forces live collection and forbids
|
|
81
|
+
stale fallback. --no-save also disables query-cache persistence/reuse. On failure,
|
|
82
|
+
a default request may return a clearly marked stale snapshot up to 24 hours old,
|
|
83
|
+
with partial status and the error; it is never represented as a new live result.
|
|
84
|
+
TTL, max pages, page delay and fallback_engines are plain configurable SETTINGS.
|
|
85
|
+
If defaults stall and a page-request budget remains, keyless Yahoo/Yep/MWMBL are
|
|
86
|
+
queried once as an explicit alternative batch. No IP/account switching, CAPTCHA
|
|
87
|
+
bypass or rate-limit evasion occurs. Explicit -e choices are not silently replaced.
|
|
88
|
+
|
|
89
|
+
The table shows **Sources**, a full contributor list, and folds complete URLs
|
|
90
|
+
without ellipses. Engine coverage distinguishes contributions, CAPTCHA, rate
|
|
91
|
+
limits and no-results-reported; the latter is not proof an engine was queried or
|
|
92
|
+
is healthy. Provider refusal does not recommend restarting Docker/VPN. Search
|
|
93
|
+
reads index snippets; use fetch separately to inspect actual page content.
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
web search 'KAMDEM Ivann' -n 30 -p 5
|
|
97
|
+
web show /tmp/web-results/SEARCH_SNAPSHOT.json -f table
|
|
98
|
+
web show /tmp/web-results/SEARCH_SNAPSHOT.json -f json
|
|
99
|
+
```
|
|
100
|
+
`show` renders exactly the saved snapshot without any network request, allowing
|
|
101
|
+
an honest table/JSON comparison. Different live requests may receive different
|
|
102
|
+
provider responses, even when their query text is identical.
|
|
103
|
+
|
|
104
|
+
## Fetch, inspection, sessions and exact downloads
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
web fetch https://example.org -s 'article h2' -r 'privacy|research' -f json
|
|
108
|
+
web fetch https://example.org/document.pdf -d /tmp/document.pdf
|
|
109
|
+
web fetch https://authorized.example/private -C /private/cookies.txt -H @/private/headers.json
|
|
110
|
+
web crawl https://quotes.toscrape.com -D 3 -n 4 -d /tmp/quotes-pages
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Fetch downloads once, records MIME/byte SHA256 and extracts links from those same
|
|
114
|
+
bytes. Binary responses are not parsed as HTML. `--download` preserves exact
|
|
115
|
+
response bytes; existing files are refused. CSS and regex inspection use the
|
|
116
|
+
retrieved body, without extra requests. HTTP 200 login/registration/challenge
|
|
117
|
+
pages are classified as partial access, not useful source reads. These heuristics
|
|
118
|
+
can miss unusual walls; inspect access_state and content, not status alone.
|
|
119
|
+
|
|
120
|
+
Cookies accept Netscape including HttpOnly comments, browser JSON records or a
|
|
121
|
+
flat dictionary scoped to the seed host. Domain/path/secure/expiry restrictions
|
|
122
|
+
are honored. Custom headers are limited to the original origin across redirects;
|
|
123
|
+
header files avoid leaking tokens in shell history. Never send actual session
|
|
124
|
+
values to agents or paste them into reports. Requests ignore environment proxies;
|
|
125
|
+
`--proxy` explicitly selects HTTP/SOCKS. No TLS verification bypass is provided.
|
|
126
|
+
|
|
127
|
+
Crawl is same-host, paced (`--delay`), depth/page bounded and robots-aware by
|
|
128
|
+
default. `--no-robots` is explicit, not a bypass of authorization or terms.
|
|
129
|
+
Next/rel=next links are prioritized; JS scroll/click/API pagination is not executed.
|
|
130
|
+
`--match` restricts downloads, not traversal. Errors and remaining frontier are
|
|
131
|
+
retained in the manifest. New output directories avoid collisions on reruns.
|
|
132
|
+
Private/local destinations need `--allow-private` for your own services.
|
|
133
|
+
`--exclude` is a URL-frontier regex; its configurable default guards common
|
|
134
|
+
logout/delete/checkout GET links. An explicit empty expression disables it after
|
|
135
|
+
review. This heuristic is not proof GET is side-effect-free: use a dedicated
|
|
136
|
+
authorized session and inspect the frontier before crawling sensitive accounts.
|
|
137
|
+
DNS checks are best effort, not a security sandbox against hostile DNS rebinding.
|
|
138
|
+
|
|
139
|
+
For JS, authenticated DOM or browser challenges, use browser-proxy independently
|
|
140
|
+
with your authorization. A cookie handoff can help ordinary sessions but cannot
|
|
141
|
+
reproduce every browser/TLS fingerprint. This CLI never promises to bypass all
|
|
142
|
+
CAPTCHAs, paywalls, permissions or account login.
|
|
143
|
+
|
|
144
|
+
## Documents, images and audio
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
web doc report.pdf --compare other.pdf --ocr --pages 10 --report /tmp/evidence.pdf
|
|
148
|
+
web doc public-report.md --online --samples 3 --limit 5
|
|
149
|
+
web image photo.jpg # local metadata only
|
|
150
|
+
web image https://public.example/logo.png # remote input, still no reverse upload
|
|
151
|
+
web image public-logo.png --online -e yandex,google,bing --text-search
|
|
152
|
+
web audio excerpt.mp3
|
|
153
|
+
web audio --record 12 --mode hum
|
|
154
|
+
web archive https://public.example/report.pdf -P '{"timestamp":"20240101"}'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Doc is offline by default: --online discloses sampled quotes to search engines.
|
|
158
|
+
PDF/DOCX tables/ODT/PPTX and UTF-8 TXT/MD/CSV/JSON/HTML/XML/RST/TeX are supported;
|
|
159
|
+
unknown binary must be exported, not decoded as garbage. Scanned PDFs require
|
|
160
|
+
explicit OCR and are rendered to temporary images before Tesseract.
|
|
161
|
+
These parsers are not a malware sandbox; use OS isolation for hostile files.
|
|
162
|
+
Page limit 0 selects all pages and can be expensive. Comparisons provide exact byte equality
|
|
163
|
+
and lexical matching spans, NOT semantic equivalence or a plagiarism verdict.
|
|
164
|
+
Online links are candidates; downloaded content is checked separately. A hash
|
|
165
|
+
search result alone is not proof a file leaked. Archive uses Wayback's closest
|
|
166
|
+
snapshot API only; no Archive.today API or exhaustive historical search is claimed.
|
|
167
|
+
|
|
168
|
+
Image uploads require --online and omit original EXIF/GPS. Providers are fragile
|
|
169
|
+
unofficial adapters: failures or empty responses are not proof of absent copies.
|
|
170
|
+
--text-search explicitly discloses local OCR words as a complementary text search;
|
|
171
|
+
those results are not verified visual matches. GPS/device/time are local metadata.
|
|
172
|
+
|
|
173
|
+
Audio uses free SongRec/Shazam; FFmpeg normalizes/records an excerpt. `hum` is a
|
|
174
|
+
qualified best-effort fingerprint attempt and returns partial status: SongRec is
|
|
175
|
+
not a melody recognizer and reliable free humming is not established. ACRCloud,
|
|
176
|
+
paid API logic and credential loading are removed. No transcription is performed.
|
|
177
|
+
|
|
178
|
+
## Hidden networks and limits
|
|
179
|
+
|
|
180
|
+
Tor fetch uses SOCKS5h (managed optional profile: 127.0.0.1:19050; override
|
|
181
|
+
tor_proxy for an existing external daemon, commonly 9050); once selected, redirects do not
|
|
182
|
+
downgrade to direct or resolve through local DNS. I2P fetch requires an actual
|
|
183
|
+
HTTP proxy (default 127.0.0.1:4444). There is no fake I2P search adapter. For
|
|
184
|
+
indexed onion discovery use `web search QUERY -e ahmia -c onions`; coverage and
|
|
185
|
+
uptime depend on the index and Tor. Private/unindexed content has no universal
|
|
186
|
+
search engine. No tool can enumerate your complete digital footprint or prove
|
|
187
|
+
absence of a leak from absent results. No arbitrary third-party kill switch
|
|
188
|
+
compatibility or perfect anonymity is promised.
|
|
189
|
+
|
|
190
|
+
Surface SearXNG startup is independent of Tor. `make -C ../searxng onion-up`
|
|
191
|
+
explicitly starts an isolated optional onion worker; a failed Tor check does not
|
|
192
|
+
crash the surface worker. `web engines -z onion` inspects it. `web search QUERY
|
|
193
|
+
-e bing,ahmia` partitions those engines between backends and reports missing
|
|
194
|
+
coverage rather than losing working surface results. `-z surface,onion` explicitly
|
|
195
|
+
selects both, or use custom `SETTINGS['search_backends']` entries with url/socket
|
|
196
|
+
fields for another SearXNG-compatible backend. Budgets apply per backend, so total
|
|
197
|
+
requests grow with the number of selected backends. Protocols other than SearXNG
|
|
198
|
+
still need an adapter; arbitrary services are not interchangeable by naming them.
|
|
199
|
+
|
|
200
|
+
## Configuration, dependencies and lifecycle
|
|
201
|
+
|
|
202
|
+
`web setup` creates ~/.config/web/config.py only if absent. SETTINGS is plain
|
|
203
|
+
trusted Python, not a loader framework. WEB_CONFIG_DIR and standard XDG roots
|
|
204
|
+
control configuration where supported. Existing xsearch configuration/cache were
|
|
205
|
+
moved, not destroyed; dormant old .env credentials are never loaded. Defaults in
|
|
206
|
+
config.py include response_max_bytes, local_max_bytes, xml_max_bytes and
|
|
207
|
+
max_redirects; put overrides in SETTINGS.
|
|
208
|
+
Set phone_region (for example FR) to validate national-format numbers; without
|
|
209
|
+
a region hint, international numbers are preferred rather than guessing dates.
|
|
210
|
+
Local SearXNG prefers its owner-only
|
|
211
|
+
Unix socket to avoid host VPN TCP routing; remote endpoints remain explicit.
|
|
212
|
+
|
|
213
|
+
Python libraries are resolved with bare uv add and uv.lock, never pip or manual
|
|
214
|
+
dependency arrays. System dependencies are deliberately separate/shared:
|
|
215
|
+
|
|
216
|
+
| Feature | Native dependency / installation guidance |
|
|
217
|
+
| --- | --- |
|
|
218
|
+
| Audio | ffmpeg; SongRec via Cargo: cargo install songrec --no-default-features --features ffmpeg |
|
|
219
|
+
| SongRec source build | Rust/Cargo, pkg-config, Clang/libclang, libsoup-3.0-dev, ALSA/PipeWire development headers as required upstream |
|
|
220
|
+
| PDF OCR | poppler-utils (pdftoppm), tesseract-ocr and desired language data |
|
|
221
|
+
| Unicode PDF report | fontconfig (fc-match), fonts-dejavu-core; fpdf2 is managed by uv |
|
|
222
|
+
| Backend | Docker Engine and Compose plugin; sibling searxng repository documents images/ports/volumes |
|
|
223
|
+
| Tor/I2P | Your own reachable Tor SOCKS5h/I2P HTTP proxy; never silently started |
|
|
224
|
+
|
|
225
|
+
Use upstream package instructions for your OS; dependency install commands evolve.
|
|
226
|
+
`make deps` reports installed native capabilities and guidance rather than a rigid
|
|
227
|
+
root installer. Cold builds need network or cached packages/images. Docker logs
|
|
228
|
+
are bounded by the backend; web has no background daemon or persistent log file.
|
|
229
|
+
JSON evidence is not silently rotated/deleted; /tmp is volatile. Explicit
|
|
230
|
+
download/report destinations are user evidence and not automatically purged.
|
|
231
|
+
|
|
232
|
+
`make uninstall` removes the uv tool only. `make purge` stops the sibling backend,
|
|
233
|
+
trashes owned runtime paths, uninstalls the tool, and retains source/shared native
|
|
234
|
+
tools. `make backend-purge CONFIRM=searxng` backs up named volumes under a private
|
|
235
|
+
/tmp directory (.bak files), then removes only that stack's volumes. Review its
|
|
236
|
+
Make recipe first. Never run global Docker prune. A clone is retained so reinstall
|
|
237
|
+
works from either GitHub or GitLab. `make purge-all CONFIRM=searxng` sequences
|
|
238
|
+
the confirmed backend backup/removal and app purge. Install from PyPI using
|
|
239
|
+
uv tool install kpihx-web.
|
|
240
|
+
|
|
241
|
+
All commands use an action/timestamp/status/data envelope. Formats: table, json,
|
|
242
|
+
jsonl, csv, md; --report creates escaped offline HTML or a real PDF. Autosaves are
|
|
243
|
+
unique 0600 JSON in /tmp/web-results; -S overrides and -N disables. Exit 2 is
|
|
244
|
+
failure, exit 3 is partial/access-wall coverage, exit 0 is completion. Inspect
|
|
245
|
+
non_exhaustive, budgets and source errors before drawing conclusions. Source
|
|
246
|
+
quality, identity attribution and correctness require human corroboration.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kpihx-web"
|
|
3
|
+
version = "2.2.0"
|
|
4
|
+
description = "Private CLI for metasearch, verified retrieval, bounded crawling and media investigation"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "MIT"}
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
dependencies = [
|
|
9
|
+
"beautifulsoup4",
|
|
10
|
+
"defusedxml>=0.7.1",
|
|
11
|
+
"fpdf2>=2.8.9",
|
|
12
|
+
"httpx[socks]",
|
|
13
|
+
"lxml",
|
|
14
|
+
"phonenumbers>=9.0.41",
|
|
15
|
+
"picimagesearch",
|
|
16
|
+
"pillow",
|
|
17
|
+
"pypdf",
|
|
18
|
+
"python-docx",
|
|
19
|
+
"regex>=2026.9.29",
|
|
20
|
+
"requests[socks]",
|
|
21
|
+
"rich",
|
|
22
|
+
"typer",
|
|
23
|
+
]
|
|
24
|
+
classifiers = [
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"License :: OSI Approved :: MIT License",
|
|
27
|
+
"Operating System :: OS Independent",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
dev = []
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
web = "k_web.cli:main"
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Repository = "https://github.com/kpihx-labs/web"
|
|
38
|
+
GitLab = "https://gitlab.com/kpihx-labs/web"
|
|
39
|
+
Issues = "https://github.com/kpihx-labs/web/issues"
|
|
40
|
+
|
|
41
|
+
[build-system]
|
|
42
|
+
requires = ["uv_build>=0.10.3,<0.11.0"]
|
|
43
|
+
build-backend = "uv_build"
|
|
44
|
+
|
|
45
|
+
[tool.uv.build-backend]
|
|
46
|
+
module-name = "k_web"
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint.flake8-bugbear]
|
|
49
|
+
extend-immutable-calls = ["typer.Argument", "typer.Option"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint]
|
|
55
|
+
select = ["E4", "E7", "E9", "F", "I", "B", "UP"]
|
|
56
|
+
|
|
57
|
+
[dependency-groups]
|
|
58
|
+
dev = [
|
|
59
|
+
"pytest>=9.1.1",
|
|
60
|
+
"reportlab>=5.1.0",
|
|
61
|
+
]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Free SongRec fingerprint adapter; humming is explicitly best-effort, not STT."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import math
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .http import WebError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def identify(
|
|
14
|
+
path, record=None, mode="recording", duration=12.0, source="default", offset=0.0
|
|
15
|
+
):
|
|
16
|
+
if mode not in {"recording", "hum"}:
|
|
17
|
+
raise WebError("Mode must be recording or hum")
|
|
18
|
+
if not math.isfinite(offset) or offset < 0 or (record is not None and offset):
|
|
19
|
+
raise WebError("Offset must be finite, nonnegative and used only with a file")
|
|
20
|
+
if not math.isfinite(duration) or (
|
|
21
|
+
record is not None and not math.isfinite(record)
|
|
22
|
+
):
|
|
23
|
+
raise WebError("Audio durations must be finite")
|
|
24
|
+
if (
|
|
25
|
+
(path is None) == (record is None)
|
|
26
|
+
or duration <= 0
|
|
27
|
+
or (record is not None and record <= 0)
|
|
28
|
+
):
|
|
29
|
+
raise WebError("Provide one file or --record SECONDS, with positive duration")
|
|
30
|
+
for command in ("ffmpeg", "songrec"):
|
|
31
|
+
if not shutil.which(command):
|
|
32
|
+
raise WebError(
|
|
33
|
+
f"Missing {command}; run make deps for installation guidance"
|
|
34
|
+
)
|
|
35
|
+
with tempfile.TemporaryDirectory(prefix="web-audio-") as folder:
|
|
36
|
+
sample = Path(folder) / "sample.wav"
|
|
37
|
+
args = ["ffmpeg", "-nostdin", "-v", "error"]
|
|
38
|
+
args += (
|
|
39
|
+
["-f", "pulse", "-i", source, "-t", str(record)]
|
|
40
|
+
if record
|
|
41
|
+
else ["-ss", str(offset), "-i", str(path), "-t", str(duration)]
|
|
42
|
+
)
|
|
43
|
+
subprocess.run(
|
|
44
|
+
[*args, "-ac", "1", "-ar", "16000", str(sample)],
|
|
45
|
+
check=True,
|
|
46
|
+
capture_output=True,
|
|
47
|
+
timeout=60 + (record or 0),
|
|
48
|
+
)
|
|
49
|
+
process = subprocess.run(
|
|
50
|
+
["songrec", "audio-file-to-recognized-song", str(sample)],
|
|
51
|
+
capture_output=True,
|
|
52
|
+
text=True,
|
|
53
|
+
timeout=30,
|
|
54
|
+
check=True,
|
|
55
|
+
)
|
|
56
|
+
result = json.loads(process.stdout)
|
|
57
|
+
return {
|
|
58
|
+
"requested_offset": offset,
|
|
59
|
+
"provider": "songrec",
|
|
60
|
+
"mode": mode,
|
|
61
|
+
"matched": bool(result.get("track")),
|
|
62
|
+
"result": result,
|
|
63
|
+
"partial": mode == "hum",
|
|
64
|
+
"capability": "Original-recording fingerprint, not query-by-humming; melody-only matches are not reliable",
|
|
65
|
+
}
|