open-nami 1.2.4 → 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 +413 -81
- 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
|
|
|
@@ -5629,7 +5629,7 @@ function WatcherView({
|
|
|
5629
5629
|
}
|
|
5630
5630
|
|
|
5631
5631
|
// src/components/views/batch-view.tsx
|
|
5632
|
-
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";
|
|
5633
5633
|
import { Box as Box14, Text as Text16, useInput as useInput5 } from "ink";
|
|
5634
5634
|
import Spinner3 from "ink-spinner";
|
|
5635
5635
|
import fs13 from "fs";
|
|
@@ -5667,13 +5667,19 @@ async function runBatchQueue(options) {
|
|
|
5667
5667
|
const choice = options.choice || "all";
|
|
5668
5668
|
const minDelay = options.minDelayMs ?? 2e3;
|
|
5669
5669
|
const maxDelay = options.maxDelayMs ?? 5e3;
|
|
5670
|
-
const items = rawEntries.map((raw) =>
|
|
5671
|
-
raw
|
|
5672
|
-
profile
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
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
|
+
});
|
|
5677
5683
|
let totalDownloaded = 0;
|
|
5678
5684
|
let totalSkipped = 0;
|
|
5679
5685
|
let succeeded = 0;
|
|
@@ -5693,10 +5699,15 @@ async function runBatchQueue(options) {
|
|
|
5693
5699
|
}
|
|
5694
5700
|
options.onAccountStart?.(item, i, items.length);
|
|
5695
5701
|
try {
|
|
5702
|
+
const targetDir = resolveDefaultDownloadDir(
|
|
5703
|
+
item.profile.platform,
|
|
5704
|
+
item.profile.username,
|
|
5705
|
+
options.outputDir
|
|
5706
|
+
);
|
|
5696
5707
|
const res = await dispatchDownload({
|
|
5697
5708
|
profile: item.profile,
|
|
5698
5709
|
choice,
|
|
5699
|
-
outputDir:
|
|
5710
|
+
outputDir: targetDir,
|
|
5700
5711
|
since: options.since,
|
|
5701
5712
|
until: options.until,
|
|
5702
5713
|
limit: options.limit,
|
|
@@ -5744,8 +5755,11 @@ async function runBatchQueue(options) {
|
|
|
5744
5755
|
|
|
5745
5756
|
// src/components/views/batch-view.tsx
|
|
5746
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"];
|
|
5747
5760
|
var DATE_PRESETS2 = ["all", "24h", "7d", "30d", "2024", "2023", "2022", "2021", "custom"];
|
|
5748
5761
|
var LIMIT_PRESETS2 = [void 0, 10, 24, 50, 100, "custom"];
|
|
5762
|
+
var OPTION_CONTROLS = ["platform", "choice", "limit", "date", "meta", "resume", "start"];
|
|
5749
5763
|
function BatchView({
|
|
5750
5764
|
onBack,
|
|
5751
5765
|
outputDir,
|
|
@@ -5754,16 +5768,18 @@ function BatchView({
|
|
|
5754
5768
|
gapComponent: Gap2,
|
|
5755
5769
|
defaultChoice = "all",
|
|
5756
5770
|
defaultLimit,
|
|
5757
|
-
defaultWriteMetadata = false
|
|
5771
|
+
defaultWriteMetadata = false,
|
|
5772
|
+
onRegisterClickTargets
|
|
5758
5773
|
}) {
|
|
5759
5774
|
const [phase, setPhase] = useState8("input");
|
|
5760
5775
|
const [inputField, setInputField] = useState8("text");
|
|
5761
5776
|
const [rawText, setRawText] = useState8("");
|
|
5762
5777
|
const [filePath, setFilePath] = useState8("");
|
|
5763
5778
|
const [errorMessage, setErrorMessage] = useState8(null);
|
|
5764
|
-
const [
|
|
5779
|
+
const [focusedControl, setFocusedControl] = useState8("input");
|
|
5765
5780
|
const [customLimitText, setCustomLimitText] = useState8("");
|
|
5766
5781
|
const [customDateText, setCustomDateText] = useState8("");
|
|
5782
|
+
const [defaultPlatform, setDefaultPlatform] = useState8("instagram");
|
|
5767
5783
|
const [choice, setChoice] = useState8(defaultChoice);
|
|
5768
5784
|
const [limit, setLimit] = useState8(defaultLimit);
|
|
5769
5785
|
const [dateFilter, setDateFilter] = useState8("all");
|
|
@@ -5775,11 +5791,16 @@ function BatchView({
|
|
|
5775
5791
|
const [isCooldown, setIsCooldown] = useState8(false);
|
|
5776
5792
|
const [result, setResult] = useState8(null);
|
|
5777
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
|
+
}, []);
|
|
5778
5800
|
const cycleChoice = useCallback4(() => {
|
|
5779
5801
|
setChoice((prev) => {
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
return "all";
|
|
5802
|
+
const idx = CHOICES.indexOf(prev);
|
|
5803
|
+
return CHOICES[(idx + 1) % CHOICES.length];
|
|
5783
5804
|
});
|
|
5784
5805
|
}, []);
|
|
5785
5806
|
const cycleLimit = useCallback4(() => {
|
|
@@ -5788,7 +5809,7 @@ function BatchView({
|
|
|
5788
5809
|
const nextVal = LIMIT_PRESETS2[nextIdx];
|
|
5789
5810
|
if (nextVal === "custom") {
|
|
5790
5811
|
setCustomLimitText(limit ? String(limit) : "24");
|
|
5791
|
-
|
|
5812
|
+
setFocusedControl("custom-limit");
|
|
5792
5813
|
} else {
|
|
5793
5814
|
setLimit(nextVal);
|
|
5794
5815
|
}
|
|
@@ -5798,8 +5819,8 @@ function BatchView({
|
|
|
5798
5819
|
const nextIdx = (curIdx + 1) % DATE_PRESETS2.length;
|
|
5799
5820
|
const nextVal = DATE_PRESETS2[nextIdx];
|
|
5800
5821
|
if (nextVal === "custom") {
|
|
5801
|
-
setCustomDateText(dateFilter !== "all" ? dateFilter : "
|
|
5802
|
-
|
|
5822
|
+
setCustomDateText(dateFilter !== "all" ? dateFilter : "2024");
|
|
5823
|
+
setFocusedControl("custom-date");
|
|
5803
5824
|
} else {
|
|
5804
5825
|
setDateFilter(nextVal);
|
|
5805
5826
|
}
|
|
@@ -5824,7 +5845,11 @@ function BatchView({
|
|
|
5824
5845
|
return;
|
|
5825
5846
|
}
|
|
5826
5847
|
} else {
|
|
5827
|
-
lines =
|
|
5848
|
+
lines = Array.from(
|
|
5849
|
+
new Set(
|
|
5850
|
+
rawText.split(/[\r\n,;\s]+/).map((s) => s.trim()).filter(Boolean)
|
|
5851
|
+
)
|
|
5852
|
+
);
|
|
5828
5853
|
if (lines.length === 0) {
|
|
5829
5854
|
setErrorMessage("Please enter at least one profile URL or username");
|
|
5830
5855
|
return;
|
|
@@ -5839,6 +5864,7 @@ function BatchView({
|
|
|
5839
5864
|
filePath: inputField === "file" ? filePath.trim() : void 0,
|
|
5840
5865
|
lines: inputField === "text" ? lines : void 0,
|
|
5841
5866
|
choice,
|
|
5867
|
+
defaultPlatform,
|
|
5842
5868
|
outputDir,
|
|
5843
5869
|
since: dateRange.since,
|
|
5844
5870
|
until: dateRange.until,
|
|
@@ -5849,7 +5875,7 @@ function BatchView({
|
|
|
5849
5875
|
onAccountStart: (item, idx) => {
|
|
5850
5876
|
setIsCooldown(false);
|
|
5851
5877
|
setCurrentIndex(idx);
|
|
5852
|
-
setCurrentProgressText(`Probing @${item.profile.username || item.raw}\u2026`);
|
|
5878
|
+
setCurrentProgressText(`Probing @${item.profile.username || item.raw} on ${item.profile.platform}\u2026`);
|
|
5853
5879
|
setQueueItems((prev) => {
|
|
5854
5880
|
const next = [...prev];
|
|
5855
5881
|
if (next[idx]) next[idx] = { ...item };
|
|
@@ -5891,15 +5917,18 @@ function BatchView({
|
|
|
5891
5917
|
setErrorMessage(msg);
|
|
5892
5918
|
setPhase("input");
|
|
5893
5919
|
}
|
|
5894
|
-
}, [inputField, filePath, rawText, choice, outputDir, dateFilter, limit, resume, writeMetadata]);
|
|
5920
|
+
}, [inputField, filePath, rawText, choice, defaultPlatform, outputDir, dateFilter, limit, resume, writeMetadata]);
|
|
5895
5921
|
useInput5((input, key) => {
|
|
5922
|
+
if (key.ctrl && (input === "c" || input === "C")) {
|
|
5923
|
+
return;
|
|
5924
|
+
}
|
|
5896
5925
|
if (key.escape) {
|
|
5897
|
-
if (
|
|
5898
|
-
|
|
5926
|
+
if (focusedControl === "custom-limit" || focusedControl === "custom-date") {
|
|
5927
|
+
setFocusedControl("start");
|
|
5899
5928
|
return;
|
|
5900
5929
|
}
|
|
5901
|
-
if (
|
|
5902
|
-
|
|
5930
|
+
if (focusedControl !== "input" && phase === "input") {
|
|
5931
|
+
setFocusedControl("input");
|
|
5903
5932
|
return;
|
|
5904
5933
|
}
|
|
5905
5934
|
if (phase === "running") {
|
|
@@ -5922,46 +5951,78 @@ function BatchView({
|
|
|
5922
5951
|
}
|
|
5923
5952
|
return;
|
|
5924
5953
|
}
|
|
5954
|
+
if (phase === "running") {
|
|
5955
|
+
return;
|
|
5956
|
+
}
|
|
5925
5957
|
if (phase === "input") {
|
|
5926
|
-
if (
|
|
5958
|
+
if (focusedControl === "custom-limit" || focusedControl === "custom-date") {
|
|
5927
5959
|
return;
|
|
5928
5960
|
}
|
|
5929
|
-
if (
|
|
5930
|
-
if (
|
|
5931
|
-
|
|
5932
|
-
setFocusSection("custom-limit");
|
|
5961
|
+
if (focusedControl === "input") {
|
|
5962
|
+
if (key.downArrow) {
|
|
5963
|
+
setFocusedControl("platform");
|
|
5933
5964
|
return;
|
|
5934
5965
|
}
|
|
5935
|
-
if (
|
|
5936
|
-
|
|
5937
|
-
setFocusSection("custom-date");
|
|
5966
|
+
if (key.upArrow) {
|
|
5967
|
+
setFocusedControl("tabs");
|
|
5938
5968
|
return;
|
|
5939
5969
|
}
|
|
5940
|
-
|
|
5941
|
-
|
|
5970
|
+
return;
|
|
5971
|
+
}
|
|
5972
|
+
if (focusedControl === "tabs") {
|
|
5973
|
+
if (key.leftArrow || key.rightArrow || input === " " || key.return) {
|
|
5974
|
+
setInputField((prev) => prev === "text" ? "file" : "text");
|
|
5942
5975
|
return;
|
|
5943
5976
|
}
|
|
5944
|
-
if (
|
|
5945
|
-
|
|
5977
|
+
if (key.downArrow || key.tab) {
|
|
5978
|
+
setFocusedControl("input");
|
|
5946
5979
|
return;
|
|
5947
5980
|
}
|
|
5948
|
-
|
|
5949
|
-
|
|
5981
|
+
return;
|
|
5982
|
+
}
|
|
5983
|
+
if (OPTION_CONTROLS.includes(focusedControl)) {
|
|
5984
|
+
if (key.upArrow) {
|
|
5985
|
+
setFocusedControl("input");
|
|
5950
5986
|
return;
|
|
5951
5987
|
}
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
setFocusSection("options");
|
|
5988
|
+
if (key.rightArrow || key.tab && !key.shift) {
|
|
5989
|
+
const idx = OPTION_CONTROLS.indexOf(focusedControl);
|
|
5990
|
+
setFocusedControl(OPTION_CONTROLS[(idx + 1) % OPTION_CONTROLS.length]);
|
|
5956
5991
|
return;
|
|
5957
5992
|
}
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
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]);
|
|
5961
5996
|
return;
|
|
5962
5997
|
}
|
|
5963
|
-
if (key.return) {
|
|
5964
|
-
|
|
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();
|
|
5965
6026
|
return;
|
|
5966
6027
|
}
|
|
5967
6028
|
if (input === "c" || input === "C") {
|
|
@@ -5987,6 +6048,172 @@ function BatchView({
|
|
|
5987
6048
|
}
|
|
5988
6049
|
}
|
|
5989
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
|
+
]);
|
|
5990
6217
|
const currentItem = queueItems[currentIndex];
|
|
5991
6218
|
const completedCount = queueItems.filter((i) => i.status === "success" || i.status === "failed").length;
|
|
5992
6219
|
const totalCount = queueItems.length > 0 ? queueItems.length : 1;
|
|
@@ -5994,9 +6221,25 @@ function BatchView({
|
|
|
5994
6221
|
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", alignItems: "center", children: [
|
|
5995
6222
|
phase === "input" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
|
|
5996
6223
|
/* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, justifyContent: "center", children: [
|
|
5997
|
-
/* @__PURE__ */ jsx17(
|
|
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
|
+
),
|
|
5998
6233
|
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: " \xB7 " }),
|
|
5999
|
-
/* @__PURE__ */ jsx17(
|
|
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
|
+
)
|
|
6000
6243
|
] }),
|
|
6001
6244
|
inputField === "text" ? /* @__PURE__ */ jsx17(FramedInput, { title: "Links or @handles", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
|
|
6002
6245
|
TextInput,
|
|
@@ -6006,9 +6249,10 @@ function BatchView({
|
|
|
6006
6249
|
onSubmit: startQueue,
|
|
6007
6250
|
placeholder: "@user1, @user2, tiktok.com/@user3\u2026",
|
|
6008
6251
|
width: Math.max(50, boxWidth - 10),
|
|
6009
|
-
focus:
|
|
6010
|
-
|
|
6011
|
-
|
|
6252
|
+
focus: focusedControl === "input",
|
|
6253
|
+
onArrowDown: () => setFocusedControl("start"),
|
|
6254
|
+
onArrowUp: () => setFocusedControl("tabs"),
|
|
6255
|
+
onTab: () => setFocusedControl("start")
|
|
6012
6256
|
}
|
|
6013
6257
|
) }) : /* @__PURE__ */ jsx17(FramedInput, { title: "Batch file (.txt)", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
|
|
6014
6258
|
TextInput,
|
|
@@ -6018,9 +6262,10 @@ function BatchView({
|
|
|
6018
6262
|
onSubmit: startQueue,
|
|
6019
6263
|
placeholder: "e.g. creators.txt or C:\\path\\creators.txt",
|
|
6020
6264
|
width: Math.max(50, boxWidth - 10),
|
|
6021
|
-
focus:
|
|
6022
|
-
|
|
6023
|
-
|
|
6265
|
+
focus: focusedControl === "input",
|
|
6266
|
+
onArrowDown: () => setFocusedControl("start"),
|
|
6267
|
+
onArrowUp: () => setFocusedControl("tabs"),
|
|
6268
|
+
onTab: () => setFocusedControl("start")
|
|
6024
6269
|
}
|
|
6025
6270
|
) }),
|
|
6026
6271
|
errorMessage ? /* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: "red", children: [
|
|
@@ -6033,10 +6278,10 @@ function BatchView({
|
|
|
6033
6278
|
flexDirection: "column",
|
|
6034
6279
|
marginTop: 1,
|
|
6035
6280
|
borderStyle: "round",
|
|
6036
|
-
borderColor:
|
|
6037
|
-
borderDimColor:
|
|
6281
|
+
borderColor: focusedControl !== "input" && focusedControl !== "tabs" ? theme.primary : theme.gray,
|
|
6282
|
+
borderDimColor: focusedControl === "input" || focusedControl === "tabs",
|
|
6038
6283
|
paddingX: 1,
|
|
6039
|
-
children:
|
|
6284
|
+
children: focusedControl === "custom-limit" ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
6040
6285
|
/* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.primary, children: "Set post limit (e.g. 24, all):" }),
|
|
6041
6286
|
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
6042
6287
|
TextInput,
|
|
@@ -6046,14 +6291,14 @@ function BatchView({
|
|
|
6046
6291
|
onSubmit: (val) => {
|
|
6047
6292
|
const parsed = parseLimit(val);
|
|
6048
6293
|
setLimit(parsed);
|
|
6049
|
-
|
|
6294
|
+
setFocusedControl("start");
|
|
6050
6295
|
},
|
|
6051
6296
|
width: 24
|
|
6052
6297
|
}
|
|
6053
6298
|
) }),
|
|
6054
6299
|
/* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
|
|
6055
|
-
] }) :
|
|
6056
|
-
/* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.primary, children: "Set date or year (e.g.
|
|
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):" }),
|
|
6057
6302
|
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
6058
6303
|
TextInput,
|
|
6059
6304
|
{
|
|
@@ -6062,7 +6307,7 @@ function BatchView({
|
|
|
6062
6307
|
onSubmit: (val) => {
|
|
6063
6308
|
const trimmed = val.trim();
|
|
6064
6309
|
setDateFilter(trimmed ? trimmed : "all");
|
|
6065
|
-
|
|
6310
|
+
setFocusedControl("start");
|
|
6066
6311
|
},
|
|
6067
6312
|
width: 24
|
|
6068
6313
|
}
|
|
@@ -6071,33 +6316,99 @@ function BatchView({
|
|
|
6071
6316
|
] }) : /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
6072
6317
|
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", children: [
|
|
6073
6318
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6074
|
-
"[
|
|
6075
|
-
|
|
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
|
+
)
|
|
6076
6330
|
] }),
|
|
6077
6331
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6078
|
-
"[
|
|
6079
|
-
|
|
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
|
+
)
|
|
6080
6343
|
] }),
|
|
6081
6344
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6082
|
-
"[
|
|
6083
|
-
|
|
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
|
+
)
|
|
6084
6356
|
] })
|
|
6085
6357
|
] }),
|
|
6086
6358
|
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", marginTop: 1, children: [
|
|
6087
6359
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6088
|
-
"[
|
|
6089
|
-
|
|
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
|
+
)
|
|
6090
6371
|
] }),
|
|
6091
6372
|
/* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
|
|
6092
|
-
"[
|
|
6093
|
-
|
|
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
|
+
)
|
|
6094
6397
|
] }),
|
|
6095
|
-
/* @__PURE__ */ jsx17(
|
|
6398
|
+
/* @__PURE__ */ jsx17(
|
|
6399
|
+
Text16,
|
|
6400
|
+
{
|
|
6401
|
+
color: theme.primary,
|
|
6402
|
+
bold: true,
|
|
6403
|
+
inverse: focusedControl === "start",
|
|
6404
|
+
children: "[\u21B5] Start Queue"
|
|
6405
|
+
}
|
|
6406
|
+
)
|
|
6096
6407
|
] })
|
|
6097
6408
|
] })
|
|
6098
6409
|
}
|
|
6099
6410
|
),
|
|
6100
|
-
/* @__PURE__ */ jsx17(Box14, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children:
|
|
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" }) })
|
|
6101
6412
|
] }) }),
|
|
6102
6413
|
phase === "running" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Running", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
|
|
6103
6414
|
/* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
@@ -6337,6 +6648,7 @@ function InnerApp({
|
|
|
6337
6648
|
const [urlInput, setUrlInput] = useState9(initialInput ?? "");
|
|
6338
6649
|
const [clipboardUrl, setClipboardUrl] = useState9(void 0);
|
|
6339
6650
|
const [settingsFocus, setSettingsFocus] = useState9("cookies");
|
|
6651
|
+
const [batchClickTargets, setBatchClickTargets] = useState9([]);
|
|
6340
6652
|
const columns = stdout?.columns && stdout.columns > 0 ? stdout.columns : 80;
|
|
6341
6653
|
const boxWidth = Math.max(14, Math.min(64, columns - 6));
|
|
6342
6654
|
const contentWidth = Math.max(10, Math.min(columns - 4, 78));
|
|
@@ -6352,7 +6664,7 @@ function InnerApp({
|
|
|
6352
6664
|
}
|
|
6353
6665
|
return { name: "input" };
|
|
6354
6666
|
});
|
|
6355
|
-
|
|
6667
|
+
useEffect8(() => {
|
|
6356
6668
|
try {
|
|
6357
6669
|
const clip = readClipboard();
|
|
6358
6670
|
if (clip && (clip.startsWith("http://") || clip.startsWith("https://") || clip.startsWith("@"))) {
|
|
@@ -6365,7 +6677,7 @@ function InnerApp({
|
|
|
6365
6677
|
const clipboardAccepted = Boolean(clipboardUrl) && urlInput === clipboardUrl;
|
|
6366
6678
|
const abortControllerRef = useRef5(null);
|
|
6367
6679
|
const probingTimeoutRef = useRef5(null);
|
|
6368
|
-
|
|
6680
|
+
useEffect8(() => {
|
|
6369
6681
|
return () => {
|
|
6370
6682
|
abortControllerRef.current?.abort();
|
|
6371
6683
|
if (probingTimeoutRef.current) {
|
|
@@ -6506,10 +6818,13 @@ function InnerApp({
|
|
|
6506
6818
|
return;
|
|
6507
6819
|
}
|
|
6508
6820
|
if (key.escape) {
|
|
6509
|
-
if (phase.name === "settings" || phase.name === "watcher"
|
|
6821
|
+
if (phase.name === "settings" || phase.name === "watcher") {
|
|
6510
6822
|
setPhase({ name: "input" });
|
|
6511
6823
|
return;
|
|
6512
6824
|
}
|
|
6825
|
+
if (phase.name === "batch") {
|
|
6826
|
+
return;
|
|
6827
|
+
}
|
|
6513
6828
|
if (phase.name === "platform") {
|
|
6514
6829
|
setPhase({ name: "input" });
|
|
6515
6830
|
return;
|
|
@@ -6601,6 +6916,9 @@ function InnerApp({
|
|
|
6601
6916
|
targets.push({ match: "Cookies Folder", padX: 2, padY: 1, action: () => setSettingsFocus("cookies") });
|
|
6602
6917
|
targets.push({ match: "Download Directory", padX: 2, padY: 1, action: () => setSettingsFocus("download") });
|
|
6603
6918
|
}
|
|
6919
|
+
if (phase.name === "batch") {
|
|
6920
|
+
targets.push(...batchClickTargets);
|
|
6921
|
+
}
|
|
6604
6922
|
for (const [key, label] of hints) {
|
|
6605
6923
|
const action = hintAction(key);
|
|
6606
6924
|
if (action) targets.push({ match: `${key} ${label}`, action });
|
|
@@ -6620,7 +6938,8 @@ function InnerApp({
|
|
|
6620
6938
|
handleInputSubmit,
|
|
6621
6939
|
handlePlatformSelect,
|
|
6622
6940
|
handleModeSelect,
|
|
6623
|
-
resetToInput
|
|
6941
|
+
resetToInput,
|
|
6942
|
+
batchClickTargets
|
|
6624
6943
|
]);
|
|
6625
6944
|
useMouseClick(
|
|
6626
6945
|
(x, y) => {
|
|
@@ -6761,7 +7080,8 @@ function InnerApp({
|
|
|
6761
7080
|
gapComponent: Gap,
|
|
6762
7081
|
defaultChoice: initialChoice,
|
|
6763
7082
|
defaultLimit: effectiveLimit,
|
|
6764
|
-
defaultWriteMetadata: effectiveWriteMetadata
|
|
7083
|
+
defaultWriteMetadata: effectiveWriteMetadata,
|
|
7084
|
+
onRegisterClickTargets: setBatchClickTargets
|
|
6765
7085
|
}
|
|
6766
7086
|
),
|
|
6767
7087
|
hints.length > 0 ? /* @__PURE__ */ jsxs15(Fragment5, { children: [
|
|
@@ -7114,6 +7434,7 @@ async function main() {
|
|
|
7114
7434
|
let themeMode = "auto";
|
|
7115
7435
|
let isWatchMode = false;
|
|
7116
7436
|
let batchFile;
|
|
7437
|
+
let cliPlatform;
|
|
7117
7438
|
let since;
|
|
7118
7439
|
let until;
|
|
7119
7440
|
let limit;
|
|
@@ -7163,6 +7484,16 @@ async function main() {
|
|
|
7163
7484
|
batchFile = args[++i];
|
|
7164
7485
|
} else if (arg.startsWith("--batch=")) {
|
|
7165
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
|
+
}
|
|
7166
7497
|
} else if (!arg.startsWith("-") && !initialInput) {
|
|
7167
7498
|
initialInput = arg;
|
|
7168
7499
|
}
|
|
@@ -7226,6 +7557,7 @@ async function main() {
|
|
|
7226
7557
|
const result = await runBatchQueue({
|
|
7227
7558
|
filePath: batchFile,
|
|
7228
7559
|
choice,
|
|
7560
|
+
defaultPlatform: cliPlatform || "instagram",
|
|
7229
7561
|
outputDir,
|
|
7230
7562
|
since,
|
|
7231
7563
|
until,
|