open-nami 1.2.3 → 1.2.5
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/cli.js +685 -148
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ var require_package = __commonJS({
|
|
|
9
9
|
"package.json"(exports, module) {
|
|
10
10
|
module.exports = {
|
|
11
11
|
name: "open-nami",
|
|
12
|
-
version: "1.2.
|
|
12
|
+
version: "1.2.5",
|
|
13
13
|
description: "Open Nami: terminal-first bulk social media profile downloader for Instagram, TikTok, Facebook & X.",
|
|
14
14
|
type: "module",
|
|
15
15
|
bin: {
|
|
@@ -77,7 +77,7 @@ import { createRequire } from "module";
|
|
|
77
77
|
import { render } from "ink";
|
|
78
78
|
|
|
79
79
|
// src/app.tsx
|
|
80
|
-
import { useState as useState9, useCallback as useCallback5, useRef as useRef5, useEffect as
|
|
80
|
+
import { useState as useState9, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect8, useMemo as useMemo3 } from "react";
|
|
81
81
|
import { Box as Box15, Text as Text17, useApp, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
82
82
|
import Spinner4 from "ink-spinner";
|
|
83
83
|
|
|
@@ -287,15 +287,17 @@ function FramedInput({
|
|
|
287
287
|
children
|
|
288
288
|
}) {
|
|
289
289
|
const theme = useTheme();
|
|
290
|
-
const inner = width - 2;
|
|
291
|
-
const
|
|
290
|
+
const inner = Math.max(0, width - 2);
|
|
291
|
+
const maxTitleLen = Math.max(0, inner - 4);
|
|
292
|
+
const displayTitle = title.length > maxTitleLen ? title.slice(0, Math.max(0, maxTitleLen - 1)) + "\u2026" : title;
|
|
293
|
+
const tail = Math.max(0, inner - displayTitle.length - 3);
|
|
292
294
|
const buttonW = button ? frameButtonWidth(button) : 0;
|
|
293
295
|
const fillColor = buttonDim ? theme.gray : theme.primary;
|
|
294
296
|
return /* @__PURE__ */ jsxs2(Box3, { width: width + buttonW, children: [
|
|
295
297
|
/* @__PURE__ */ jsxs2(Box3, { flexDirection: "column", width, children: [
|
|
296
|
-
/* @__PURE__ */ jsxs2(Text3, { children: [
|
|
298
|
+
/* @__PURE__ */ jsxs2(Text3, { wrap: "truncate-end", children: [
|
|
297
299
|
/* @__PURE__ */ jsx4(Text3, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u256D\u2500 " }),
|
|
298
|
-
/* @__PURE__ */ jsx4(Text3, { color: theme.primary, children:
|
|
300
|
+
/* @__PURE__ */ jsx4(Text3, { color: theme.primary, children: displayTitle }),
|
|
299
301
|
/* @__PURE__ */ jsx4(Text3, { color: theme.gray, dimColor: theme.dimSecondary, children: ` ${"\u2500".repeat(tail)}${button ? "\u2500" : "\u256E"}` })
|
|
300
302
|
] }),
|
|
301
303
|
/* @__PURE__ */ jsxs2(Box3, { width, height: 1, overflow: "hidden", children: [
|
|
@@ -661,12 +663,14 @@ import { Box as Box5, Text as Text6 } from "ink";
|
|
|
661
663
|
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
662
664
|
function Panel({ title, width, children }) {
|
|
663
665
|
const theme = useTheme();
|
|
664
|
-
const inner = width - 2;
|
|
665
|
-
const
|
|
666
|
+
const inner = Math.max(0, width - 2);
|
|
667
|
+
const maxTitleLen = Math.max(0, inner - 4);
|
|
668
|
+
const displayTitle = title.length > maxTitleLen ? title.slice(0, Math.max(0, maxTitleLen - 1)) + "\u2026" : title;
|
|
669
|
+
const tail = Math.max(0, inner - displayTitle.length - 3);
|
|
666
670
|
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", width, children: [
|
|
667
|
-
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
671
|
+
/* @__PURE__ */ jsxs5(Text6, { wrap: "truncate-end", children: [
|
|
668
672
|
/* @__PURE__ */ jsx7(Text6, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u256D\u2500 " }),
|
|
669
|
-
/* @__PURE__ */ jsx7(Text6, { color: theme.primary, children:
|
|
673
|
+
/* @__PURE__ */ jsx7(Text6, { color: theme.primary, children: displayTitle }),
|
|
670
674
|
/* @__PURE__ */ jsx7(Text6, { color: theme.gray, dimColor: theme.dimSecondary, children: ` ${"\u2500".repeat(tail)}\u256E` })
|
|
671
675
|
] }),
|
|
672
676
|
/* @__PURE__ */ jsx7(
|
|
@@ -3323,6 +3327,15 @@ function parseDateBoundary(input, boundary) {
|
|
|
3323
3327
|
return nowSeconds - offsetSeconds;
|
|
3324
3328
|
}
|
|
3325
3329
|
if (/^\d+$/.test(trimmed)) {
|
|
3330
|
+
if (trimmed.length === 4) {
|
|
3331
|
+
const year = parseInt(trimmed, 10);
|
|
3332
|
+
if (year >= 1990 && year <= 2100) {
|
|
3333
|
+
const date = boundary === "until" ? new Date(Date.UTC(year, 11, 31, 23, 59, 59, 999)) : new Date(Date.UTC(year, 0, 1, 0, 0, 0, 0));
|
|
3334
|
+
if (!isNaN(date.getTime())) {
|
|
3335
|
+
return Math.floor(date.getTime() / 1e3);
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3326
3339
|
if (trimmed.length === 8) {
|
|
3327
3340
|
const year = parseInt(trimmed.slice(0, 4), 10);
|
|
3328
3341
|
const month = parseInt(trimmed.slice(4, 6), 10) - 1;
|
|
@@ -3338,6 +3351,14 @@ function parseDateBoundary(input, boundary) {
|
|
|
3338
3351
|
}
|
|
3339
3352
|
return num;
|
|
3340
3353
|
}
|
|
3354
|
+
if (/^\d{4}-\d{2}$/.test(trimmed)) {
|
|
3355
|
+
const year = parseInt(trimmed.slice(0, 4), 10);
|
|
3356
|
+
const month = parseInt(trimmed.slice(5, 7), 10);
|
|
3357
|
+
const date = boundary === "until" ? new Date(Date.UTC(year, month, 0, 23, 59, 59, 999)) : new Date(Date.UTC(year, month - 1, 1, 0, 0, 0, 0));
|
|
3358
|
+
if (!isNaN(date.getTime())) {
|
|
3359
|
+
return Math.floor(date.getTime() / 1e3);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3341
3362
|
if (/^\d{4}-\d{2}-\d{2}$/.test(trimmed)) {
|
|
3342
3363
|
const timeStr = boundary === "until" ? "T23:59:59.999Z" : "T00:00:00.000Z";
|
|
3343
3364
|
const parsed2 = /* @__PURE__ */ new Date(`${trimmed}${timeStr}`);
|
|
@@ -3351,8 +3372,34 @@ function parseDateBoundary(input, boundary) {
|
|
|
3351
3372
|
}
|
|
3352
3373
|
return void 0;
|
|
3353
3374
|
}
|
|
3375
|
+
function resolveDateFilter(input) {
|
|
3376
|
+
if (!input) return {};
|
|
3377
|
+
const trimmed = input.trim();
|
|
3378
|
+
if (!trimmed || trimmed.toLowerCase() === "all" || trimmed.toLowerCase() === "none") return {};
|
|
3379
|
+
if (trimmed.includes("..") || /\s+-\s+/.test(trimmed)) {
|
|
3380
|
+
const parts = trimmed.split(/\.\.|\s+-\s+/);
|
|
3381
|
+
return {
|
|
3382
|
+
since: parts[0]?.trim(),
|
|
3383
|
+
until: parts[1]?.trim()
|
|
3384
|
+
};
|
|
3385
|
+
}
|
|
3386
|
+
if (/^\d{4}$/.test(trimmed) || /^\d{4}-\d{2}$/.test(trimmed)) {
|
|
3387
|
+
return {
|
|
3388
|
+
since: trimmed,
|
|
3389
|
+
until: trimmed
|
|
3390
|
+
};
|
|
3391
|
+
}
|
|
3392
|
+
return {
|
|
3393
|
+
since: trimmed,
|
|
3394
|
+
until: void 0
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3354
3397
|
function parseLimit(input) {
|
|
3355
3398
|
if (input === void 0 || input === null) return void 0;
|
|
3399
|
+
if (typeof input === "string") {
|
|
3400
|
+
const trimmed = input.trim().toLowerCase();
|
|
3401
|
+
if (!trimmed || trimmed === "all" || trimmed === "none" || trimmed === "0") return void 0;
|
|
3402
|
+
}
|
|
3356
3403
|
const num = typeof input === "number" ? input : parseInt(String(input).trim(), 10);
|
|
3357
3404
|
if (isNaN(num) || num <= 0) return void 0;
|
|
3358
3405
|
return Math.floor(num);
|
|
@@ -4321,7 +4368,7 @@ async function dispatchDownload(options) {
|
|
|
4321
4368
|
}
|
|
4322
4369
|
|
|
4323
4370
|
// src/components/views/picking-view.tsx
|
|
4324
|
-
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4371
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4325
4372
|
function ChoiceIndicator({ isSelected }) {
|
|
4326
4373
|
const theme = useTheme();
|
|
4327
4374
|
return /* @__PURE__ */ jsx8(Box6, { marginRight: 1, children: /* @__PURE__ */ jsx8(Text7, { color: theme.primary, children: isSelected ? "\u276F" : " " }) });
|
|
@@ -4345,6 +4392,8 @@ function getPickingOptions(platform) {
|
|
|
4345
4392
|
});
|
|
4346
4393
|
return items;
|
|
4347
4394
|
}
|
|
4395
|
+
var DATE_PRESETS = ["all", "24h", "7d", "30d", "2024", "2023", "2022", "2021", "custom"];
|
|
4396
|
+
var LIMIT_PRESETS = [void 0, 10, 24, 50, 100, "custom"];
|
|
4348
4397
|
function PickingView({
|
|
4349
4398
|
contentWidth,
|
|
4350
4399
|
profile,
|
|
@@ -4362,14 +4411,17 @@ function PickingView({
|
|
|
4362
4411
|
const items = getPickingOptions(profile.platform);
|
|
4363
4412
|
const [limit, setLimit] = useState4(initialLimit);
|
|
4364
4413
|
const [dateFilter, setDateFilter] = useState4(() => {
|
|
4365
|
-
if (typeof initialSince === "string" && (
|
|
4366
|
-
return initialSince;
|
|
4414
|
+
if (typeof initialSince === "string" && initialSince.trim()) {
|
|
4415
|
+
return initialSince.trim();
|
|
4367
4416
|
}
|
|
4368
4417
|
return "all";
|
|
4369
4418
|
});
|
|
4370
4419
|
const [writeMetadata, setWriteMetadata] = useState4(initialWriteMetadata);
|
|
4371
4420
|
const [resume, setResume] = useState4(initialResume);
|
|
4372
4421
|
const [hasCheckpoint, setHasCheckpoint] = useState4(false);
|
|
4422
|
+
const [editingModal, setEditingModal] = useState4(null);
|
|
4423
|
+
const [customLimitText, setCustomLimitText] = useState4("");
|
|
4424
|
+
const [customDateText, setCustomDateText] = useState4("");
|
|
4373
4425
|
const targetDir = resolveDefaultDownloadDir(profile.platform, profile.username, outputDir);
|
|
4374
4426
|
useEffect4(() => {
|
|
4375
4427
|
let isMounted = true;
|
|
@@ -4385,29 +4437,40 @@ function PickingView({
|
|
|
4385
4437
|
};
|
|
4386
4438
|
}, [targetDir]);
|
|
4387
4439
|
const cycleLimit = useCallback(() => {
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
}
|
|
4395
|
-
|
|
4440
|
+
const curIdx = LIMIT_PRESETS.findIndex((p) => p === limit);
|
|
4441
|
+
const nextIdx = (curIdx + 1) % LIMIT_PRESETS.length;
|
|
4442
|
+
const nextVal = LIMIT_PRESETS[nextIdx];
|
|
4443
|
+
if (nextVal === "custom") {
|
|
4444
|
+
setCustomLimitText(limit ? String(limit) : "24");
|
|
4445
|
+
setEditingModal("limit");
|
|
4446
|
+
} else {
|
|
4447
|
+
setLimit(nextVal);
|
|
4448
|
+
}
|
|
4449
|
+
}, [limit]);
|
|
4396
4450
|
const cycleDate = useCallback(() => {
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4451
|
+
const curIdx = DATE_PRESETS.indexOf(dateFilter);
|
|
4452
|
+
const nextIdx = (curIdx + 1) % DATE_PRESETS.length;
|
|
4453
|
+
const nextVal = DATE_PRESETS[nextIdx];
|
|
4454
|
+
if (nextVal === "custom") {
|
|
4455
|
+
setCustomDateText(dateFilter !== "all" ? dateFilter : "2021");
|
|
4456
|
+
setEditingModal("date");
|
|
4457
|
+
} else {
|
|
4458
|
+
setDateFilter(nextVal);
|
|
4459
|
+
}
|
|
4460
|
+
}, [dateFilter]);
|
|
4404
4461
|
const toggleMetadata = useCallback(() => {
|
|
4405
4462
|
setWriteMetadata((prev) => !prev);
|
|
4406
4463
|
}, []);
|
|
4407
4464
|
const toggleResume = useCallback(() => {
|
|
4408
4465
|
setResume((prev) => !prev);
|
|
4409
4466
|
}, []);
|
|
4410
|
-
useInput2((input) => {
|
|
4467
|
+
useInput2((input, key) => {
|
|
4468
|
+
if (editingModal) {
|
|
4469
|
+
if (key.escape) {
|
|
4470
|
+
setEditingModal(null);
|
|
4471
|
+
}
|
|
4472
|
+
return;
|
|
4473
|
+
}
|
|
4411
4474
|
if (input === "l" || input === "L") {
|
|
4412
4475
|
cycleLimit();
|
|
4413
4476
|
return;
|
|
@@ -4426,10 +4489,13 @@ function PickingView({
|
|
|
4426
4489
|
}
|
|
4427
4490
|
}, { isActive: Boolean(process.stdin.isTTY) });
|
|
4428
4491
|
const handleItemSelect = (selectedChoice) => {
|
|
4492
|
+
if (editingModal) return;
|
|
4493
|
+
const dateRange = resolveDateFilter(dateFilter);
|
|
4429
4494
|
onSelect({
|
|
4430
4495
|
choice: selectedChoice,
|
|
4431
4496
|
limit,
|
|
4432
|
-
since:
|
|
4497
|
+
since: dateRange.since,
|
|
4498
|
+
until: dateRange.until,
|
|
4433
4499
|
writeMetadata,
|
|
4434
4500
|
resume
|
|
4435
4501
|
});
|
|
@@ -4447,12 +4513,11 @@ function PickingView({
|
|
|
4447
4513
|
profile.cleanUrl ? ` \xB7 ${profile.cleanUrl}` : ""
|
|
4448
4514
|
] }),
|
|
4449
4515
|
/* @__PURE__ */ jsx8(Gap2, {}),
|
|
4450
|
-
/* @__PURE__ */ jsx8(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: "
|
|
4451
|
-
/* @__PURE__ */ jsx8(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: "Use hotkeys [l], [d], [m], [r] to adjust options." }),
|
|
4516
|
+
/* @__PURE__ */ jsx8(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: "Select media type. Hotkeys [l], [d], [m], [r] adjust options." }),
|
|
4452
4517
|
hasCheckpoint ? /* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: "\u26A1 Checkpoint found (cursor saved)" }) }) : null
|
|
4453
4518
|
] }),
|
|
4454
4519
|
/* @__PURE__ */ jsxs6(Panel, { title: "Download", width: 38, children: [
|
|
4455
|
-
/* @__PURE__ */ jsx8(
|
|
4520
|
+
!editingModal && /* @__PURE__ */ jsx8(
|
|
4456
4521
|
SelectInput,
|
|
4457
4522
|
{
|
|
4458
4523
|
indicatorComponent: ChoiceIndicator,
|
|
@@ -4466,29 +4531,61 @@ function PickingView({
|
|
|
4466
4531
|
onHighlight: (item) => onHighlight?.(item.value)
|
|
4467
4532
|
}
|
|
4468
4533
|
),
|
|
4469
|
-
/* @__PURE__ */
|
|
4534
|
+
/* @__PURE__ */ jsx8(
|
|
4470
4535
|
Box6,
|
|
4471
4536
|
{
|
|
4472
4537
|
flexDirection: "column",
|
|
4473
4538
|
marginTop: 1,
|
|
4474
4539
|
borderStyle: "round",
|
|
4475
|
-
borderColor: theme.gray,
|
|
4476
|
-
borderDimColor:
|
|
4540
|
+
borderColor: editingModal ? theme.primary : theme.gray,
|
|
4541
|
+
borderDimColor: !editingModal,
|
|
4477
4542
|
paddingX: 1,
|
|
4478
|
-
children: [
|
|
4543
|
+
children: editingModal === "limit" ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
4544
|
+
/* @__PURE__ */ jsx8(Text7, { bold: true, color: theme.primary, children: "Set post limit (e.g. 24, all):" }),
|
|
4545
|
+
/* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx8(
|
|
4546
|
+
TextInput,
|
|
4547
|
+
{
|
|
4548
|
+
value: customLimitText,
|
|
4549
|
+
onChange: setCustomLimitText,
|
|
4550
|
+
onSubmit: (val) => {
|
|
4551
|
+
const parsed = parseLimit(val);
|
|
4552
|
+
setLimit(parsed);
|
|
4553
|
+
setEditingModal(null);
|
|
4554
|
+
},
|
|
4555
|
+
width: 24
|
|
4556
|
+
}
|
|
4557
|
+
) }),
|
|
4558
|
+
/* @__PURE__ */ jsx8(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
|
|
4559
|
+
] }) : editingModal === "date" ? /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
4560
|
+
/* @__PURE__ */ jsx8(Text7, { bold: true, color: theme.primary, children: "Set date or year (e.g. 2021, 7d):" }),
|
|
4561
|
+
/* @__PURE__ */ jsx8(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx8(
|
|
4562
|
+
TextInput,
|
|
4563
|
+
{
|
|
4564
|
+
value: customDateText,
|
|
4565
|
+
onChange: setCustomDateText,
|
|
4566
|
+
onSubmit: (val) => {
|
|
4567
|
+
const trimmed = val.trim();
|
|
4568
|
+
setDateFilter(trimmed ? trimmed : "all");
|
|
4569
|
+
setEditingModal(null);
|
|
4570
|
+
},
|
|
4571
|
+
width: 24
|
|
4572
|
+
}
|
|
4573
|
+
) }),
|
|
4574
|
+
/* @__PURE__ */ jsx8(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
|
|
4575
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
4479
4576
|
/* @__PURE__ */ jsxs6(Box6, { justifyContent: "space-between", children: [
|
|
4480
4577
|
/* @__PURE__ */ jsxs6(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
4481
|
-
"[l]
|
|
4578
|
+
"[l] Posts: ",
|
|
4482
4579
|
/* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: limit ? `${limit}` : "ALL" })
|
|
4483
4580
|
] }),
|
|
4484
4581
|
/* @__PURE__ */ jsxs6(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
4485
4582
|
"[d] Date: ",
|
|
4486
|
-
/* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: dateFilter
|
|
4583
|
+
/* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: dateFilter.toUpperCase() })
|
|
4487
4584
|
] })
|
|
4488
4585
|
] }),
|
|
4489
4586
|
/* @__PURE__ */ jsxs6(Box6, { justifyContent: "space-between", children: [
|
|
4490
4587
|
/* @__PURE__ */ jsxs6(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
4491
|
-
"[m]
|
|
4588
|
+
"[m] Meta: ",
|
|
4492
4589
|
/* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: writeMetadata ? "ON" : "OFF" })
|
|
4493
4590
|
] }),
|
|
4494
4591
|
/* @__PURE__ */ jsxs6(Text7, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
@@ -4496,7 +4593,7 @@ function PickingView({
|
|
|
4496
4593
|
/* @__PURE__ */ jsx8(Text7, { color: theme.primary, bold: true, children: resume ? "ON" : "OFF" })
|
|
4497
4594
|
] })
|
|
4498
4595
|
] })
|
|
4499
|
-
]
|
|
4596
|
+
] })
|
|
4500
4597
|
}
|
|
4501
4598
|
)
|
|
4502
4599
|
] })
|
|
@@ -4711,7 +4808,7 @@ function DownloadingView({
|
|
|
4711
4808
|
// src/components/views/completion-view.tsx
|
|
4712
4809
|
import os7 from "os";
|
|
4713
4810
|
import { Box as Box10, Text as Text12 } from "ink";
|
|
4714
|
-
import { Fragment as
|
|
4811
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
4715
4812
|
var DONE_LABEL = "\u21B5 download another";
|
|
4716
4813
|
function CompletionView({
|
|
4717
4814
|
profile,
|
|
@@ -4723,10 +4820,10 @@ function CompletionView({
|
|
|
4723
4820
|
const plural = result.downloadedCount === 1 ? "" : "s";
|
|
4724
4821
|
const skipText = result.skippedCount > 0 ? ` (${result.skippedCount} archived)` : "";
|
|
4725
4822
|
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", alignItems: "center", children: [
|
|
4726
|
-
/* @__PURE__ */ jsx13(Text12, { children: isZero ? /* @__PURE__ */ jsxs10(
|
|
4823
|
+
/* @__PURE__ */ jsx13(Text12, { children: isZero ? /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
4727
4824
|
/* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.primary, children: "\u2713 profile scanned " }),
|
|
4728
4825
|
/* @__PURE__ */ jsx13(Text12, { color: theme.primary, children: "\u2014 0 media items found" })
|
|
4729
|
-
] }) : /* @__PURE__ */ jsxs10(
|
|
4826
|
+
] }) : /* @__PURE__ */ jsxs10(Fragment3, { children: [
|
|
4730
4827
|
/* @__PURE__ */ jsx13(Text12, { bold: true, color: theme.primary, children: "\u2713 profile downloaded! " }),
|
|
4731
4828
|
/* @__PURE__ */ jsx13(Text12, { color: theme.primary, children: "saved to:" })
|
|
4732
4829
|
] }) }),
|
|
@@ -5532,7 +5629,7 @@ function WatcherView({
|
|
|
5532
5629
|
}
|
|
5533
5630
|
|
|
5534
5631
|
// src/components/views/batch-view.tsx
|
|
5535
|
-
import { useState as useState8, useRef as useRef4, useCallback as useCallback4 } from "react";
|
|
5632
|
+
import { useState as useState8, useRef as useRef4, useCallback as useCallback4, useEffect as useEffect7 } from "react";
|
|
5536
5633
|
import { Box as Box14, Text as Text16, useInput as useInput5 } from "ink";
|
|
5537
5634
|
import Spinner3 from "ink-spinner";
|
|
5538
5635
|
import fs13 from "fs";
|
|
@@ -5570,13 +5667,19 @@ async function runBatchQueue(options) {
|
|
|
5570
5667
|
const choice = options.choice || "all";
|
|
5571
5668
|
const minDelay = options.minDelayMs ?? 2e3;
|
|
5572
5669
|
const maxDelay = options.maxDelayMs ?? 5e3;
|
|
5573
|
-
const items = rawEntries.map((raw) =>
|
|
5574
|
-
raw
|
|
5575
|
-
profile
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5670
|
+
const items = rawEntries.map((raw) => {
|
|
5671
|
+
let profile = parseProfileInput(raw);
|
|
5672
|
+
if (options.defaultPlatform && profile.platform === "unknown" && profile.username) {
|
|
5673
|
+
profile = buildCanonicalProfile(options.defaultPlatform, profile.username, raw);
|
|
5674
|
+
}
|
|
5675
|
+
return {
|
|
5676
|
+
raw,
|
|
5677
|
+
profile,
|
|
5678
|
+
status: "pending",
|
|
5679
|
+
downloaded: 0,
|
|
5680
|
+
skipped: 0
|
|
5681
|
+
};
|
|
5682
|
+
});
|
|
5580
5683
|
let totalDownloaded = 0;
|
|
5581
5684
|
let totalSkipped = 0;
|
|
5582
5685
|
let succeeded = 0;
|
|
@@ -5596,10 +5699,15 @@ async function runBatchQueue(options) {
|
|
|
5596
5699
|
}
|
|
5597
5700
|
options.onAccountStart?.(item, i, items.length);
|
|
5598
5701
|
try {
|
|
5702
|
+
const targetDir = resolveDefaultDownloadDir(
|
|
5703
|
+
item.profile.platform,
|
|
5704
|
+
item.profile.username,
|
|
5705
|
+
options.outputDir
|
|
5706
|
+
);
|
|
5599
5707
|
const res = await dispatchDownload({
|
|
5600
5708
|
profile: item.profile,
|
|
5601
5709
|
choice,
|
|
5602
|
-
outputDir:
|
|
5710
|
+
outputDir: targetDir,
|
|
5603
5711
|
since: options.since,
|
|
5604
5712
|
until: options.until,
|
|
5605
5713
|
limit: options.limit,
|
|
@@ -5646,7 +5754,12 @@ async function runBatchQueue(options) {
|
|
|
5646
5754
|
}
|
|
5647
5755
|
|
|
5648
5756
|
// src/components/views/batch-view.tsx
|
|
5649
|
-
import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5757
|
+
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
5758
|
+
var PLATFORMS = ["instagram", "tiktok", "facebook", "x"];
|
|
5759
|
+
var CHOICES = ["all", "photos", "videos", "stories", "highlights"];
|
|
5760
|
+
var DATE_PRESETS2 = ["all", "24h", "7d", "30d", "2024", "2023", "2022", "2021", "custom"];
|
|
5761
|
+
var LIMIT_PRESETS2 = [void 0, 10, 24, 50, 100, "custom"];
|
|
5762
|
+
var OPTION_CONTROLS = ["platform", "choice", "limit", "date", "meta", "resume", "start"];
|
|
5650
5763
|
function BatchView({
|
|
5651
5764
|
onBack,
|
|
5652
5765
|
outputDir,
|
|
@@ -5655,13 +5768,18 @@ function BatchView({
|
|
|
5655
5768
|
gapComponent: Gap2,
|
|
5656
5769
|
defaultChoice = "all",
|
|
5657
5770
|
defaultLimit,
|
|
5658
|
-
defaultWriteMetadata = false
|
|
5771
|
+
defaultWriteMetadata = false,
|
|
5772
|
+
onRegisterClickTargets
|
|
5659
5773
|
}) {
|
|
5660
5774
|
const [phase, setPhase] = useState8("input");
|
|
5661
5775
|
const [inputField, setInputField] = useState8("text");
|
|
5662
5776
|
const [rawText, setRawText] = useState8("");
|
|
5663
5777
|
const [filePath, setFilePath] = useState8("");
|
|
5664
5778
|
const [errorMessage, setErrorMessage] = useState8(null);
|
|
5779
|
+
const [focusedControl, setFocusedControl] = useState8("input");
|
|
5780
|
+
const [customLimitText, setCustomLimitText] = useState8("");
|
|
5781
|
+
const [customDateText, setCustomDateText] = useState8("");
|
|
5782
|
+
const [defaultPlatform, setDefaultPlatform] = useState8("instagram");
|
|
5665
5783
|
const [choice, setChoice] = useState8(defaultChoice);
|
|
5666
5784
|
const [limit, setLimit] = useState8(defaultLimit);
|
|
5667
5785
|
const [dateFilter, setDateFilter] = useState8("all");
|
|
@@ -5673,30 +5791,40 @@ function BatchView({
|
|
|
5673
5791
|
const [isCooldown, setIsCooldown] = useState8(false);
|
|
5674
5792
|
const [result, setResult] = useState8(null);
|
|
5675
5793
|
const abortControllerRef = useRef4(null);
|
|
5794
|
+
const cyclePlatform = useCallback4(() => {
|
|
5795
|
+
setDefaultPlatform((prev) => {
|
|
5796
|
+
const idx = PLATFORMS.indexOf(prev);
|
|
5797
|
+
return PLATFORMS[(idx + 1) % PLATFORMS.length];
|
|
5798
|
+
});
|
|
5799
|
+
}, []);
|
|
5676
5800
|
const cycleChoice = useCallback4(() => {
|
|
5677
5801
|
setChoice((prev) => {
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
return "all";
|
|
5802
|
+
const idx = CHOICES.indexOf(prev);
|
|
5803
|
+
return CHOICES[(idx + 1) % CHOICES.length];
|
|
5681
5804
|
});
|
|
5682
5805
|
}, []);
|
|
5683
5806
|
const cycleLimit = useCallback4(() => {
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
}
|
|
5691
|
-
|
|
5807
|
+
const curIdx = LIMIT_PRESETS2.findIndex((p) => p === limit);
|
|
5808
|
+
const nextIdx = (curIdx + 1) % LIMIT_PRESETS2.length;
|
|
5809
|
+
const nextVal = LIMIT_PRESETS2[nextIdx];
|
|
5810
|
+
if (nextVal === "custom") {
|
|
5811
|
+
setCustomLimitText(limit ? String(limit) : "24");
|
|
5812
|
+
setFocusedControl("custom-limit");
|
|
5813
|
+
} else {
|
|
5814
|
+
setLimit(nextVal);
|
|
5815
|
+
}
|
|
5816
|
+
}, [limit]);
|
|
5692
5817
|
const cycleDate = useCallback4(() => {
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5818
|
+
const curIdx = DATE_PRESETS2.indexOf(dateFilter);
|
|
5819
|
+
const nextIdx = (curIdx + 1) % DATE_PRESETS2.length;
|
|
5820
|
+
const nextVal = DATE_PRESETS2[nextIdx];
|
|
5821
|
+
if (nextVal === "custom") {
|
|
5822
|
+
setCustomDateText(dateFilter !== "all" ? dateFilter : "2024");
|
|
5823
|
+
setFocusedControl("custom-date");
|
|
5824
|
+
} else {
|
|
5825
|
+
setDateFilter(nextVal);
|
|
5826
|
+
}
|
|
5827
|
+
}, [dateFilter]);
|
|
5700
5828
|
const toggleMetadata = useCallback4(() => {
|
|
5701
5829
|
setWriteMetadata((prev) => !prev);
|
|
5702
5830
|
}, []);
|
|
@@ -5717,7 +5845,11 @@ function BatchView({
|
|
|
5717
5845
|
return;
|
|
5718
5846
|
}
|
|
5719
5847
|
} else {
|
|
5720
|
-
lines =
|
|
5848
|
+
lines = Array.from(
|
|
5849
|
+
new Set(
|
|
5850
|
+
rawText.split(/[\r\n,;\s]+/).map((s) => s.trim()).filter(Boolean)
|
|
5851
|
+
)
|
|
5852
|
+
);
|
|
5721
5853
|
if (lines.length === 0) {
|
|
5722
5854
|
setErrorMessage("Please enter at least one profile URL or username");
|
|
5723
5855
|
return;
|
|
@@ -5727,12 +5859,15 @@ function BatchView({
|
|
|
5727
5859
|
abortControllerRef.current = controller;
|
|
5728
5860
|
setPhase("running");
|
|
5729
5861
|
try {
|
|
5862
|
+
const dateRange = resolveDateFilter(dateFilter);
|
|
5730
5863
|
const queueRes = await runBatchQueue({
|
|
5731
5864
|
filePath: inputField === "file" ? filePath.trim() : void 0,
|
|
5732
5865
|
lines: inputField === "text" ? lines : void 0,
|
|
5733
5866
|
choice,
|
|
5867
|
+
defaultPlatform,
|
|
5734
5868
|
outputDir,
|
|
5735
|
-
since:
|
|
5869
|
+
since: dateRange.since,
|
|
5870
|
+
until: dateRange.until,
|
|
5736
5871
|
limit,
|
|
5737
5872
|
resume,
|
|
5738
5873
|
writeMetadata,
|
|
@@ -5740,7 +5875,7 @@ function BatchView({
|
|
|
5740
5875
|
onAccountStart: (item, idx) => {
|
|
5741
5876
|
setIsCooldown(false);
|
|
5742
5877
|
setCurrentIndex(idx);
|
|
5743
|
-
setCurrentProgressText(`Probing @${item.profile.username || item.raw}\u2026`);
|
|
5878
|
+
setCurrentProgressText(`Probing @${item.profile.username || item.raw} on ${item.profile.platform}\u2026`);
|
|
5744
5879
|
setQueueItems((prev) => {
|
|
5745
5880
|
const next = [...prev];
|
|
5746
5881
|
if (next[idx]) next[idx] = { ...item };
|
|
@@ -5748,7 +5883,7 @@ function BatchView({
|
|
|
5748
5883
|
return next;
|
|
5749
5884
|
});
|
|
5750
5885
|
},
|
|
5751
|
-
onAccountProgress: (
|
|
5886
|
+
onAccountProgress: (_item, progress) => {
|
|
5752
5887
|
setCurrentProgressText(progress.statusText);
|
|
5753
5888
|
},
|
|
5754
5889
|
onAccountComplete: (item, idx) => {
|
|
@@ -5782,9 +5917,20 @@ function BatchView({
|
|
|
5782
5917
|
setErrorMessage(msg);
|
|
5783
5918
|
setPhase("input");
|
|
5784
5919
|
}
|
|
5785
|
-
}, [inputField, filePath, rawText, choice, outputDir, dateFilter, limit, resume, writeMetadata]);
|
|
5920
|
+
}, [inputField, filePath, rawText, choice, defaultPlatform, outputDir, dateFilter, limit, resume, writeMetadata]);
|
|
5786
5921
|
useInput5((input, key) => {
|
|
5922
|
+
if (key.ctrl && (input === "c" || input === "C")) {
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5787
5925
|
if (key.escape) {
|
|
5926
|
+
if (focusedControl === "custom-limit" || focusedControl === "custom-date") {
|
|
5927
|
+
setFocusedControl("start");
|
|
5928
|
+
return;
|
|
5929
|
+
}
|
|
5930
|
+
if (focusedControl !== "input" && phase === "input") {
|
|
5931
|
+
setFocusedControl("input");
|
|
5932
|
+
return;
|
|
5933
|
+
}
|
|
5788
5934
|
if (phase === "running") {
|
|
5789
5935
|
abortControllerRef.current?.abort();
|
|
5790
5936
|
setPhase("input");
|
|
@@ -5805,98 +5951,466 @@ function BatchView({
|
|
|
5805
5951
|
}
|
|
5806
5952
|
return;
|
|
5807
5953
|
}
|
|
5954
|
+
if (phase === "running") {
|
|
5955
|
+
return;
|
|
5956
|
+
}
|
|
5808
5957
|
if (phase === "input") {
|
|
5809
|
-
if (
|
|
5810
|
-
cycleChoice();
|
|
5811
|
-
return;
|
|
5812
|
-
}
|
|
5813
|
-
if (input === "l" || input === "L") {
|
|
5814
|
-
cycleLimit();
|
|
5958
|
+
if (focusedControl === "custom-limit" || focusedControl === "custom-date") {
|
|
5815
5959
|
return;
|
|
5816
5960
|
}
|
|
5817
|
-
if (
|
|
5818
|
-
|
|
5961
|
+
if (focusedControl === "input") {
|
|
5962
|
+
if (key.downArrow) {
|
|
5963
|
+
setFocusedControl("platform");
|
|
5964
|
+
return;
|
|
5965
|
+
}
|
|
5966
|
+
if (key.upArrow) {
|
|
5967
|
+
setFocusedControl("tabs");
|
|
5968
|
+
return;
|
|
5969
|
+
}
|
|
5819
5970
|
return;
|
|
5820
5971
|
}
|
|
5821
|
-
if (
|
|
5822
|
-
|
|
5972
|
+
if (focusedControl === "tabs") {
|
|
5973
|
+
if (key.leftArrow || key.rightArrow || input === " " || key.return) {
|
|
5974
|
+
setInputField((prev) => prev === "text" ? "file" : "text");
|
|
5975
|
+
return;
|
|
5976
|
+
}
|
|
5977
|
+
if (key.downArrow || key.tab) {
|
|
5978
|
+
setFocusedControl("input");
|
|
5979
|
+
return;
|
|
5980
|
+
}
|
|
5823
5981
|
return;
|
|
5824
5982
|
}
|
|
5825
|
-
if (
|
|
5826
|
-
|
|
5827
|
-
|
|
5983
|
+
if (OPTION_CONTROLS.includes(focusedControl)) {
|
|
5984
|
+
if (key.upArrow) {
|
|
5985
|
+
setFocusedControl("input");
|
|
5986
|
+
return;
|
|
5987
|
+
}
|
|
5988
|
+
if (key.rightArrow || key.tab && !key.shift) {
|
|
5989
|
+
const idx = OPTION_CONTROLS.indexOf(focusedControl);
|
|
5990
|
+
setFocusedControl(OPTION_CONTROLS[(idx + 1) % OPTION_CONTROLS.length]);
|
|
5991
|
+
return;
|
|
5992
|
+
}
|
|
5993
|
+
if (key.leftArrow || key.tab && key.shift) {
|
|
5994
|
+
const idx = OPTION_CONTROLS.indexOf(focusedControl);
|
|
5995
|
+
setFocusedControl(OPTION_CONTROLS[(idx - 1 + OPTION_CONTROLS.length) % OPTION_CONTROLS.length]);
|
|
5996
|
+
return;
|
|
5997
|
+
}
|
|
5998
|
+
if (input === " " || key.return) {
|
|
5999
|
+
switch (focusedControl) {
|
|
6000
|
+
case "platform":
|
|
6001
|
+
cyclePlatform();
|
|
6002
|
+
break;
|
|
6003
|
+
case "choice":
|
|
6004
|
+
cycleChoice();
|
|
6005
|
+
break;
|
|
6006
|
+
case "limit":
|
|
6007
|
+
cycleLimit();
|
|
6008
|
+
break;
|
|
6009
|
+
case "date":
|
|
6010
|
+
cycleDate();
|
|
6011
|
+
break;
|
|
6012
|
+
case "meta":
|
|
6013
|
+
toggleMetadata();
|
|
6014
|
+
break;
|
|
6015
|
+
case "resume":
|
|
6016
|
+
toggleResume();
|
|
6017
|
+
break;
|
|
6018
|
+
case "start":
|
|
6019
|
+
startQueue();
|
|
6020
|
+
break;
|
|
6021
|
+
}
|
|
6022
|
+
return;
|
|
6023
|
+
}
|
|
6024
|
+
if (input === "p" || input === "P") {
|
|
6025
|
+
cyclePlatform();
|
|
6026
|
+
return;
|
|
6027
|
+
}
|
|
6028
|
+
if (input === "c" || input === "C") {
|
|
6029
|
+
cycleChoice();
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
6032
|
+
if (input === "l" || input === "L") {
|
|
6033
|
+
cycleLimit();
|
|
6034
|
+
return;
|
|
6035
|
+
}
|
|
6036
|
+
if (input === "d" || input === "D") {
|
|
6037
|
+
cycleDate();
|
|
6038
|
+
return;
|
|
6039
|
+
}
|
|
6040
|
+
if (input === "m" || input === "M") {
|
|
6041
|
+
toggleMetadata();
|
|
6042
|
+
return;
|
|
6043
|
+
}
|
|
6044
|
+
if (input === "r" || input === "R") {
|
|
6045
|
+
toggleResume();
|
|
6046
|
+
return;
|
|
6047
|
+
}
|
|
5828
6048
|
}
|
|
5829
6049
|
}
|
|
5830
6050
|
}, { isActive: Boolean(process.stdin.isTTY) });
|
|
6051
|
+
useEffect7(() => {
|
|
6052
|
+
if (!onRegisterClickTargets) return;
|
|
6053
|
+
const targets = [];
|
|
6054
|
+
if (phase === "input") {
|
|
6055
|
+
targets.push({
|
|
6056
|
+
match: "Links / Handles",
|
|
6057
|
+
padX: 2,
|
|
6058
|
+
action: () => {
|
|
6059
|
+
setInputField("text");
|
|
6060
|
+
setFocusedControl("input");
|
|
6061
|
+
}
|
|
6062
|
+
});
|
|
6063
|
+
targets.push({
|
|
6064
|
+
match: "File (.txt)",
|
|
6065
|
+
padX: 2,
|
|
6066
|
+
action: () => {
|
|
6067
|
+
setInputField("file");
|
|
6068
|
+
setFocusedControl("input");
|
|
6069
|
+
}
|
|
6070
|
+
});
|
|
6071
|
+
targets.push({
|
|
6072
|
+
match: "Links or @handles",
|
|
6073
|
+
padX: 2,
|
|
6074
|
+
action: () => setFocusedControl("input")
|
|
6075
|
+
});
|
|
6076
|
+
targets.push({
|
|
6077
|
+
match: "Batch file (.txt)",
|
|
6078
|
+
padX: 2,
|
|
6079
|
+
action: () => setFocusedControl("input")
|
|
6080
|
+
});
|
|
6081
|
+
targets.push({
|
|
6082
|
+
match: "Platform:",
|
|
6083
|
+
padX: 2,
|
|
6084
|
+
action: () => {
|
|
6085
|
+
setFocusedControl("platform");
|
|
6086
|
+
cyclePlatform();
|
|
6087
|
+
}
|
|
6088
|
+
});
|
|
6089
|
+
targets.push({
|
|
6090
|
+
match: "Media:",
|
|
6091
|
+
padX: 2,
|
|
6092
|
+
action: () => {
|
|
6093
|
+
setFocusedControl("choice");
|
|
6094
|
+
cycleChoice();
|
|
6095
|
+
}
|
|
6096
|
+
});
|
|
6097
|
+
targets.push({
|
|
6098
|
+
match: "Posts:",
|
|
6099
|
+
padX: 2,
|
|
6100
|
+
action: () => {
|
|
6101
|
+
setFocusedControl("limit");
|
|
6102
|
+
cycleLimit();
|
|
6103
|
+
}
|
|
6104
|
+
});
|
|
6105
|
+
targets.push({
|
|
6106
|
+
match: "Date:",
|
|
6107
|
+
padX: 2,
|
|
6108
|
+
action: () => {
|
|
6109
|
+
setFocusedControl("date");
|
|
6110
|
+
cycleDate();
|
|
6111
|
+
}
|
|
6112
|
+
});
|
|
6113
|
+
targets.push({
|
|
6114
|
+
match: "Meta:",
|
|
6115
|
+
padX: 2,
|
|
6116
|
+
action: () => {
|
|
6117
|
+
setFocusedControl("meta");
|
|
6118
|
+
toggleMetadata();
|
|
6119
|
+
}
|
|
6120
|
+
});
|
|
6121
|
+
targets.push({
|
|
6122
|
+
match: "Resume:",
|
|
6123
|
+
padX: 2,
|
|
6124
|
+
action: () => {
|
|
6125
|
+
setFocusedControl("resume");
|
|
6126
|
+
toggleResume();
|
|
6127
|
+
}
|
|
6128
|
+
});
|
|
6129
|
+
targets.push({
|
|
6130
|
+
match: "Start Queue",
|
|
6131
|
+
padX: 3,
|
|
6132
|
+
action: () => {
|
|
6133
|
+
setFocusedControl("start");
|
|
6134
|
+
startQueue();
|
|
6135
|
+
}
|
|
6136
|
+
});
|
|
6137
|
+
targets.push({
|
|
6138
|
+
match: "tab switch field",
|
|
6139
|
+
action: () => setInputField((prev) => prev === "text" ? "file" : "text")
|
|
6140
|
+
});
|
|
6141
|
+
targets.push({
|
|
6142
|
+
match: "c target",
|
|
6143
|
+
action: cycleChoice
|
|
6144
|
+
});
|
|
6145
|
+
targets.push({
|
|
6146
|
+
match: "m sidecar",
|
|
6147
|
+
action: toggleMetadata
|
|
6148
|
+
});
|
|
6149
|
+
targets.push({
|
|
6150
|
+
match: "l limit",
|
|
6151
|
+
action: cycleLimit
|
|
6152
|
+
});
|
|
6153
|
+
targets.push({
|
|
6154
|
+
match: "d date",
|
|
6155
|
+
action: cycleDate
|
|
6156
|
+
});
|
|
6157
|
+
targets.push({
|
|
6158
|
+
match: "r resume",
|
|
6159
|
+
action: toggleResume
|
|
6160
|
+
});
|
|
6161
|
+
targets.push({
|
|
6162
|
+
match: "\u21B5 start",
|
|
6163
|
+
action: startQueue
|
|
6164
|
+
});
|
|
6165
|
+
}
|
|
6166
|
+
if (phase === "running") {
|
|
6167
|
+
targets.push({
|
|
6168
|
+
match: "Stop queue and return",
|
|
6169
|
+
padX: 2,
|
|
6170
|
+
action: () => {
|
|
6171
|
+
abortControllerRef.current?.abort();
|
|
6172
|
+
setPhase("input");
|
|
6173
|
+
}
|
|
6174
|
+
});
|
|
6175
|
+
targets.push({
|
|
6176
|
+
match: "Stop queue",
|
|
6177
|
+
padX: 2,
|
|
6178
|
+
action: () => {
|
|
6179
|
+
abortControllerRef.current?.abort();
|
|
6180
|
+
setPhase("input");
|
|
6181
|
+
}
|
|
6182
|
+
});
|
|
6183
|
+
}
|
|
6184
|
+
if (phase === "done") {
|
|
6185
|
+
targets.push({
|
|
6186
|
+
match: "Open Downloads Folder",
|
|
6187
|
+
padX: 2,
|
|
6188
|
+
action: () => {
|
|
6189
|
+
const target = outputDir || resolveDefaultDownloadDir("instagram", "batch");
|
|
6190
|
+
revealInFileManager(target);
|
|
6191
|
+
}
|
|
6192
|
+
});
|
|
6193
|
+
targets.push({
|
|
6194
|
+
match: "Return to Start",
|
|
6195
|
+
padX: 2,
|
|
6196
|
+
action: () => setPhase("input")
|
|
6197
|
+
});
|
|
6198
|
+
}
|
|
6199
|
+
onRegisterClickTargets(targets);
|
|
6200
|
+
return () => {
|
|
6201
|
+
onRegisterClickTargets([]);
|
|
6202
|
+
};
|
|
6203
|
+
}, [
|
|
6204
|
+
phase,
|
|
6205
|
+
inputField,
|
|
6206
|
+
focusedControl,
|
|
6207
|
+
onRegisterClickTargets,
|
|
6208
|
+
cyclePlatform,
|
|
6209
|
+
cycleChoice,
|
|
6210
|
+
cycleLimit,
|
|
6211
|
+
cycleDate,
|
|
6212
|
+
toggleMetadata,
|
|
6213
|
+
toggleResume,
|
|
6214
|
+
startQueue,
|
|
6215
|
+
outputDir
|
|
6216
|
+
]);
|
|
5831
6217
|
const currentItem = queueItems[currentIndex];
|
|
5832
6218
|
const completedCount = queueItems.filter((i) => i.status === "success" || i.status === "failed").length;
|
|
5833
6219
|
const totalCount = queueItems.length > 0 ? queueItems.length : 1;
|
|
5834
6220
|
const percent = Math.min(100, Math.floor(completedCount / totalCount * 100));
|
|
5835
6221
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", alignItems: "center", children: [
|
|
5836
|
-
phase === "input" && /* @__PURE__ */ jsx17(Panel, { title: "Batch
|
|
5837
|
-
/* @__PURE__ */
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
6222
|
+
phase === "input" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
|
|
6223
|
+
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, justifyContent: "center", children: [
|
|
6224
|
+
/* @__PURE__ */ jsx17(
|
|
6225
|
+
Text16,
|
|
6226
|
+
{
|
|
6227
|
+
bold: true,
|
|
6228
|
+
color: inputField === "text" ? theme.primary : theme.gray,
|
|
6229
|
+
inverse: focusedControl === "tabs" && inputField === "text",
|
|
6230
|
+
children: inputField === "text" ? "\u25CF Links / Handles" : "\u25CB Links / Handles"
|
|
6231
|
+
}
|
|
6232
|
+
),
|
|
6233
|
+
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: " \xB7 " }),
|
|
6234
|
+
/* @__PURE__ */ jsx17(
|
|
6235
|
+
Text16,
|
|
6236
|
+
{
|
|
6237
|
+
bold: true,
|
|
6238
|
+
color: inputField === "file" ? theme.primary : theme.gray,
|
|
6239
|
+
inverse: focusedControl === "tabs" && inputField === "file",
|
|
6240
|
+
children: inputField === "file" ? "\u25CF File (.txt)" : "\u25CB File (.txt)"
|
|
6241
|
+
}
|
|
6242
|
+
)
|
|
5843
6243
|
] }),
|
|
5844
|
-
inputField === "text" ? /* @__PURE__ */ jsx17(FramedInput, { title: "
|
|
6244
|
+
inputField === "text" ? /* @__PURE__ */ jsx17(FramedInput, { title: "Links or @handles", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
|
|
5845
6245
|
TextInput,
|
|
5846
6246
|
{
|
|
5847
6247
|
value: rawText,
|
|
5848
6248
|
onChange: setRawText,
|
|
5849
6249
|
onSubmit: startQueue,
|
|
5850
|
-
placeholder: "
|
|
5851
|
-
width: Math.max(
|
|
5852
|
-
|
|
5853
|
-
onArrowDown: () =>
|
|
6250
|
+
placeholder: "@user1, @user2, tiktok.com/@user3\u2026",
|
|
6251
|
+
width: Math.max(50, boxWidth - 10),
|
|
6252
|
+
focus: focusedControl === "input",
|
|
6253
|
+
onArrowDown: () => setFocusedControl("start"),
|
|
6254
|
+
onArrowUp: () => setFocusedControl("tabs"),
|
|
6255
|
+
onTab: () => setFocusedControl("start")
|
|
5854
6256
|
}
|
|
5855
|
-
) }) : /* @__PURE__ */ jsx17(FramedInput, { title: "
|
|
6257
|
+
) }) : /* @__PURE__ */ jsx17(FramedInput, { title: "Batch file (.txt)", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
|
|
5856
6258
|
TextInput,
|
|
5857
6259
|
{
|
|
5858
6260
|
value: filePath,
|
|
5859
6261
|
onChange: setFilePath,
|
|
5860
6262
|
onSubmit: startQueue,
|
|
5861
|
-
placeholder: "e.g.
|
|
5862
|
-
width: Math.max(
|
|
5863
|
-
|
|
5864
|
-
|
|
6263
|
+
placeholder: "e.g. creators.txt or C:\\path\\creators.txt",
|
|
6264
|
+
width: Math.max(50, boxWidth - 10),
|
|
6265
|
+
focus: focusedControl === "input",
|
|
6266
|
+
onArrowDown: () => setFocusedControl("start"),
|
|
6267
|
+
onArrowUp: () => setFocusedControl("tabs"),
|
|
6268
|
+
onTab: () => setFocusedControl("start")
|
|
5865
6269
|
}
|
|
5866
6270
|
) }),
|
|
5867
6271
|
errorMessage ? /* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: "red", children: [
|
|
5868
6272
|
"\u2717 ",
|
|
5869
6273
|
errorMessage
|
|
5870
6274
|
] }) }) : null,
|
|
5871
|
-
/* @__PURE__ */ jsx17(
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
/* @__PURE__ */
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
6275
|
+
/* @__PURE__ */ jsx17(
|
|
6276
|
+
Box14,
|
|
6277
|
+
{
|
|
6278
|
+
flexDirection: "column",
|
|
6279
|
+
marginTop: 1,
|
|
6280
|
+
borderStyle: "round",
|
|
6281
|
+
borderColor: focusedControl !== "input" && focusedControl !== "tabs" ? theme.primary : theme.gray,
|
|
6282
|
+
borderDimColor: focusedControl === "input" || focusedControl === "tabs",
|
|
6283
|
+
paddingX: 1,
|
|
6284
|
+
children: focusedControl === "custom-limit" ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
6285
|
+
/* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.primary, children: "Set post limit (e.g. 24, all):" }),
|
|
6286
|
+
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
6287
|
+
TextInput,
|
|
6288
|
+
{
|
|
6289
|
+
value: customLimitText,
|
|
6290
|
+
onChange: setCustomLimitText,
|
|
6291
|
+
onSubmit: (val) => {
|
|
6292
|
+
const parsed = parseLimit(val);
|
|
6293
|
+
setLimit(parsed);
|
|
6294
|
+
setFocusedControl("start");
|
|
6295
|
+
},
|
|
6296
|
+
width: 24
|
|
6297
|
+
}
|
|
6298
|
+
) }),
|
|
6299
|
+
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
|
|
6300
|
+
] }) : focusedControl === "custom-date" ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
6301
|
+
/* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.primary, children: "Set date or year (e.g. 2024, 7d):" }),
|
|
6302
|
+
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
6303
|
+
TextInput,
|
|
6304
|
+
{
|
|
6305
|
+
value: customDateText,
|
|
6306
|
+
onChange: setCustomDateText,
|
|
6307
|
+
onSubmit: (val) => {
|
|
6308
|
+
const trimmed = val.trim();
|
|
6309
|
+
setDateFilter(trimmed ? trimmed : "all");
|
|
6310
|
+
setFocusedControl("start");
|
|
6311
|
+
},
|
|
6312
|
+
width: 24
|
|
6313
|
+
}
|
|
6314
|
+
) }),
|
|
6315
|
+
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
|
|
6316
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
6317
|
+
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", children: [
|
|
6318
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6319
|
+
"[p] Platform:",
|
|
6320
|
+
" ",
|
|
6321
|
+
/* @__PURE__ */ jsx17(
|
|
6322
|
+
Text16,
|
|
6323
|
+
{
|
|
6324
|
+
color: theme.primary,
|
|
6325
|
+
bold: true,
|
|
6326
|
+
inverse: focusedControl === "platform",
|
|
6327
|
+
children: defaultPlatform.toUpperCase()
|
|
6328
|
+
}
|
|
6329
|
+
)
|
|
6330
|
+
] }),
|
|
6331
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6332
|
+
"[c] Media:",
|
|
6333
|
+
" ",
|
|
6334
|
+
/* @__PURE__ */ jsx17(
|
|
6335
|
+
Text16,
|
|
6336
|
+
{
|
|
6337
|
+
color: theme.primary,
|
|
6338
|
+
bold: true,
|
|
6339
|
+
inverse: focusedControl === "choice",
|
|
6340
|
+
children: choice === "all" ? "EVERYTHING" : choice.toUpperCase()
|
|
6341
|
+
}
|
|
6342
|
+
)
|
|
6343
|
+
] }),
|
|
6344
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6345
|
+
"[l] Posts:",
|
|
6346
|
+
" ",
|
|
6347
|
+
/* @__PURE__ */ jsx17(
|
|
6348
|
+
Text16,
|
|
6349
|
+
{
|
|
6350
|
+
color: theme.primary,
|
|
6351
|
+
bold: true,
|
|
6352
|
+
inverse: focusedControl === "limit",
|
|
6353
|
+
children: limit ? `${limit}` : "ALL"
|
|
6354
|
+
}
|
|
6355
|
+
)
|
|
6356
|
+
] })
|
|
6357
|
+
] }),
|
|
6358
|
+
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", marginTop: 1, children: [
|
|
6359
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6360
|
+
"[d] Date:",
|
|
6361
|
+
" ",
|
|
6362
|
+
/* @__PURE__ */ jsx17(
|
|
6363
|
+
Text16,
|
|
6364
|
+
{
|
|
6365
|
+
color: theme.primary,
|
|
6366
|
+
bold: true,
|
|
6367
|
+
inverse: focusedControl === "date",
|
|
6368
|
+
children: dateFilter.toUpperCase()
|
|
6369
|
+
}
|
|
6370
|
+
)
|
|
6371
|
+
] }),
|
|
6372
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6373
|
+
"[m] Meta:",
|
|
6374
|
+
" ",
|
|
6375
|
+
/* @__PURE__ */ jsx17(
|
|
6376
|
+
Text16,
|
|
6377
|
+
{
|
|
6378
|
+
color: theme.primary,
|
|
6379
|
+
bold: true,
|
|
6380
|
+
inverse: focusedControl === "meta",
|
|
6381
|
+
children: writeMetadata ? "ON" : "OFF"
|
|
6382
|
+
}
|
|
6383
|
+
)
|
|
6384
|
+
] }),
|
|
6385
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6386
|
+
"[r] Resume:",
|
|
6387
|
+
" ",
|
|
6388
|
+
/* @__PURE__ */ jsx17(
|
|
6389
|
+
Text16,
|
|
6390
|
+
{
|
|
6391
|
+
color: theme.primary,
|
|
6392
|
+
bold: true,
|
|
6393
|
+
inverse: focusedControl === "resume",
|
|
6394
|
+
children: resume ? "ON" : "OFF"
|
|
6395
|
+
}
|
|
6396
|
+
)
|
|
6397
|
+
] }),
|
|
6398
|
+
/* @__PURE__ */ jsx17(
|
|
6399
|
+
Text16,
|
|
6400
|
+
{
|
|
6401
|
+
color: theme.primary,
|
|
6402
|
+
bold: true,
|
|
6403
|
+
inverse: focusedControl === "start",
|
|
6404
|
+
children: "[\u21B5] Start Queue"
|
|
6405
|
+
}
|
|
6406
|
+
)
|
|
6407
|
+
] })
|
|
6408
|
+
] })
|
|
6409
|
+
}
|
|
6410
|
+
),
|
|
6411
|
+
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: focusedControl === "input" ? "Type handles or URLs \xB7 \u21B5 to start \xB7 \u2193 to customize options" : focusedControl === "tabs" ? "Space to switch mode \xB7 \u2193 to edit input" : "\u2190/\u2192/Tab choose option \xB7 Space/Enter toggle \xB7 \u21B5 start queue \xB7 \u2191 edit input" }) })
|
|
5898
6412
|
] }) }),
|
|
5899
|
-
phase === "running" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Running
|
|
6413
|
+
phase === "running" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Running", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
|
|
5900
6414
|
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
5901
6415
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.primary, bold: true, children: [
|
|
5902
6416
|
"Account ",
|
|
@@ -5907,9 +6421,9 @@ function BatchView({
|
|
|
5907
6421
|
percent,
|
|
5908
6422
|
"%)"
|
|
5909
6423
|
] }),
|
|
5910
|
-
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: isCooldown ? "\u23F3
|
|
6424
|
+
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: isCooldown ? "\u23F3 Cooldown active" : "\u25B6 Downloading" })
|
|
5911
6425
|
] }),
|
|
5912
|
-
/* @__PURE__ */ jsx17(ProgressBar, { percent, width:
|
|
6426
|
+
/* @__PURE__ */ jsx17(ProgressBar, { percent, width: 54 }),
|
|
5913
6427
|
/* @__PURE__ */ jsx17(Gap2, {}),
|
|
5914
6428
|
currentItem ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.primary, paddingX: 1, paddingY: 1, children: [
|
|
5915
6429
|
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
@@ -5931,7 +6445,7 @@ function BatchView({
|
|
|
5931
6445
|
/* @__PURE__ */ jsx17(Gap2, {}),
|
|
5932
6446
|
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[esc] Stop queue and return" })
|
|
5933
6447
|
] }) }),
|
|
5934
|
-
phase === "done" && result && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Completed", width: Math.max(
|
|
6448
|
+
phase === "done" && result && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Completed", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
|
|
5935
6449
|
/* @__PURE__ */ jsxs14(Text16, { bold: true, color: theme.primary, children: [
|
|
5936
6450
|
"\u2713 Successfully processed ",
|
|
5937
6451
|
result.total,
|
|
@@ -5951,7 +6465,7 @@ function BatchView({
|
|
|
5951
6465
|
result.totalDownloaded
|
|
5952
6466
|
] }),
|
|
5953
6467
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
5954
|
-
"\u2022 Total items skipped
|
|
6468
|
+
"\u2022 Total items skipped: ",
|
|
5955
6469
|
result.totalSkipped
|
|
5956
6470
|
] }),
|
|
5957
6471
|
/* @__PURE__ */ jsx17(Gap2, {}),
|
|
@@ -6015,7 +6529,7 @@ function frameRowSpan(row) {
|
|
|
6015
6529
|
}
|
|
6016
6530
|
|
|
6017
6531
|
// src/app.tsx
|
|
6018
|
-
import { Fragment as
|
|
6532
|
+
import { Fragment as Fragment5, jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
6019
6533
|
var TAGLINE = "grab any profile. paste. download. done.";
|
|
6020
6534
|
var DOWNLOAD_BUTTON = "download";
|
|
6021
6535
|
var Gap = ({ lines = 1 }) => /* @__PURE__ */ jsx18(Box15, { flexDirection: "column", flexShrink: 0, children: Array.from({ length: lines }, (_, i) => /* @__PURE__ */ jsx18(Text17, { children: " " }, i)) });
|
|
@@ -6134,6 +6648,7 @@ function InnerApp({
|
|
|
6134
6648
|
const [urlInput, setUrlInput] = useState9(initialInput ?? "");
|
|
6135
6649
|
const [clipboardUrl, setClipboardUrl] = useState9(void 0);
|
|
6136
6650
|
const [settingsFocus, setSettingsFocus] = useState9("cookies");
|
|
6651
|
+
const [batchClickTargets, setBatchClickTargets] = useState9([]);
|
|
6137
6652
|
const columns = stdout?.columns && stdout.columns > 0 ? stdout.columns : 80;
|
|
6138
6653
|
const boxWidth = Math.max(14, Math.min(64, columns - 6));
|
|
6139
6654
|
const contentWidth = Math.max(10, Math.min(columns - 4, 78));
|
|
@@ -6149,7 +6664,7 @@ function InnerApp({
|
|
|
6149
6664
|
}
|
|
6150
6665
|
return { name: "input" };
|
|
6151
6666
|
});
|
|
6152
|
-
|
|
6667
|
+
useEffect8(() => {
|
|
6153
6668
|
try {
|
|
6154
6669
|
const clip = readClipboard();
|
|
6155
6670
|
if (clip && (clip.startsWith("http://") || clip.startsWith("https://") || clip.startsWith("@"))) {
|
|
@@ -6162,7 +6677,7 @@ function InnerApp({
|
|
|
6162
6677
|
const clipboardAccepted = Boolean(clipboardUrl) && urlInput === clipboardUrl;
|
|
6163
6678
|
const abortControllerRef = useRef5(null);
|
|
6164
6679
|
const probingTimeoutRef = useRef5(null);
|
|
6165
|
-
|
|
6680
|
+
useEffect8(() => {
|
|
6166
6681
|
return () => {
|
|
6167
6682
|
abortControllerRef.current?.abort();
|
|
6168
6683
|
if (probingTimeoutRef.current) {
|
|
@@ -6187,6 +6702,7 @@ function InnerApp({
|
|
|
6187
6702
|
const targetChoice = typeof choiceOrOptions === "string" ? choiceOrOptions : choiceOrOptions.choice;
|
|
6188
6703
|
const targetLimit = typeof choiceOrOptions === "string" ? effectiveLimit : choiceOrOptions.limit ?? effectiveLimit;
|
|
6189
6704
|
const targetSince = typeof choiceOrOptions === "string" ? since : choiceOrOptions.since ?? since;
|
|
6705
|
+
const targetUntil = typeof choiceOrOptions === "string" ? until : choiceOrOptions.until ?? until;
|
|
6190
6706
|
const targetResume = typeof choiceOrOptions === "string" ? resume : choiceOrOptions.resume ?? resume;
|
|
6191
6707
|
const targetWriteMetadata = typeof choiceOrOptions === "string" ? effectiveWriteMetadata : choiceOrOptions.writeMetadata ?? effectiveWriteMetadata;
|
|
6192
6708
|
setPhase({ name: "downloading", profile, choice: targetChoice });
|
|
@@ -6197,7 +6713,7 @@ function InnerApp({
|
|
|
6197
6713
|
choice: targetChoice,
|
|
6198
6714
|
outputDir: targetDir,
|
|
6199
6715
|
since: targetSince,
|
|
6200
|
-
until,
|
|
6716
|
+
until: targetUntil,
|
|
6201
6717
|
limit: targetLimit,
|
|
6202
6718
|
resume: targetResume,
|
|
6203
6719
|
writeMetadata: targetWriteMetadata,
|
|
@@ -6302,10 +6818,13 @@ function InnerApp({
|
|
|
6302
6818
|
return;
|
|
6303
6819
|
}
|
|
6304
6820
|
if (key.escape) {
|
|
6305
|
-
if (phase.name === "settings" || phase.name === "watcher"
|
|
6821
|
+
if (phase.name === "settings" || phase.name === "watcher") {
|
|
6306
6822
|
setPhase({ name: "input" });
|
|
6307
6823
|
return;
|
|
6308
6824
|
}
|
|
6825
|
+
if (phase.name === "batch") {
|
|
6826
|
+
return;
|
|
6827
|
+
}
|
|
6309
6828
|
if (phase.name === "platform") {
|
|
6310
6829
|
setPhase({ name: "input" });
|
|
6311
6830
|
return;
|
|
@@ -6397,6 +6916,9 @@ function InnerApp({
|
|
|
6397
6916
|
targets.push({ match: "Cookies Folder", padX: 2, padY: 1, action: () => setSettingsFocus("cookies") });
|
|
6398
6917
|
targets.push({ match: "Download Directory", padX: 2, padY: 1, action: () => setSettingsFocus("download") });
|
|
6399
6918
|
}
|
|
6919
|
+
if (phase.name === "batch") {
|
|
6920
|
+
targets.push(...batchClickTargets);
|
|
6921
|
+
}
|
|
6400
6922
|
for (const [key, label] of hints) {
|
|
6401
6923
|
const action = hintAction(key);
|
|
6402
6924
|
if (action) targets.push({ match: `${key} ${label}`, action });
|
|
@@ -6416,7 +6938,8 @@ function InnerApp({
|
|
|
6416
6938
|
handleInputSubmit,
|
|
6417
6939
|
handlePlatformSelect,
|
|
6418
6940
|
handleModeSelect,
|
|
6419
|
-
resetToInput
|
|
6941
|
+
resetToInput,
|
|
6942
|
+
batchClickTargets
|
|
6420
6943
|
]);
|
|
6421
6944
|
useMouseClick(
|
|
6422
6945
|
(x, y) => {
|
|
@@ -6483,6 +7006,7 @@ function InnerApp({
|
|
|
6483
7006
|
outputDir,
|
|
6484
7007
|
initialLimit: effectiveLimit,
|
|
6485
7008
|
initialSince: since,
|
|
7009
|
+
initialUntil: until,
|
|
6486
7010
|
initialWriteMetadata: effectiveWriteMetadata,
|
|
6487
7011
|
initialResume: resume,
|
|
6488
7012
|
onSelect: (choiceOrOptions) => handleModeSelect(choiceOrOptions, phase.profile),
|
|
@@ -6556,10 +7080,11 @@ function InnerApp({
|
|
|
6556
7080
|
gapComponent: Gap,
|
|
6557
7081
|
defaultChoice: initialChoice,
|
|
6558
7082
|
defaultLimit: effectiveLimit,
|
|
6559
|
-
defaultWriteMetadata: effectiveWriteMetadata
|
|
7083
|
+
defaultWriteMetadata: effectiveWriteMetadata,
|
|
7084
|
+
onRegisterClickTargets: setBatchClickTargets
|
|
6560
7085
|
}
|
|
6561
7086
|
),
|
|
6562
|
-
hints.length > 0 ? /* @__PURE__ */ jsxs15(
|
|
7087
|
+
hints.length > 0 ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
6563
7088
|
/* @__PURE__ */ jsx18(Gap, { lines: 2 }),
|
|
6564
7089
|
/* @__PURE__ */ jsx18(
|
|
6565
7090
|
Shortcuts,
|
|
@@ -6909,6 +7434,7 @@ async function main() {
|
|
|
6909
7434
|
let themeMode = "auto";
|
|
6910
7435
|
let isWatchMode = false;
|
|
6911
7436
|
let batchFile;
|
|
7437
|
+
let cliPlatform;
|
|
6912
7438
|
let since;
|
|
6913
7439
|
let until;
|
|
6914
7440
|
let limit;
|
|
@@ -6958,6 +7484,16 @@ async function main() {
|
|
|
6958
7484
|
batchFile = args[++i];
|
|
6959
7485
|
} else if (arg.startsWith("--batch=")) {
|
|
6960
7486
|
batchFile = arg.slice("--batch=".length);
|
|
7487
|
+
} else if (arg === "-p" || arg === "--platform") {
|
|
7488
|
+
const val = args[++i]?.toLowerCase();
|
|
7489
|
+
if (val === "instagram" || val === "tiktok" || val === "facebook" || val === "x") {
|
|
7490
|
+
cliPlatform = val;
|
|
7491
|
+
}
|
|
7492
|
+
} else if (arg.startsWith("--platform=")) {
|
|
7493
|
+
const val = arg.slice("--platform=".length).toLowerCase();
|
|
7494
|
+
if (val === "instagram" || val === "tiktok" || val === "facebook" || val === "x") {
|
|
7495
|
+
cliPlatform = val;
|
|
7496
|
+
}
|
|
6961
7497
|
} else if (!arg.startsWith("-") && !initialInput) {
|
|
6962
7498
|
initialInput = arg;
|
|
6963
7499
|
}
|
|
@@ -7021,6 +7557,7 @@ async function main() {
|
|
|
7021
7557
|
const result = await runBatchQueue({
|
|
7022
7558
|
filePath: batchFile,
|
|
7023
7559
|
choice,
|
|
7560
|
+
defaultPlatform: cliPlatform || "instagram",
|
|
7024
7561
|
outputDir,
|
|
7025
7562
|
since,
|
|
7026
7563
|
until,
|