mcp-scraper 0.19.0 → 0.20.0
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/dist/bin/api-server.cjs +189 -37
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +100 -14
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +4 -4
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +3 -3
- package/dist/{chunk-GL4BW4CP.js → chunk-22VEGGTW.js} +21 -9
- package/dist/{chunk-GL4BW4CP.js.map → chunk-22VEGGTW.js.map} +1 -1
- package/dist/{chunk-RUGJE5EB.js → chunk-EJK25QOW.js} +2 -2
- package/dist/chunk-JWIE5NCR.js +284 -0
- package/dist/chunk-JWIE5NCR.js.map +1 -0
- package/dist/{chunk-O2S5TOCG.js → chunk-KE7KE2Q2.js} +102 -16
- package/dist/chunk-KE7KE2Q2.js.map +1 -0
- package/dist/chunk-PZB3TJWK.js +7 -0
- package/dist/chunk-PZB3TJWK.js.map +1 -0
- package/dist/{chunk-D7ZT27HY.js → chunk-UN7VMHZL.js} +2 -2
- package/dist/{chunk-2HDMYW4B.js → chunk-XDFSLSSH.js} +2 -2
- package/dist/{chunk-HE2LQPJ2.js → chunk-ZRKFW5FB.js} +2 -2
- package/dist/{db-LIOTIWVN.js → db-YHZYG7D2.js} +2 -2
- package/dist/{extract-bundle-U4D5LW5W.js → extract-bundle-OSUPAHCE.js} +58 -5
- package/dist/extract-bundle-OSUPAHCE.js.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{server-VWXDE64Y.js → server-VDWIPV7F.js} +37 -310
- package/dist/server-VDWIPV7F.js.map +1 -0
- package/dist/{site-extract-repository-NVSZH35Y.js → site-extract-repository-GWKGK46Z.js} +3 -3
- package/dist/{worker-AM2DHUWG.js → worker-O5PZTTPY.js} +5 -5
- package/docs/mcp-tool-manifest.generated.json +166 -23
- package/docs/specs/meta-ad-creative-media-resolution-spec.md +3 -3
- package/docs/specs/unified-credit-and-scheduled-execution-billing-spec.md +1007 -0
- package/package.json +1 -1
- package/dist/chunk-O2S5TOCG.js.map +0 -1
- package/dist/chunk-OQHYDW4Q.js +0 -7
- package/dist/chunk-OQHYDW4Q.js.map +0 -1
- package/dist/extract-bundle-U4D5LW5W.js.map +0 -1
- package/dist/server-VWXDE64Y.js.map +0 -1
- /package/dist/{chunk-RUGJE5EB.js.map → chunk-EJK25QOW.js.map} +0 -0
- /package/dist/{chunk-D7ZT27HY.js.map → chunk-UN7VMHZL.js.map} +0 -0
- /package/dist/{chunk-2HDMYW4B.js.map → chunk-XDFSLSSH.js.map} +0 -0
- /package/dist/{chunk-HE2LQPJ2.js.map → chunk-ZRKFW5FB.js.map} +0 -0
- /package/dist/{db-LIOTIWVN.js.map → db-YHZYG7D2.js.map} +0 -0
- /package/dist/{site-extract-repository-NVSZH35Y.js.map → site-extract-repository-GWKGK46Z.js.map} +0 -0
- /package/dist/{worker-AM2DHUWG.js.map → worker-O5PZTTPY.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
harvest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XDFSLSSH.js";
|
|
4
4
|
import {
|
|
5
5
|
recordVendorUsage
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UN7VMHZL.js";
|
|
7
7
|
import "./chunk-K443GQY5.js";
|
|
8
8
|
import "./chunk-XGIPATLV.js";
|
|
9
9
|
import "./chunk-M2S27J6Z.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-22VEGGTW.js";
|
|
11
11
|
|
|
12
12
|
// src/video/VideoGenerator.ts
|
|
13
13
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
harvestPageMedia
|
|
3
|
+
} from "./chunk-JWIE5NCR.js";
|
|
1
4
|
import {
|
|
2
5
|
classifyHarvestProblem,
|
|
3
6
|
createHarvestAttemptRecorder,
|
|
4
7
|
harvestProblemResponse,
|
|
5
8
|
serializeHarvestProblem
|
|
6
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZRKFW5FB.js";
|
|
7
10
|
import {
|
|
8
11
|
BrowserDriver,
|
|
9
12
|
MapsSelectors,
|
|
@@ -11,7 +14,7 @@ import {
|
|
|
11
14
|
deleteKernelProxyId,
|
|
12
15
|
harvest,
|
|
13
16
|
resolveKernelProxyId
|
|
14
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-XDFSLSSH.js";
|
|
15
18
|
import {
|
|
16
19
|
HttpMcpToolExecutor,
|
|
17
20
|
MemoryMcpToolExecutor,
|
|
@@ -32,7 +35,7 @@ import {
|
|
|
32
35
|
sanitizeAttempts,
|
|
33
36
|
sanitizeHarvestResult,
|
|
34
37
|
transcribeMediaUrl
|
|
35
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-KE7KE2Q2.js";
|
|
36
39
|
import {
|
|
37
40
|
auditImages,
|
|
38
41
|
buildLinkReport,
|
|
@@ -50,7 +53,7 @@ import {
|
|
|
50
53
|
recordKernelSession,
|
|
51
54
|
recordVendorUsage,
|
|
52
55
|
runWithCostContext
|
|
53
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-UN7VMHZL.js";
|
|
54
57
|
import {
|
|
55
58
|
csvRecords,
|
|
56
59
|
listWorkflowDefinitions,
|
|
@@ -74,7 +77,7 @@ import {
|
|
|
74
77
|
RawMapsOverviewSchema,
|
|
75
78
|
RawMapsReviewStatsSchema
|
|
76
79
|
} from "./chunk-XGIPATLV.js";
|
|
77
|
-
import "./chunk-
|
|
80
|
+
import "./chunk-PZB3TJWK.js";
|
|
78
81
|
import {
|
|
79
82
|
completeExtractJob,
|
|
80
83
|
countSuccessfulPages,
|
|
@@ -85,7 +88,7 @@ import {
|
|
|
85
88
|
saveExtractPages,
|
|
86
89
|
setExtractJobTotal,
|
|
87
90
|
settleExtractJob
|
|
88
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-EJK25QOW.js";
|
|
89
92
|
import {
|
|
90
93
|
BROWSER_OPEN_MIN_BALANCE_MC,
|
|
91
94
|
CONCURRENCY_PRICE_ID,
|
|
@@ -191,7 +194,7 @@ import {
|
|
|
191
194
|
setUserMemoryCreds,
|
|
192
195
|
upsertPageSnapshot,
|
|
193
196
|
verifyPassword
|
|
194
|
-
} from "./chunk-
|
|
197
|
+
} from "./chunk-22VEGGTW.js";
|
|
195
198
|
|
|
196
199
|
// src/blog/registry.ts
|
|
197
200
|
var posts = [
|
|
@@ -4226,285 +4229,6 @@ async function capturePageData(url, opts = {}) {
|
|
|
4226
4229
|
}
|
|
4227
4230
|
}
|
|
4228
4231
|
|
|
4229
|
-
// src/lib/media-extractor.ts
|
|
4230
|
-
import { createWriteStream, mkdirSync } from "fs";
|
|
4231
|
-
import { homedir } from "os";
|
|
4232
|
-
import { join as join2, extname, basename } from "path";
|
|
4233
|
-
import { pipeline } from "stream/promises";
|
|
4234
|
-
import { Readable } from "stream";
|
|
4235
|
-
var AD_PATTERNS = [
|
|
4236
|
-
"doubleclick.net",
|
|
4237
|
-
"googlesyndication.com",
|
|
4238
|
-
"googletagmanager.com",
|
|
4239
|
-
"google-analytics.com",
|
|
4240
|
-
"googletagservices.com",
|
|
4241
|
-
"adservice.google",
|
|
4242
|
-
"googletag.",
|
|
4243
|
-
"pagead2.googlesyndication",
|
|
4244
|
-
"facebook.net/tr",
|
|
4245
|
-
"connect.facebook.net",
|
|
4246
|
-
"fbcdn.net/rsrc",
|
|
4247
|
-
"analytics.twitter.com",
|
|
4248
|
-
"static.ads-twitter.com",
|
|
4249
|
-
"ads.twitter.com",
|
|
4250
|
-
"t.co/i/adsct",
|
|
4251
|
-
"pixel.advertising.com",
|
|
4252
|
-
"hotjar.com",
|
|
4253
|
-
"clarity.ms",
|
|
4254
|
-
"quantserve.com",
|
|
4255
|
-
"scorecardresearch.com",
|
|
4256
|
-
"newrelic.com",
|
|
4257
|
-
"nr-data.net",
|
|
4258
|
-
"segment.io",
|
|
4259
|
-
"segment.com",
|
|
4260
|
-
"amplitude.com",
|
|
4261
|
-
"mixpanel.com",
|
|
4262
|
-
"heap.io",
|
|
4263
|
-
"fullstory.com",
|
|
4264
|
-
"moatads.com",
|
|
4265
|
-
"criteo.com",
|
|
4266
|
-
"adsrvr.org",
|
|
4267
|
-
"rubiconproject.com",
|
|
4268
|
-
"pubmatic.com",
|
|
4269
|
-
"openx.net",
|
|
4270
|
-
"appnexus.com",
|
|
4271
|
-
"amazon-adsystem.com",
|
|
4272
|
-
"media.net",
|
|
4273
|
-
"yieldmo.com",
|
|
4274
|
-
"triplelift.com",
|
|
4275
|
-
"sharethrough.com",
|
|
4276
|
-
"prebid.",
|
|
4277
|
-
"smaato.net",
|
|
4278
|
-
"indexworm.com",
|
|
4279
|
-
"casalemedia.com",
|
|
4280
|
-
"outbrain.com",
|
|
4281
|
-
"taboola.com",
|
|
4282
|
-
"revcontent.com",
|
|
4283
|
-
"mgid.com",
|
|
4284
|
-
"tawk.to",
|
|
4285
|
-
"intercom.io",
|
|
4286
|
-
"drift.com",
|
|
4287
|
-
"hs-scripts.com",
|
|
4288
|
-
"zopim.com",
|
|
4289
|
-
"livechatinc.com",
|
|
4290
|
-
"userlike.com",
|
|
4291
|
-
"onetrust.com",
|
|
4292
|
-
"cookielaw.org",
|
|
4293
|
-
"cookieinformation.com",
|
|
4294
|
-
"trustarc.com",
|
|
4295
|
-
"/ads/",
|
|
4296
|
-
"/ad/",
|
|
4297
|
-
"/banner/",
|
|
4298
|
-
"/banners/",
|
|
4299
|
-
"/pixel/",
|
|
4300
|
-
"/beacon/",
|
|
4301
|
-
"/tracking/",
|
|
4302
|
-
"/tracker/",
|
|
4303
|
-
"/remarketing/",
|
|
4304
|
-
"/conversion/",
|
|
4305
|
-
"1x1.gif",
|
|
4306
|
-
"spacer.gif",
|
|
4307
|
-
"blank.gif",
|
|
4308
|
-
"transparent.gif"
|
|
4309
|
-
];
|
|
4310
|
-
var IMAGE_EXTS = /* @__PURE__ */ new Set([".jpg", ".jpeg", ".png", ".webp", ".gif", ".avif", ".svg", ".tiff"]);
|
|
4311
|
-
var VIDEO_EXTS = /* @__PURE__ */ new Set([".mp4", ".webm", ".mov", ".avi", ".m4v", ".ogv", ".mkv"]);
|
|
4312
|
-
var AUDIO_EXTS = /* @__PURE__ */ new Set([".mp3", ".wav", ".ogg", ".aac", ".m4a", ".flac", ".opus"]);
|
|
4313
|
-
function isAdUrl(url) {
|
|
4314
|
-
const lower = url.toLowerCase();
|
|
4315
|
-
return AD_PATTERNS.some((p) => lower.includes(p));
|
|
4316
|
-
}
|
|
4317
|
-
function isDataUri(url) {
|
|
4318
|
-
return url.startsWith("data:");
|
|
4319
|
-
}
|
|
4320
|
-
function typeFromUrl(url) {
|
|
4321
|
-
try {
|
|
4322
|
-
const ext = extname(new URL(url).pathname).toLowerCase();
|
|
4323
|
-
if (IMAGE_EXTS.has(ext)) return "image";
|
|
4324
|
-
if (VIDEO_EXTS.has(ext)) return "video";
|
|
4325
|
-
if (AUDIO_EXTS.has(ext)) return "audio";
|
|
4326
|
-
} catch {
|
|
4327
|
-
}
|
|
4328
|
-
return null;
|
|
4329
|
-
}
|
|
4330
|
-
function typeFromMime(mime) {
|
|
4331
|
-
const lower = mime.toLowerCase();
|
|
4332
|
-
if (lower.startsWith("image/")) return "image";
|
|
4333
|
-
if (lower.startsWith("video/")) return "video";
|
|
4334
|
-
if (lower.startsWith("audio/")) return "audio";
|
|
4335
|
-
return null;
|
|
4336
|
-
}
|
|
4337
|
-
function resolveUrl(raw, base) {
|
|
4338
|
-
if (!raw || isDataUri(raw)) return null;
|
|
4339
|
-
try {
|
|
4340
|
-
return new URL(raw, base).href;
|
|
4341
|
-
} catch {
|
|
4342
|
-
return null;
|
|
4343
|
-
}
|
|
4344
|
-
}
|
|
4345
|
-
function safeFilename(url, index) {
|
|
4346
|
-
try {
|
|
4347
|
-
const u = new URL(url);
|
|
4348
|
-
const base = basename(u.pathname).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
4349
|
-
return base || `asset-${index}`;
|
|
4350
|
-
} catch {
|
|
4351
|
-
return `asset-${index}`;
|
|
4352
|
-
}
|
|
4353
|
-
}
|
|
4354
|
-
function extractMediaUrls(html, baseUrl) {
|
|
4355
|
-
const seen = /* @__PURE__ */ new Set();
|
|
4356
|
-
const urls = [];
|
|
4357
|
-
const add = (raw) => {
|
|
4358
|
-
const resolved = resolveUrl(raw.trim(), baseUrl);
|
|
4359
|
-
if (!resolved || seen.has(resolved) || isAdUrl(resolved)) return;
|
|
4360
|
-
seen.add(resolved);
|
|
4361
|
-
urls.push(resolved);
|
|
4362
|
-
};
|
|
4363
|
-
for (const m of html.matchAll(/<img\s[^>]*>/gi)) {
|
|
4364
|
-
const tag = m[0];
|
|
4365
|
-
for (const attr of ["src", "data-src", "data-lazy-src", "data-original"]) {
|
|
4366
|
-
const v = (tag.match(new RegExp(`\\b${attr}\\s*=\\s*["']([^"']+)["']`, "i")) ?? [])[1];
|
|
4367
|
-
if (v) add(v);
|
|
4368
|
-
}
|
|
4369
|
-
const srcset = (tag.match(/\bsrcset\s*=\s*["']([^"']+)["']/i) ?? [])[1];
|
|
4370
|
-
if (srcset) {
|
|
4371
|
-
for (const part of srcset.split(",")) {
|
|
4372
|
-
const u = part.trim().split(/\s+/)[0];
|
|
4373
|
-
if (u) add(u);
|
|
4374
|
-
}
|
|
4375
|
-
}
|
|
4376
|
-
}
|
|
4377
|
-
for (const m of html.matchAll(/<source\s[^>]*>/gi)) {
|
|
4378
|
-
const tag = m[0];
|
|
4379
|
-
const src = (tag.match(/\bsrc\s*=\s*["']([^"']+)["']/i) ?? [])[1];
|
|
4380
|
-
if (src) add(src);
|
|
4381
|
-
const srcset = (tag.match(/\bsrcset\s*=\s*["']([^"']+)["']/i) ?? [])[1];
|
|
4382
|
-
if (srcset) {
|
|
4383
|
-
for (const part of srcset.split(",")) {
|
|
4384
|
-
const u = part.trim().split(/\s+/)[0];
|
|
4385
|
-
if (u) add(u);
|
|
4386
|
-
}
|
|
4387
|
-
}
|
|
4388
|
-
}
|
|
4389
|
-
for (const m of html.matchAll(/<video\s[^>]*>/gi)) {
|
|
4390
|
-
const tag = m[0];
|
|
4391
|
-
for (const attr of ["src", "poster"]) {
|
|
4392
|
-
const v = (tag.match(new RegExp(`\\b${attr}\\s*=\\s*["']([^"']+)["']`, "i")) ?? [])[1];
|
|
4393
|
-
if (v) add(v);
|
|
4394
|
-
}
|
|
4395
|
-
}
|
|
4396
|
-
for (const m of html.matchAll(/<audio\s[^>]*>/gi)) {
|
|
4397
|
-
const tag = m[0];
|
|
4398
|
-
const v = (tag.match(/\bsrc\s*=\s*["']([^"']+)["']/i) ?? [])[1];
|
|
4399
|
-
if (v) add(v);
|
|
4400
|
-
}
|
|
4401
|
-
for (const m of html.matchAll(/<meta\s[^>]*>/gi)) {
|
|
4402
|
-
const tag = m[0];
|
|
4403
|
-
const prop = (tag.match(/\b(?:property|name)\s*=\s*["']([^"']+)["']/i) ?? [])[1]?.toLowerCase();
|
|
4404
|
-
if (prop === "og:image" || prop === "twitter:image") {
|
|
4405
|
-
const content = (tag.match(/\bcontent\s*=\s*["']([^"']+)["']/i) ?? [])[1];
|
|
4406
|
-
if (content) add(content);
|
|
4407
|
-
}
|
|
4408
|
-
}
|
|
4409
|
-
for (const m of html.matchAll(/background(?:-image)?\s*:\s*url\(\s*["']?([^"')]+)["']?\s*\)/gi)) {
|
|
4410
|
-
add(m[1]);
|
|
4411
|
-
}
|
|
4412
|
-
return urls;
|
|
4413
|
-
}
|
|
4414
|
-
async function downloadAsset(url, destDir, filename) {
|
|
4415
|
-
const res = await fetch(url, {
|
|
4416
|
-
headers: { "User-Agent": "Mozilla/5.0 (compatible; ThorbitBot/1.0)" },
|
|
4417
|
-
signal: AbortSignal.timeout(15e3)
|
|
4418
|
-
});
|
|
4419
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
4420
|
-
if (!res.body) throw new Error("Empty response body");
|
|
4421
|
-
const mimeType = res.headers.get("content-type")?.split(";")[0].trim() ?? null;
|
|
4422
|
-
let dest = join2(destDir, filename);
|
|
4423
|
-
if (mimeType && !extname(filename)) {
|
|
4424
|
-
const mimeExt = {
|
|
4425
|
-
"image/jpeg": ".jpg",
|
|
4426
|
-
"image/png": ".png",
|
|
4427
|
-
"image/webp": ".webp",
|
|
4428
|
-
"image/gif": ".gif",
|
|
4429
|
-
"image/svg+xml": ".svg",
|
|
4430
|
-
"image/avif": ".avif",
|
|
4431
|
-
"video/mp4": ".mp4",
|
|
4432
|
-
"video/webm": ".webm",
|
|
4433
|
-
"audio/mpeg": ".mp3",
|
|
4434
|
-
"audio/ogg": ".ogg",
|
|
4435
|
-
"audio/wav": ".wav"
|
|
4436
|
-
};
|
|
4437
|
-
const ext = mimeExt[mimeType];
|
|
4438
|
-
if (ext) dest = dest + ext;
|
|
4439
|
-
}
|
|
4440
|
-
const writer = createWriteStream(dest);
|
|
4441
|
-
await pipeline(Readable.fromWeb(res.body), writer);
|
|
4442
|
-
const { statSync } = await import("fs");
|
|
4443
|
-
const sizeBytes = statSync(dest).size;
|
|
4444
|
-
return { savedPath: dest, sizeBytes, mimeType };
|
|
4445
|
-
}
|
|
4446
|
-
async function harvestPageMedia(html, pageUrl, options = {}) {
|
|
4447
|
-
const types = options.types ?? ["image", "video", "audio"];
|
|
4448
|
-
const typesSet = new Set(types);
|
|
4449
|
-
const rawUrls = extractMediaUrls(html, pageUrl);
|
|
4450
|
-
const totalFound = rawUrls.length;
|
|
4451
|
-
const filteredUrls = [];
|
|
4452
|
-
const kept = [];
|
|
4453
|
-
for (const url of rawUrls) {
|
|
4454
|
-
const type = typeFromUrl(url);
|
|
4455
|
-
if (!type || !typesSet.has(type)) {
|
|
4456
|
-
filteredUrls.push(url);
|
|
4457
|
-
continue;
|
|
4458
|
-
}
|
|
4459
|
-
kept.push({ url, type });
|
|
4460
|
-
}
|
|
4461
|
-
if (options.outputDir === null) {
|
|
4462
|
-
return {
|
|
4463
|
-
pageUrl,
|
|
4464
|
-
outputDir: null,
|
|
4465
|
-
assets: kept.map(({ url, type }, i) => ({
|
|
4466
|
-
url,
|
|
4467
|
-
type,
|
|
4468
|
-
mimeType: null,
|
|
4469
|
-
filename: safeFilename(url, i),
|
|
4470
|
-
savedPath: null,
|
|
4471
|
-
sizeBytes: null
|
|
4472
|
-
})),
|
|
4473
|
-
filteredCount: filteredUrls.length,
|
|
4474
|
-
totalFound
|
|
4475
|
-
};
|
|
4476
|
-
}
|
|
4477
|
-
const domain = (() => {
|
|
4478
|
-
try {
|
|
4479
|
-
return new URL(pageUrl).hostname.replace(/^www\./, "");
|
|
4480
|
-
} catch {
|
|
4481
|
-
return "unknown";
|
|
4482
|
-
}
|
|
4483
|
-
})();
|
|
4484
|
-
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
4485
|
-
const outDir = options.outputDir ?? join2(homedir(), "Downloads", "mcp-scraper", "media", `${stamp}-${domain}`);
|
|
4486
|
-
mkdirSync(outDir, { recursive: true });
|
|
4487
|
-
const assets = [];
|
|
4488
|
-
await Promise.allSettled(
|
|
4489
|
-
kept.map(async ({ url, type }, i) => {
|
|
4490
|
-
const filename = safeFilename(url, i);
|
|
4491
|
-
try {
|
|
4492
|
-
const { savedPath, sizeBytes, mimeType } = await downloadAsset(url, outDir, filename);
|
|
4493
|
-
const resolvedType = mimeType ? typeFromMime(mimeType) ?? type : type;
|
|
4494
|
-
assets.push({ url, type: resolvedType, mimeType, filename: basename(savedPath), savedPath, sizeBytes });
|
|
4495
|
-
} catch {
|
|
4496
|
-
assets.push({ url, type, mimeType: null, filename, savedPath: null, sizeBytes: null });
|
|
4497
|
-
}
|
|
4498
|
-
})
|
|
4499
|
-
);
|
|
4500
|
-
assets.sort((a, b) => {
|
|
4501
|
-
if (a.savedPath && !b.savedPath) return -1;
|
|
4502
|
-
if (!a.savedPath && b.savedPath) return 1;
|
|
4503
|
-
return a.url.localeCompare(b.url);
|
|
4504
|
-
});
|
|
4505
|
-
return { pageUrl, outputDir: outDir, assets, filteredCount: filteredUrls.length, totalFound };
|
|
4506
|
-
}
|
|
4507
|
-
|
|
4508
4232
|
// src/api/site-mapper.ts
|
|
4509
4233
|
var SKIP_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
4510
4234
|
"jpg",
|
|
@@ -7628,7 +7352,7 @@ var siteExtractFn = inngest.createFunction(
|
|
|
7628
7352
|
return buildSeoAudit(pages, job.startUrl);
|
|
7629
7353
|
}) : null;
|
|
7630
7354
|
const artifacts = await step.run("finalize", async () => {
|
|
7631
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
7355
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-OSUPAHCE.js");
|
|
7632
7356
|
const stored = await assembleExtractArtifacts(job, { branding, imageAudit, seoAudit });
|
|
7633
7357
|
await completeExtractJob(jobId, stored);
|
|
7634
7358
|
return stored;
|
|
@@ -9100,6 +8824,7 @@ var ExtractSiteBodySchema = z11.object({
|
|
|
9100
8824
|
rotateProxies: z11.boolean().optional(),
|
|
9101
8825
|
rotateProxyEvery: z11.number().int().min(1).max(100).optional(),
|
|
9102
8826
|
background: z11.boolean().optional(),
|
|
8827
|
+
downloadImages: z11.boolean().optional(),
|
|
9103
8828
|
formats: z11.array(z11.enum(["markdown", "links", "json", "images", "branding", "issues"])).optional()
|
|
9104
8829
|
});
|
|
9105
8830
|
var YoutubeHarvestBodySchema = z11.object({
|
|
@@ -11187,7 +10912,7 @@ import { Hono as Hono7 } from "hono";
|
|
|
11187
10912
|
import { z as z15 } from "zod";
|
|
11188
10913
|
import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "fs";
|
|
11189
10914
|
import { tmpdir } from "os";
|
|
11190
|
-
import { join as
|
|
10915
|
+
import { join as join3 } from "path";
|
|
11191
10916
|
import { spawn } from "child_process";
|
|
11192
10917
|
|
|
11193
10918
|
// src/extractor/InstagramContentExtractor.ts
|
|
@@ -11785,8 +11510,8 @@ instagramApp.post("/media-download", createApiKeyAuth(), async (c) => {
|
|
|
11785
11510
|
downloads.push({ kind, url: track.url, savedPath: stored.url, sizeBytes: stored.bytes, mimeType, error: null });
|
|
11786
11511
|
const isMuxInput = muxEligible && (track.url === extraction.selectedVideoTrack.url || track.url === extraction.selectedAudioTrack.url);
|
|
11787
11512
|
if (isMuxInput) {
|
|
11788
|
-
if (!muxWorkDir) muxWorkDir = mkdtempSync(
|
|
11789
|
-
const localPath =
|
|
11513
|
+
if (!muxWorkDir) muxWorkDir = mkdtempSync(join3(tmpdir(), "ig-mux-"));
|
|
11514
|
+
const localPath = join3(muxWorkDir, trackFilename(track, index, extraction.shortcode));
|
|
11790
11515
|
writeFileSync(localPath, bytes);
|
|
11791
11516
|
muxInputs.set(track.url, localPath);
|
|
11792
11517
|
}
|
|
@@ -11795,7 +11520,7 @@ instagramApp.post("/media-download", createApiKeyAuth(), async (c) => {
|
|
|
11795
11520
|
}
|
|
11796
11521
|
}
|
|
11797
11522
|
if (muxEligible && muxWorkDir && muxInputs.has(extraction.selectedVideoTrack.url) && muxInputs.has(extraction.selectedAudioTrack.url)) {
|
|
11798
|
-
const outPath =
|
|
11523
|
+
const outPath = join3(muxWorkDir, "muxed.mp4");
|
|
11799
11524
|
const muxed = await runFfmpegMux(muxInputs.get(extraction.selectedVideoTrack.url), muxInputs.get(extraction.selectedAudioTrack.url), outPath);
|
|
11800
11525
|
if (muxed.ok) {
|
|
11801
11526
|
const stored = await store.put(`${prefix}/muxed.mp4`, readFileSync2(outPath), "video/mp4");
|
|
@@ -13706,7 +13431,7 @@ import { Hono as Hono13 } from "hono";
|
|
|
13706
13431
|
|
|
13707
13432
|
// src/directory/directory-workflow.ts
|
|
13708
13433
|
import { mkdir as mkdir2, writeFile } from "fs/promises";
|
|
13709
|
-
import { join as
|
|
13434
|
+
import { join as join4 } from "path";
|
|
13710
13435
|
import { z as z21 } from "zod";
|
|
13711
13436
|
|
|
13712
13437
|
// src/directory/location-db.ts
|
|
@@ -14042,11 +13767,11 @@ function csvRowsFor(result) {
|
|
|
14042
13767
|
return rows;
|
|
14043
13768
|
}
|
|
14044
13769
|
async function saveDirectoryCsv(result) {
|
|
14045
|
-
const outDir =
|
|
13770
|
+
const outDir = join4(outputBaseDir(), "directory-workflows");
|
|
14046
13771
|
await mkdir2(outDir, { recursive: true });
|
|
14047
13772
|
const stamp = result.extractedAt.replace(/[:.]/g, "-");
|
|
14048
13773
|
const slug = `${result.state}-${result.query}`.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
14049
|
-
const path5 =
|
|
13774
|
+
const path5 = join4(outDir, `${stamp}-${slug}-directory-workflow.csv`);
|
|
14050
13775
|
const headers = [
|
|
14051
13776
|
"source_query",
|
|
14052
13777
|
"source_location",
|
|
@@ -20618,8 +20343,8 @@ async function importServiceConnectionToMemory(identity, input, dependencies) {
|
|
|
20618
20343
|
|
|
20619
20344
|
// src/api/scrape-blob-cleanup.ts
|
|
20620
20345
|
import { readdir, stat, unlink } from "fs/promises";
|
|
20621
|
-
import { homedir
|
|
20622
|
-
import { join as
|
|
20346
|
+
import { homedir } from "os";
|
|
20347
|
+
import { join as join5 } from "path";
|
|
20623
20348
|
async function cleanupVercel(token, cutoff) {
|
|
20624
20349
|
const { list, del } = await import("@vercel/blob");
|
|
20625
20350
|
let cursor;
|
|
@@ -20636,8 +20361,8 @@ async function cleanupVercel(token, cutoff) {
|
|
|
20636
20361
|
return { deleted, store: "vercel-blob" };
|
|
20637
20362
|
}
|
|
20638
20363
|
async function cleanupLocal(cutoff) {
|
|
20639
|
-
const baseDir = process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() ||
|
|
20640
|
-
const dir =
|
|
20364
|
+
const baseDir = process.env.MCP_SCRAPER_OUTPUT_DIR?.trim() || join5(homedir(), "Downloads", "mcp-scraper");
|
|
20365
|
+
const dir = join5(baseDir, "blobs", SCRAPE_FALLBACK_PREFIX.replace(/\/$/, ""));
|
|
20641
20366
|
let deleted = 0;
|
|
20642
20367
|
let entries;
|
|
20643
20368
|
try {
|
|
@@ -20646,7 +20371,7 @@ async function cleanupLocal(cutoff) {
|
|
|
20646
20371
|
return { deleted: 0, store: "local" };
|
|
20647
20372
|
}
|
|
20648
20373
|
for (const name of entries) {
|
|
20649
|
-
const path5 =
|
|
20374
|
+
const path5 = join5(dir, name);
|
|
20650
20375
|
try {
|
|
20651
20376
|
const s = await stat(path5);
|
|
20652
20377
|
if (s.isFile() && s.mtimeMs < cutoff) {
|
|
@@ -22219,7 +21944,7 @@ var auth2 = createMiddleware3(async (c, next) => {
|
|
|
22219
21944
|
const user = await getUserByApiKey(key);
|
|
22220
21945
|
if (!user) return c.json({ error: "Invalid or inactive API key" }, 401);
|
|
22221
21946
|
const refreshed = await applyMonthlyFreeRefresh(user);
|
|
22222
|
-
const balanceMc = await reconcileBalanceMc(refreshed.id);
|
|
21947
|
+
const balanceMc = await reconcileBalanceMc(refreshed.id, refreshed.balance_mc);
|
|
22223
21948
|
c.set("user", { ...refreshed, balance_mc: balanceMc });
|
|
22224
21949
|
return next();
|
|
22225
21950
|
});
|
|
@@ -22238,7 +21963,7 @@ var sessionAuth = createMiddleware3(async (c, next) => {
|
|
|
22238
21963
|
const user = await getUserById(userId);
|
|
22239
21964
|
if (!user) return c.json({ error: "User not found" }, 401);
|
|
22240
21965
|
const refreshed = await applyMonthlyFreeRefresh(user);
|
|
22241
|
-
const balanceMc = await reconcileBalanceMc(refreshed.id);
|
|
21966
|
+
const balanceMc = await reconcileBalanceMc(refreshed.id, refreshed.balance_mc);
|
|
22242
21967
|
c.set("sessionUser", { ...refreshed, balance_mc: balanceMc });
|
|
22243
21968
|
return next();
|
|
22244
21969
|
});
|
|
@@ -22478,7 +22203,7 @@ app.get("/me", async (c) => {
|
|
|
22478
22203
|
}
|
|
22479
22204
|
const refreshed = await applyMonthlyFreeRefresh(foundUser);
|
|
22480
22205
|
const [balanceMc, stats] = await Promise.all([
|
|
22481
|
-
reconcileBalanceMc(refreshed.id),
|
|
22206
|
+
reconcileBalanceMc(refreshed.id, refreshed.balance_mc),
|
|
22482
22207
|
getUserStats(refreshed.id)
|
|
22483
22208
|
]);
|
|
22484
22209
|
const user = { ...refreshed, balance_mc: balanceMc };
|
|
@@ -23902,7 +23627,8 @@ app.post("/extract-site", auth2, async (c) => {
|
|
|
23902
23627
|
if (checked.error || !checked.parsed) return c.json({ error: checked.error ?? "Invalid URL" }, 400);
|
|
23903
23628
|
const parsed = checked.parsed;
|
|
23904
23629
|
const user = c.get("user");
|
|
23905
|
-
|
|
23630
|
+
const downloadImages = body.downloadImages === true;
|
|
23631
|
+
if (body.background === true || downloadImages) {
|
|
23906
23632
|
const affordablePages = Math.floor(user.balance_mc / MC_COSTS.page_scrape);
|
|
23907
23633
|
if (affordablePages < 1) return c.json(insufficientBalanceResponse(user.balance_mc, MC_COSTS.page_scrape), 402);
|
|
23908
23634
|
const maxPages = Math.min(Math.min(1e4, Math.max(1, body.maxPages ?? 1e4)), affordablePages);
|
|
@@ -23917,6 +23643,7 @@ app.post("/extract-site", auth2, async (c) => {
|
|
|
23917
23643
|
concurrency: concurrencyLimitForUser(user),
|
|
23918
23644
|
urlsPerBrowser: body.rotateProxyEvery ?? 10,
|
|
23919
23645
|
formats: body.formats,
|
|
23646
|
+
downloadImages,
|
|
23920
23647
|
heldMc
|
|
23921
23648
|
});
|
|
23922
23649
|
jobCreated = true;
|
|
@@ -24225,7 +23952,7 @@ app.post("/billing/concurrency/cancel", requireAllowedOrigin, sessionAuth, async
|
|
|
24225
23952
|
});
|
|
24226
23953
|
app.get("/billing/balance", auth2, async (c) => {
|
|
24227
23954
|
const user = c.get("user");
|
|
24228
|
-
const balanceMc =
|
|
23955
|
+
const balanceMc = user.balance_mc;
|
|
24229
23956
|
const ledger = await getLedger(user.id, 20);
|
|
24230
23957
|
const freeCredits = await getFreeCreditBreakdown(user.id);
|
|
24231
23958
|
return c.json({
|
|
@@ -24237,7 +23964,7 @@ app.get("/billing/balance", auth2, async (c) => {
|
|
|
24237
23964
|
});
|
|
24238
23965
|
app.post("/billing/credits", auth2, async (c) => {
|
|
24239
23966
|
const user = c.get("user");
|
|
24240
|
-
const balanceMc =
|
|
23967
|
+
const balanceMc = user.balance_mc;
|
|
24241
23968
|
const body = await c.req.json().catch(() => ({}));
|
|
24242
23969
|
const query = body.item?.trim().toLowerCase();
|
|
24243
23970
|
const costs = CREDIT_COST_CATALOG.map(({ aliases, ...cost }) => cost);
|
|
@@ -24270,7 +23997,7 @@ app.get("/cron/tick", async (c) => {
|
|
|
24270
23997
|
if (!process.env.CRON_SECRET || secret2 !== `Bearer ${process.env.CRON_SECRET}`) {
|
|
24271
23998
|
return c.json({ error: "Unauthorized" }, 401);
|
|
24272
23999
|
}
|
|
24273
|
-
const { drainQueue } = await import("./worker-
|
|
24000
|
+
const { drainQueue } = await import("./worker-O5PZTTPY.js");
|
|
24274
24001
|
const budget = { maxJobs: 10, deadlineMs: Date.now() + 28e4 };
|
|
24275
24002
|
const workflowDispatchResult = await dispatchDueWorkflowSchedules(`${new URL(c.req.url).protocol}//${new URL(c.req.url).host}`);
|
|
24276
24003
|
const [results, sweepResult, reapResult, expiredResult, blobCleanup, connectedDataArtifactCleanup] = await Promise.all([
|
|
@@ -24298,15 +24025,15 @@ app.post("/api/internal/extract-refinalize/:id", async (c) => {
|
|
|
24298
24025
|
return c.json({ error: "Unauthorized" }, 401);
|
|
24299
24026
|
}
|
|
24300
24027
|
const jobId = c.req.param("id");
|
|
24301
|
-
const { getExtractJob: getExtractJob2, completeExtractJob: completeExtractJob2 } = await import("./site-extract-repository-
|
|
24302
|
-
const { assembleExtractArtifacts } = await import("./extract-bundle-
|
|
24028
|
+
const { getExtractJob: getExtractJob2, completeExtractJob: completeExtractJob2 } = await import("./site-extract-repository-GWKGK46Z.js");
|
|
24029
|
+
const { assembleExtractArtifacts } = await import("./extract-bundle-OSUPAHCE.js");
|
|
24303
24030
|
const job = await getExtractJob2(jobId);
|
|
24304
24031
|
if (!job) return c.json({ error: "job not found" }, 404);
|
|
24305
24032
|
const stored = await assembleExtractArtifacts(job, {});
|
|
24306
24033
|
await completeExtractJob2(jobId, stored);
|
|
24307
24034
|
let settlement = "already_settled_or_refunded";
|
|
24308
24035
|
if (job.billedMc == null && job.userId != null) {
|
|
24309
|
-
const { settleExtractJob: settleExtractJob2, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-
|
|
24036
|
+
const { settleExtractJob: settleExtractJob2, countSuccessfulPages: countSuccessfulPages2 } = await import("./site-extract-repository-GWKGK46Z.js");
|
|
24310
24037
|
const heldMc = Number(job.options.heldMc ?? 0);
|
|
24311
24038
|
const successful = await countSuccessfulPages2(jobId);
|
|
24312
24039
|
const usedMc = Math.min(successful * MC_COSTS.page_scrape, heldMc);
|
|
@@ -24471,4 +24198,4 @@ app.get("/blog/:slug/", (c) => {
|
|
|
24471
24198
|
export {
|
|
24472
24199
|
app
|
|
24473
24200
|
};
|
|
24474
|
-
//# sourceMappingURL=server-
|
|
24201
|
+
//# sourceMappingURL=server-VDWIPV7F.js.map
|