findweb 0.1.0 → 0.1.2
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.
- package/README.md +148 -0
- package/dist/index.js +104 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# findweb
|
|
2
|
+
|
|
3
|
+
Google search CLI powered by system Chrome, with programmatic ad blocking.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install -g findweb
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bunx findweb "yc"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Single search
|
|
21
|
+
findweb "Y Combinator"
|
|
22
|
+
|
|
23
|
+
# Batch search
|
|
24
|
+
findweb "yc" "apple" "tesla" --parallel 3
|
|
25
|
+
|
|
26
|
+
# JSON output
|
|
27
|
+
findweb --json "react useEffect"
|
|
28
|
+
|
|
29
|
+
# Custom region and language
|
|
30
|
+
findweb --gl kr --lang ko "startup"
|
|
31
|
+
|
|
32
|
+
# More results
|
|
33
|
+
findweb -n 10 "rust async"
|
|
34
|
+
|
|
35
|
+
# Prepare a signed-in Chrome profile (reduces rate limiting)
|
|
36
|
+
findweb login
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## First Run Behavior
|
|
40
|
+
|
|
41
|
+
`findweb` requires an initialized Google profile before it will run the first search for a given `--userDataDir`.
|
|
42
|
+
|
|
43
|
+
- If the profile is already prepared, search runs immediately.
|
|
44
|
+
- If the profile has not been prepared yet, `findweb` automatically opens the login flow first.
|
|
45
|
+
- After you sign in and close the browser window, `findweb` writes a local prepared-profile marker so future searches can start immediately.
|
|
46
|
+
- By default, the profile directory is `${XDG_DATA_HOME:-~/.local/share}/findweb/chrome-profile` unless you pass `--userDataDir` or set `GOOGLE_SEARCH_USER_DATA_DIR`.
|
|
47
|
+
|
|
48
|
+
In practice, the first search on a fresh profile behaves like this:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
findweb "yc"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
1. detect missing prepared-profile marker
|
|
55
|
+
2. open headed Chrome login flow
|
|
56
|
+
3. wait for you to sign in and close the browser
|
|
57
|
+
4. continue the original search
|
|
58
|
+
|
|
59
|
+
## Options
|
|
60
|
+
|
|
61
|
+
| Option | Default | Description |
|
|
62
|
+
| ------------------ | -------------- | ------------------------------------ |
|
|
63
|
+
| `--gl <country>` | `us` | Google region hint |
|
|
64
|
+
| `-l, --lang` | `en` | Google UI language |
|
|
65
|
+
| `-n, --num` | `3` | Results per query |
|
|
66
|
+
| `--parallel` | `4` | Batch tab concurrency |
|
|
67
|
+
| `--userDataDir` | auto-detected | Chrome profile directory |
|
|
68
|
+
| `--headed` | `false` | Show the Chrome window |
|
|
69
|
+
| `--json` | `false` | Print output as JSON |
|
|
70
|
+
|
|
71
|
+
## How It Works
|
|
72
|
+
|
|
73
|
+
1. Launches system Chrome (`/Applications/Google Chrome.app`) with a free debugging port
|
|
74
|
+
2. Connects via CDP using puppeteer-core
|
|
75
|
+
3. Loads the [Ghostery adblocker](https://github.com/ghostery/adblocker) engine programmatically on each page
|
|
76
|
+
4. Navigates to Google, submits the query through DOM manipulation, and extracts results from the rendered page
|
|
77
|
+
5. Returns results as plain text or JSON, then closes Chrome
|
|
78
|
+
|
|
79
|
+
No Chromium download. No browser extension. No user confirmation.
|
|
80
|
+
|
|
81
|
+
## Batch Mode
|
|
82
|
+
|
|
83
|
+
Pass multiple quoted queries as positional arguments. Each query opens a separate tab in the same browser instance and profile.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
findweb "yc" "apple" "tesla"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Results are returned in input order. Concurrency is controlled by `--parallel` (default: 4).
|
|
90
|
+
|
|
91
|
+
## Login
|
|
92
|
+
|
|
93
|
+
Google rate-limits unauthenticated or fresh-profile searches. `findweb` now enforces an interactive login before the first search on a new profile.
|
|
94
|
+
|
|
95
|
+
You can trigger that ahead of time with:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
findweb login
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
This opens a visible Chrome window with the Google sign-in page. After signing in, close the browser. The session is saved to the profile directory, and `findweb` records that the profile is ready for future searches.
|
|
102
|
+
|
|
103
|
+
## Output
|
|
104
|
+
|
|
105
|
+
### Plain text (default)
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
1. Y Combinator
|
|
109
|
+
https://www.ycombinator.com/
|
|
110
|
+
Y Combinator created a new model for funding early stage startups.
|
|
111
|
+
|
|
112
|
+
2. Y Combinator - Wikipedia
|
|
113
|
+
https://en.wikipedia.org/wiki/Y_Combinator
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### JSON (`--json`)
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
[
|
|
120
|
+
{
|
|
121
|
+
"title": "Y Combinator",
|
|
122
|
+
"url": "https://www.ycombinator.com/",
|
|
123
|
+
"snippet": "Y Combinator created a new model for funding early stage startups."
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Requirements
|
|
129
|
+
|
|
130
|
+
- macOS
|
|
131
|
+
- System Chrome (`/Applications/Google Chrome.app`)
|
|
132
|
+
- [Bun](https://bun.sh) >= 1.3.11
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
git clone https://github.com/ysm-dev/findweb.git
|
|
138
|
+
cd findweb
|
|
139
|
+
bun install
|
|
140
|
+
bun run check # tsgo typecheck
|
|
141
|
+
bun run test # unit tests
|
|
142
|
+
bun run dev # run from source
|
|
143
|
+
bun run build # bundle to dist/
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -53157,7 +53157,7 @@ var require_ffi_WASM_RELEASE_SYNC = __commonJS((exports) => {
|
|
|
53157
53157
|
|
|
53158
53158
|
// node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js
|
|
53159
53159
|
var require_emscripten_module_WASM_RELEASE_SYNC = __commonJS((exports, module) => {
|
|
53160
|
-
var __dirname = "/
|
|
53160
|
+
var __dirname = "/home/runner/work/findweb/findweb/node_modules/@tootallnate/quickjs-emscripten/dist/generated", __filename = "/home/runner/work/findweb/findweb/node_modules/@tootallnate/quickjs-emscripten/dist/generated/emscripten-module.WASM_RELEASE_SYNC.js";
|
|
53161
53161
|
var QuickJSRaw = (() => {
|
|
53162
53162
|
var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : undefined;
|
|
53163
53163
|
if (typeof __filename !== "undefined")
|
|
@@ -66931,13 +66931,11 @@ async function runMain(cmd, opts = {}) {
|
|
|
66931
66931
|
}
|
|
66932
66932
|
}
|
|
66933
66933
|
|
|
66934
|
-
// src/cli/commands/login.ts
|
|
66935
|
-
import fs7 from "fs/promises";
|
|
66936
|
-
|
|
66937
66934
|
// src/search/browser.ts
|
|
66938
|
-
import { existsSync as existsSync3 } from "fs";
|
|
66939
66935
|
import { spawn as spawn3 } from "child_process";
|
|
66940
66936
|
import http2 from "http";
|
|
66937
|
+
import os9 from "os";
|
|
66938
|
+
import path12 from "path";
|
|
66941
66939
|
|
|
66942
66940
|
// node_modules/puppeteer-core/lib/esm/puppeteer/api/api.js
|
|
66943
66941
|
init_Browser();
|
|
@@ -76310,13 +76308,19 @@ async function closeSearchBrowser(activeBrowser) {
|
|
|
76310
76308
|
activeBrowser.chromeProcess.kill("SIGTERM");
|
|
76311
76309
|
}
|
|
76312
76310
|
}
|
|
76311
|
+
function defaultXdgDataHome() {
|
|
76312
|
+
const configured = process.env.XDG_DATA_HOME;
|
|
76313
|
+
if (configured && path12.isAbsolute(configured)) {
|
|
76314
|
+
return configured;
|
|
76315
|
+
}
|
|
76316
|
+
return path12.join(os9.homedir(), ".local", "share");
|
|
76317
|
+
}
|
|
76313
76318
|
function defaultUserDataDir() {
|
|
76314
76319
|
const configured = process.env.GOOGLE_SEARCH_USER_DATA_DIR;
|
|
76315
76320
|
if (configured) {
|
|
76316
76321
|
return configured;
|
|
76317
76322
|
}
|
|
76318
|
-
|
|
76319
|
-
return ["/tmp/google-search-profile", legacyProfile].find((candidate) => existsSync3(candidate)) ?? "/tmp/google-search-profile";
|
|
76323
|
+
return path12.join(defaultXdgDataHome(), "findweb", "chrome-profile");
|
|
76320
76324
|
}
|
|
76321
76325
|
|
|
76322
76326
|
// src/search/page.ts
|
|
@@ -76557,8 +76561,68 @@ async function runLoginSession(options) {
|
|
|
76557
76561
|
});
|
|
76558
76562
|
}
|
|
76559
76563
|
|
|
76564
|
+
// src/cli/profile.ts
|
|
76565
|
+
import fs7 from "fs/promises";
|
|
76566
|
+
import path13 from "path";
|
|
76567
|
+
var PROFILE_READY_MARKER = ".findweb-profile-ready";
|
|
76568
|
+
async function ensureProfileDir(dirPath) {
|
|
76569
|
+
await fs7.mkdir(dirPath, { recursive: true });
|
|
76570
|
+
}
|
|
76571
|
+
function readyMarkerPath(userDataDir) {
|
|
76572
|
+
return path13.join(userDataDir, PROFILE_READY_MARKER);
|
|
76573
|
+
}
|
|
76574
|
+
async function hasPreparedProfile(userDataDir) {
|
|
76575
|
+
try {
|
|
76576
|
+
await fs7.access(readyMarkerPath(userDataDir));
|
|
76577
|
+
return true;
|
|
76578
|
+
} catch {
|
|
76579
|
+
return false;
|
|
76580
|
+
}
|
|
76581
|
+
}
|
|
76582
|
+
async function markProfilePrepared(userDataDir) {
|
|
76583
|
+
await ensureProfileDir(userDataDir);
|
|
76584
|
+
await fs7.writeFile(readyMarkerPath(userDataDir), `${new Date().toISOString()}
|
|
76585
|
+
`, "utf8");
|
|
76586
|
+
}
|
|
76587
|
+
|
|
76588
|
+
// src/cli/flows/login.ts
|
|
76589
|
+
function printLoginInstructions(userDataDir) {
|
|
76590
|
+
console.log(`Login browser launched with profile: ${userDataDir}`);
|
|
76591
|
+
console.log("Sign in to Google to prepare this profile for future searches.");
|
|
76592
|
+
console.log("Close the browser window when you are done.");
|
|
76593
|
+
}
|
|
76594
|
+
async function runInteractiveLoginFlow(options) {
|
|
76595
|
+
await ensureProfileDir(options.userDataDir);
|
|
76596
|
+
const activeBrowser = await launchSearchBrowser({
|
|
76597
|
+
headed: true,
|
|
76598
|
+
lang: options.lang,
|
|
76599
|
+
userDataDir: options.userDataDir
|
|
76600
|
+
});
|
|
76601
|
+
printLoginInstructions(options.userDataDir);
|
|
76602
|
+
try {
|
|
76603
|
+
await runLoginSession({
|
|
76604
|
+
browser: activeBrowser.browser,
|
|
76605
|
+
gl: options.gl,
|
|
76606
|
+
lang: options.lang
|
|
76607
|
+
});
|
|
76608
|
+
} finally {
|
|
76609
|
+
await closeSearchBrowser(activeBrowser);
|
|
76610
|
+
}
|
|
76611
|
+
await markProfilePrepared(options.userDataDir);
|
|
76612
|
+
}
|
|
76613
|
+
async function ensureInteractiveLogin(options) {
|
|
76614
|
+
await ensureProfileDir(options.userDataDir);
|
|
76615
|
+
if (await hasPreparedProfile(options.userDataDir)) {
|
|
76616
|
+
return false;
|
|
76617
|
+
}
|
|
76618
|
+
console.log("No prepared Google profile was found for this user-data-dir.");
|
|
76619
|
+
console.log("A login step is required before the first search.");
|
|
76620
|
+
await runInteractiveLoginFlow(options);
|
|
76621
|
+
return true;
|
|
76622
|
+
}
|
|
76623
|
+
|
|
76560
76624
|
// src/cli/schema.ts
|
|
76561
|
-
import
|
|
76625
|
+
import path14 from "path";
|
|
76562
76626
|
|
|
76563
76627
|
// node_modules/zod/v4/classic/external.js
|
|
76564
76628
|
var exports_external = {};
|
|
@@ -77325,10 +77389,10 @@ function mergeDefs(...defs) {
|
|
|
77325
77389
|
function cloneDef(schema) {
|
|
77326
77390
|
return mergeDefs(schema._zod.def);
|
|
77327
77391
|
}
|
|
77328
|
-
function getElementAtPath(obj,
|
|
77329
|
-
if (!
|
|
77392
|
+
function getElementAtPath(obj, path14) {
|
|
77393
|
+
if (!path14)
|
|
77330
77394
|
return obj;
|
|
77331
|
-
return
|
|
77395
|
+
return path14.reduce((acc, key) => acc?.[key], obj);
|
|
77332
77396
|
}
|
|
77333
77397
|
function promiseAllObject(promisesObj) {
|
|
77334
77398
|
const keys = Object.keys(promisesObj);
|
|
@@ -77709,11 +77773,11 @@ function aborted(x, startIndex = 0) {
|
|
|
77709
77773
|
}
|
|
77710
77774
|
return false;
|
|
77711
77775
|
}
|
|
77712
|
-
function prefixIssues(
|
|
77776
|
+
function prefixIssues(path14, issues) {
|
|
77713
77777
|
return issues.map((iss) => {
|
|
77714
77778
|
var _a4;
|
|
77715
77779
|
(_a4 = iss).path ?? (_a4.path = []);
|
|
77716
|
-
iss.path.unshift(
|
|
77780
|
+
iss.path.unshift(path14);
|
|
77717
77781
|
return iss;
|
|
77718
77782
|
});
|
|
77719
77783
|
}
|
|
@@ -77896,7 +77960,7 @@ function formatError(error, mapper = (issue2) => issue2.message) {
|
|
|
77896
77960
|
}
|
|
77897
77961
|
function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
77898
77962
|
const result = { errors: [] };
|
|
77899
|
-
const processError = (error2,
|
|
77963
|
+
const processError = (error2, path14 = []) => {
|
|
77900
77964
|
var _a4, _b2;
|
|
77901
77965
|
for (const issue2 of error2.issues) {
|
|
77902
77966
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -77906,7 +77970,7 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
77906
77970
|
} else if (issue2.code === "invalid_element") {
|
|
77907
77971
|
processError({ issues: issue2.issues }, issue2.path);
|
|
77908
77972
|
} else {
|
|
77909
|
-
const fullpath = [...
|
|
77973
|
+
const fullpath = [...path14, ...issue2.path];
|
|
77910
77974
|
if (fullpath.length === 0) {
|
|
77911
77975
|
result.errors.push(mapper(issue2));
|
|
77912
77976
|
continue;
|
|
@@ -77938,8 +78002,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
77938
78002
|
}
|
|
77939
78003
|
function toDotPath(_path) {
|
|
77940
78004
|
const segs = [];
|
|
77941
|
-
const
|
|
77942
|
-
for (const seg of
|
|
78005
|
+
const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
78006
|
+
for (const seg of path14) {
|
|
77943
78007
|
if (typeof seg === "number")
|
|
77944
78008
|
segs.push(`[${seg}]`);
|
|
77945
78009
|
else if (typeof seg === "symbol")
|
|
@@ -89686,13 +89750,13 @@ function resolveRef(ref, ctx) {
|
|
|
89686
89750
|
if (!ref.startsWith("#")) {
|
|
89687
89751
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
89688
89752
|
}
|
|
89689
|
-
const
|
|
89690
|
-
if (
|
|
89753
|
+
const path14 = ref.slice(1).split("/").filter(Boolean);
|
|
89754
|
+
if (path14.length === 0) {
|
|
89691
89755
|
return ctx.rootSchema;
|
|
89692
89756
|
}
|
|
89693
89757
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
89694
|
-
if (
|
|
89695
|
-
const key =
|
|
89758
|
+
if (path14[0] === defsKey) {
|
|
89759
|
+
const key = path14[1];
|
|
89696
89760
|
if (!key || !ctx.defs[key]) {
|
|
89697
89761
|
throw new Error(`Reference not found: ${ref}`);
|
|
89698
89762
|
}
|
|
@@ -90101,7 +90165,7 @@ var sharedSchema = exports_external.object({
|
|
|
90101
90165
|
headed: exports_external.boolean().default(false),
|
|
90102
90166
|
json: exports_external.boolean().default(false),
|
|
90103
90167
|
lang: defaultedString("lang", "en"),
|
|
90104
|
-
userDataDir: defaultedString("userDataDir", defaultUserDataDir()).transform((value) =>
|
|
90168
|
+
userDataDir: defaultedString("userDataDir", defaultUserDataDir()).transform((value) => path14.resolve(value))
|
|
90105
90169
|
});
|
|
90106
90170
|
var searchSchema = sharedSchema.extend({
|
|
90107
90171
|
num: positiveInteger("num").default(3),
|
|
@@ -90145,25 +90209,6 @@ function normalizeLoginOptions(input2) {
|
|
|
90145
90209
|
}
|
|
90146
90210
|
|
|
90147
90211
|
// src/cli/commands/login.ts
|
|
90148
|
-
async function ensureProfileDir(dirPath) {
|
|
90149
|
-
await fs7.mkdir(dirPath, { recursive: true });
|
|
90150
|
-
}
|
|
90151
|
-
async function runLoginFlow(gl, lang, userDataDir) {
|
|
90152
|
-
await ensureProfileDir(userDataDir);
|
|
90153
|
-
const activeBrowser = await launchSearchBrowser({
|
|
90154
|
-
headed: true,
|
|
90155
|
-
lang,
|
|
90156
|
-
userDataDir
|
|
90157
|
-
});
|
|
90158
|
-
console.log(`Login browser launched with profile: ${userDataDir}`);
|
|
90159
|
-
console.log("Sign in to Google if you want to reuse a logged-in search profile.");
|
|
90160
|
-
console.log("Close the browser window when you are done.");
|
|
90161
|
-
try {
|
|
90162
|
-
await runLoginSession({ browser: activeBrowser.browser, gl, lang });
|
|
90163
|
-
} finally {
|
|
90164
|
-
await closeSearchBrowser(activeBrowser);
|
|
90165
|
-
}
|
|
90166
|
-
}
|
|
90167
90212
|
function createLoginArgs() {
|
|
90168
90213
|
return {
|
|
90169
90214
|
gl: {
|
|
@@ -90190,7 +90235,7 @@ async function runLogin(args) {
|
|
|
90190
90235
|
lang: typeof args.lang === "string" ? args.lang : undefined,
|
|
90191
90236
|
userDataDir: typeof args.userDataDir === "string" ? args.userDataDir : undefined
|
|
90192
90237
|
});
|
|
90193
|
-
await
|
|
90238
|
+
await runInteractiveLoginFlow(options);
|
|
90194
90239
|
}
|
|
90195
90240
|
function createLoginCommand(commandName = "findweb login") {
|
|
90196
90241
|
return defineCommand({
|
|
@@ -90207,13 +90252,12 @@ function createLoginCommand(commandName = "findweb login") {
|
|
|
90207
90252
|
}
|
|
90208
90253
|
|
|
90209
90254
|
// src/cli/commands/search.ts
|
|
90210
|
-
import fs9 from "fs/promises";
|
|
90211
90255
|
import process4 from "process";
|
|
90212
90256
|
|
|
90213
90257
|
// src/search/blocker.ts
|
|
90214
90258
|
import fs8 from "fs/promises";
|
|
90215
|
-
import
|
|
90216
|
-
import
|
|
90259
|
+
import os10 from "os";
|
|
90260
|
+
import path15 from "path";
|
|
90217
90261
|
|
|
90218
90262
|
// node_modules/tldts-core/dist/es6/src/domain.js
|
|
90219
90263
|
function shareSameDomainSuffix(hostname3, vhost) {
|
|
@@ -99477,8 +99521,8 @@ class FilterEngine extends EventEmitter5 {
|
|
|
99477
99521
|
if (caching === undefined) {
|
|
99478
99522
|
return init();
|
|
99479
99523
|
}
|
|
99480
|
-
const { path:
|
|
99481
|
-
return read(
|
|
99524
|
+
const { path: path15, read, write } = caching;
|
|
99525
|
+
return read(path15).then((buffer) => this.deserialize(buffer)).catch(() => init().then((engine) => write(path15, engine.serialize()).then(() => engine)));
|
|
99482
99526
|
}
|
|
99483
99527
|
static empty(config3 = {}) {
|
|
99484
99528
|
return new this({ config: config3 });
|
|
@@ -101270,13 +101314,13 @@ class PuppeteerBlocker extends FilterEngine {
|
|
|
101270
101314
|
// src/search/blocker.ts
|
|
101271
101315
|
var blockerPromise;
|
|
101272
101316
|
function defaultCacheDir() {
|
|
101273
|
-
return process.env.GOOGLE_SEARCH_CACHE_DIR ??
|
|
101317
|
+
return process.env.GOOGLE_SEARCH_CACHE_DIR ?? path15.join(os10.homedir(), ".cache", "google-search");
|
|
101274
101318
|
}
|
|
101275
101319
|
async function readCache(filePath) {
|
|
101276
101320
|
return fs8.readFile(filePath);
|
|
101277
101321
|
}
|
|
101278
101322
|
async function writeCache(filePath, buffer) {
|
|
101279
|
-
await fs8.mkdir(
|
|
101323
|
+
await fs8.mkdir(path15.dirname(filePath), { recursive: true });
|
|
101280
101324
|
await fs8.writeFile(filePath, buffer);
|
|
101281
101325
|
}
|
|
101282
101326
|
async function loadBlocker() {
|
|
@@ -101285,7 +101329,7 @@ async function loadBlocker() {
|
|
|
101285
101329
|
const cacheDir = defaultCacheDir();
|
|
101286
101330
|
await fs8.mkdir(cacheDir, { recursive: true });
|
|
101287
101331
|
return PuppeteerBlocker.fromPrebuiltAdsAndTracking(globalThis.fetch.bind(globalThis), {
|
|
101288
|
-
path:
|
|
101332
|
+
path: path15.join(cacheDir, "ghostery-engine.bin"),
|
|
101289
101333
|
read: readCache,
|
|
101290
101334
|
write: writeCache
|
|
101291
101335
|
});
|
|
@@ -101339,9 +101383,6 @@ function exitCodeForOutcomes(items) {
|
|
|
101339
101383
|
}
|
|
101340
101384
|
|
|
101341
101385
|
// src/cli/commands/search.ts
|
|
101342
|
-
async function ensureProfileDir2(dirPath) {
|
|
101343
|
-
await fs9.mkdir(dirPath, { recursive: true });
|
|
101344
|
-
}
|
|
101345
101386
|
function printResults(json2, outcomes) {
|
|
101346
101387
|
if (json2) {
|
|
101347
101388
|
printJsonResults(outcomes);
|
|
@@ -101402,7 +101443,16 @@ async function runSearch(args) {
|
|
|
101402
101443
|
parallel: typeof args.parallel === "string" || typeof args.parallel === "number" ? args.parallel : undefined,
|
|
101403
101444
|
userDataDir: typeof args.userDataDir === "string" ? args.userDataDir : undefined
|
|
101404
101445
|
});
|
|
101405
|
-
await
|
|
101446
|
+
await ensureProfileDir(options.userDataDir);
|
|
101447
|
+
const loginWasRequired = await ensureInteractiveLogin({
|
|
101448
|
+
gl: options.gl,
|
|
101449
|
+
lang: options.lang,
|
|
101450
|
+
userDataDir: options.userDataDir
|
|
101451
|
+
});
|
|
101452
|
+
if (loginWasRequired) {
|
|
101453
|
+
console.log(`Login completed. Continuing with search...
|
|
101454
|
+
`);
|
|
101455
|
+
}
|
|
101406
101456
|
const blocker = await loadBlocker();
|
|
101407
101457
|
const activeBrowser = await launchSearchBrowser({
|
|
101408
101458
|
headed: options.headed,
|