open-nami 1.2.5 → 1.2.7

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.
Files changed (2) hide show
  1. package/dist/cli.js +400 -165
  2. 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.5",
12
+ version: "1.2.7",
13
13
  description: "Open Nami: terminal-first bulk social media profile downloader for Instagram, TikTok, Facebook & X.",
14
14
  type: "module",
15
15
  bin: {
@@ -5352,9 +5352,9 @@ function startClipboardWatcher(options = {}) {
5352
5352
  try {
5353
5353
  const res = await dispatch({
5354
5354
  profile: parsed,
5355
- choice,
5356
- outputDir: options.outputDir,
5357
- writeMetadata: options.writeMetadata,
5355
+ choice: options.getChoice ? options.getChoice() : options.choice || "all",
5356
+ outputDir: resolveDefaultDownloadDir(parsed.platform, parsed.username, options.outputDir),
5357
+ writeMetadata: options.getWriteMetadata ? options.getWriteMetadata() : options.writeMetadata ?? false,
5358
5358
  signal: options.signal,
5359
5359
  onProgress: (p) => {
5360
5360
  if (p.statusText) {
@@ -5444,16 +5444,19 @@ function revealInFileManager(targetPath) {
5444
5444
 
5445
5445
  // src/components/views/watcher-view.tsx
5446
5446
  import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
5447
+ var CHOICES = ["all", "photos", "videos", "stories", "highlights"];
5447
5448
  function WatcherView({
5448
5449
  onBack,
5449
5450
  outputDir,
5450
5451
  theme,
5451
5452
  gapComponent: Gap2,
5452
5453
  defaultChoice = "all",
5453
- defaultWriteMetadata = false
5454
+ defaultWriteMetadata = false,
5455
+ onRegisterClickTargets
5454
5456
  }) {
5455
5457
  const [mediaChoice, setMediaChoice] = useState7(defaultChoice);
5456
5458
  const [writeMetadata, setWriteMetadata] = useState7(defaultWriteMetadata);
5459
+ const [focusedIndex, setFocusedIndex] = useState7(0);
5457
5460
  const [history, setHistory] = useState7([]);
5458
5461
  const [activeJob, setActiveJob] = useState7(null);
5459
5462
  const [stats, setStats] = useState7({ detected: 0, downloaded: 0, skipped: 0 });
@@ -5471,8 +5474,10 @@ function WatcherView({
5471
5474
  useEffect6(() => {
5472
5475
  const watcher = startClipboardWatcher({
5473
5476
  choice: mediaChoiceRef.current,
5477
+ getChoice: () => mediaChoiceRef.current,
5474
5478
  outputDir,
5475
5479
  writeMetadata: writeMetadataRef.current,
5480
+ getWriteMetadata: () => writeMetadataRef.current,
5476
5481
  onDetected: (profile) => {
5477
5482
  setStats((prev) => ({ ...prev, detected: prev.detected + 1 }));
5478
5483
  const newItem = {
@@ -5528,9 +5533,9 @@ function WatcherView({
5528
5533
  }, [outputDir]);
5529
5534
  const cycleChoice = useCallback3(() => {
5530
5535
  setMediaChoice((prev) => {
5531
- if (prev === "all") return "photos";
5532
- if (prev === "photos") return "videos";
5533
- return "all";
5536
+ const idx = CHOICES.indexOf(prev);
5537
+ const nextChoice = CHOICES[(idx + 1) % CHOICES.length] || "all";
5538
+ return nextChoice;
5534
5539
  });
5535
5540
  }, []);
5536
5541
  const toggleMetadata = useCallback3(() => {
@@ -5540,20 +5545,68 @@ function WatcherView({
5540
5545
  const target = outputDir || resolveDefaultDownloadDir("instagram", "watcher");
5541
5546
  revealInFileManager(target);
5542
5547
  }, [outputDir]);
5548
+ useEffect6(() => {
5549
+ if (!onRegisterClickTargets) return;
5550
+ const targets = [
5551
+ { match: "Target:", padX: 1, action: () => {
5552
+ setFocusedIndex(0);
5553
+ cycleChoice();
5554
+ } },
5555
+ { match: "Sidecars:", padX: 1, action: () => {
5556
+ setFocusedIndex(1);
5557
+ toggleMetadata();
5558
+ } },
5559
+ { match: "Open Folder", padX: 1, action: () => {
5560
+ setFocusedIndex(2);
5561
+ openFolder();
5562
+ } },
5563
+ { match: "c target", padX: 1, action: () => {
5564
+ setFocusedIndex(0);
5565
+ cycleChoice();
5566
+ } },
5567
+ { match: "m sidecar", padX: 1, action: () => {
5568
+ setFocusedIndex(1);
5569
+ toggleMetadata();
5570
+ } },
5571
+ { match: "o open dir", padX: 1, action: () => {
5572
+ setFocusedIndex(2);
5573
+ openFolder();
5574
+ } },
5575
+ { match: "esc back", padX: 1, action: onBack }
5576
+ ];
5577
+ onRegisterClickTargets(targets);
5578
+ }, [onRegisterClickTargets, cycleChoice, toggleMetadata, openFolder, onBack, mediaChoice, writeMetadata]);
5543
5579
  useInput4((input, key) => {
5544
5580
  if (key.escape) {
5545
5581
  onBack();
5546
5582
  return;
5547
5583
  }
5584
+ if (key.leftArrow) {
5585
+ setFocusedIndex((prev) => prev === 0 ? 2 : prev - 1);
5586
+ return;
5587
+ }
5588
+ if (key.rightArrow || key.tab) {
5589
+ setFocusedIndex((prev) => prev === 2 ? 0 : prev + 1);
5590
+ return;
5591
+ }
5592
+ if (key.return || input === " ") {
5593
+ if (focusedIndex === 0) cycleChoice();
5594
+ else if (focusedIndex === 1) toggleMetadata();
5595
+ else if (focusedIndex === 2) openFolder();
5596
+ return;
5597
+ }
5548
5598
  if (input === "c" || input === "C") {
5599
+ setFocusedIndex(0);
5549
5600
  cycleChoice();
5550
5601
  return;
5551
5602
  }
5552
5603
  if (input === "m" || input === "M") {
5604
+ setFocusedIndex(1);
5553
5605
  toggleMetadata();
5554
5606
  return;
5555
5607
  }
5556
5608
  if (input === "o" || input === "O") {
5609
+ setFocusedIndex(2);
5557
5610
  openFolder();
5558
5611
  return;
5559
5612
  }
@@ -5569,8 +5622,10 @@ function WatcherView({
5569
5622
  ] }),
5570
5623
  /* @__PURE__ */ jsx16(ProgressBar, { indeterminate: true, width: 58, tick: pulseTick }),
5571
5624
  /* @__PURE__ */ jsx16(Gap2, {}),
5572
- /* @__PURE__ */ jsx16(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: "Listening for Instagram, TikTok, Facebook, or X profile links in clipboard." }),
5573
- /* @__PURE__ */ jsx16(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: "Simply copy any profile link in your browser and Open Nami will download it!" }),
5625
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
5626
+ /* @__PURE__ */ jsx16(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: "Auto-monitoring clipboard for profile links (Instagram, TikTok, FB, X)." }),
5627
+ /* @__PURE__ */ jsx16(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: "Copy any profile link in your browser: Open Nami downloads it in background." })
5628
+ ] }),
5574
5629
  /* @__PURE__ */ jsx16(Gap2, {}),
5575
5630
  /* @__PURE__ */ jsx16(
5576
5631
  Box13,
@@ -5606,15 +5661,42 @@ function WatcherView({
5606
5661
  ] }) : null,
5607
5662
  /* @__PURE__ */ jsx16(Gap2, {}),
5608
5663
  /* @__PURE__ */ jsxs13(Box13, { justifyContent: "space-between", children: [
5609
- /* @__PURE__ */ jsxs13(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: [
5610
- "[c] Target: ",
5611
- /* @__PURE__ */ jsx16(Text15, { color: theme.primary, bold: true, children: mediaChoice.toUpperCase() })
5612
- ] }),
5613
- /* @__PURE__ */ jsxs13(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: [
5614
- "[m] Sidecars: ",
5615
- /* @__PURE__ */ jsx16(Text15, { color: theme.primary, bold: true, children: writeMetadata ? "ON" : "OFF" })
5616
- ] }),
5617
- /* @__PURE__ */ jsx16(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: "[o] Open Folder" })
5664
+ /* @__PURE__ */ jsx16(
5665
+ Box13,
5666
+ {
5667
+ borderStyle: "round",
5668
+ borderColor: focusedIndex === 0 ? theme.primary : theme.gray,
5669
+ borderDimColor: focusedIndex !== 0,
5670
+ paddingX: 1,
5671
+ children: /* @__PURE__ */ jsxs13(Text15, { color: focusedIndex === 0 ? theme.primary : theme.gray, bold: focusedIndex === 0, children: [
5672
+ "[c] Target: ",
5673
+ /* @__PURE__ */ jsx16(Text15, { color: theme.primary, bold: true, children: mediaChoice === "all" ? "EVERYTHING" : mediaChoice.toUpperCase() })
5674
+ ] })
5675
+ }
5676
+ ),
5677
+ /* @__PURE__ */ jsx16(
5678
+ Box13,
5679
+ {
5680
+ borderStyle: "round",
5681
+ borderColor: focusedIndex === 1 ? theme.primary : theme.gray,
5682
+ borderDimColor: focusedIndex !== 1,
5683
+ paddingX: 1,
5684
+ children: /* @__PURE__ */ jsxs13(Text15, { color: focusedIndex === 1 ? theme.primary : theme.gray, bold: focusedIndex === 1, children: [
5685
+ "[m] Sidecars: ",
5686
+ /* @__PURE__ */ jsx16(Text15, { color: theme.primary, bold: true, children: writeMetadata ? "ON" : "OFF" })
5687
+ ] })
5688
+ }
5689
+ ),
5690
+ /* @__PURE__ */ jsx16(
5691
+ Box13,
5692
+ {
5693
+ borderStyle: "round",
5694
+ borderColor: focusedIndex === 2 ? theme.primary : theme.gray,
5695
+ borderDimColor: focusedIndex !== 2,
5696
+ paddingX: 1,
5697
+ children: /* @__PURE__ */ jsx16(Text15, { color: focusedIndex === 2 ? theme.primary : theme.gray, bold: focusedIndex === 2, children: "[o] Open Folder" })
5698
+ }
5699
+ )
5618
5700
  ] }),
5619
5701
  /* @__PURE__ */ jsx16(Box13, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs13(Text15, { color: theme.gray, dimColor: theme.dimSecondary, children: [
5620
5702
  "Session Stats: ",
@@ -5756,10 +5838,9 @@ async function runBatchQueue(options) {
5756
5838
  // src/components/views/batch-view.tsx
5757
5839
  import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
5758
5840
  var PLATFORMS = ["instagram", "tiktok", "facebook", "x"];
5759
- var CHOICES = ["all", "photos", "videos", "stories", "highlights"];
5841
+ var CHOICES2 = ["all", "photos", "videos", "stories", "highlights"];
5760
5842
  var DATE_PRESETS2 = ["all", "24h", "7d", "30d", "2024", "2023", "2022", "2021", "custom"];
5761
5843
  var LIMIT_PRESETS2 = [void 0, 10, 24, 50, 100, "custom"];
5762
- var OPTION_CONTROLS = ["platform", "choice", "limit", "date", "meta", "resume", "start"];
5763
5844
  function BatchView({
5764
5845
  onBack,
5765
5846
  outputDir,
@@ -5799,8 +5880,8 @@ function BatchView({
5799
5880
  }, []);
5800
5881
  const cycleChoice = useCallback4(() => {
5801
5882
  setChoice((prev) => {
5802
- const idx = CHOICES.indexOf(prev);
5803
- return CHOICES[(idx + 1) % CHOICES.length];
5883
+ const idx = CHOICES2.indexOf(prev);
5884
+ return CHOICES2[(idx + 1) % CHOICES2.length];
5804
5885
  });
5805
5886
  }, []);
5806
5887
  const cycleLimit = useCallback4(() => {
@@ -5980,71 +6061,195 @@ function BatchView({
5980
6061
  }
5981
6062
  return;
5982
6063
  }
5983
- if (OPTION_CONTROLS.includes(focusedControl)) {
6064
+ if (focusedControl === "platform") {
6065
+ if (key.rightArrow) {
6066
+ setFocusedControl("choice");
6067
+ return;
6068
+ }
6069
+ if (key.downArrow) {
6070
+ setFocusedControl("limit");
6071
+ return;
6072
+ }
5984
6073
  if (key.upArrow) {
5985
6074
  setFocusedControl("input");
5986
6075
  return;
5987
6076
  }
5988
- if (key.rightArrow || key.tab && !key.shift) {
5989
- const idx = OPTION_CONTROLS.indexOf(focusedControl);
5990
- setFocusedControl(OPTION_CONTROLS[(idx + 1) % OPTION_CONTROLS.length]);
6077
+ if (key.tab && !key.shift) {
6078
+ setFocusedControl("choice");
5991
6079
  return;
5992
6080
  }
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]);
6081
+ if (key.tab && key.shift) {
6082
+ setFocusedControl("input");
5996
6083
  return;
5997
6084
  }
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
- }
6085
+ } else if (focusedControl === "choice") {
6086
+ if (key.leftArrow) {
6087
+ setFocusedControl("platform");
6022
6088
  return;
6023
6089
  }
6024
- if (input === "p" || input === "P") {
6025
- cyclePlatform();
6090
+ if (key.downArrow) {
6091
+ setFocusedControl("date");
6026
6092
  return;
6027
6093
  }
6028
- if (input === "c" || input === "C") {
6029
- cycleChoice();
6094
+ if (key.upArrow) {
6095
+ setFocusedControl("input");
6030
6096
  return;
6031
6097
  }
6032
- if (input === "l" || input === "L") {
6033
- cycleLimit();
6098
+ if (key.tab && !key.shift) {
6099
+ setFocusedControl("limit");
6034
6100
  return;
6035
6101
  }
6036
- if (input === "d" || input === "D") {
6037
- cycleDate();
6102
+ if (key.tab && key.shift) {
6103
+ setFocusedControl("platform");
6038
6104
  return;
6039
6105
  }
6040
- if (input === "m" || input === "M") {
6041
- toggleMetadata();
6106
+ } else if (focusedControl === "limit") {
6107
+ if (key.upArrow) {
6108
+ setFocusedControl("platform");
6042
6109
  return;
6043
6110
  }
6044
- if (input === "r" || input === "R") {
6045
- toggleResume();
6111
+ if (key.rightArrow) {
6112
+ setFocusedControl("date");
6113
+ return;
6114
+ }
6115
+ if (key.downArrow) {
6116
+ setFocusedControl("meta");
6117
+ return;
6118
+ }
6119
+ if (key.tab && !key.shift) {
6120
+ setFocusedControl("date");
6121
+ return;
6122
+ }
6123
+ if (key.tab && key.shift) {
6124
+ setFocusedControl("choice");
6046
6125
  return;
6047
6126
  }
6127
+ } else if (focusedControl === "date") {
6128
+ if (key.upArrow) {
6129
+ setFocusedControl("choice");
6130
+ return;
6131
+ }
6132
+ if (key.leftArrow) {
6133
+ setFocusedControl("limit");
6134
+ return;
6135
+ }
6136
+ if (key.downArrow) {
6137
+ setFocusedControl("resume");
6138
+ return;
6139
+ }
6140
+ if (key.tab && !key.shift) {
6141
+ setFocusedControl("meta");
6142
+ return;
6143
+ }
6144
+ if (key.tab && key.shift) {
6145
+ setFocusedControl("limit");
6146
+ return;
6147
+ }
6148
+ } else if (focusedControl === "meta") {
6149
+ if (key.upArrow) {
6150
+ setFocusedControl("limit");
6151
+ return;
6152
+ }
6153
+ if (key.rightArrow) {
6154
+ setFocusedControl("resume");
6155
+ return;
6156
+ }
6157
+ if (key.downArrow) {
6158
+ setFocusedControl("start");
6159
+ return;
6160
+ }
6161
+ if (key.tab && !key.shift) {
6162
+ setFocusedControl("resume");
6163
+ return;
6164
+ }
6165
+ if (key.tab && key.shift) {
6166
+ setFocusedControl("date");
6167
+ return;
6168
+ }
6169
+ } else if (focusedControl === "resume") {
6170
+ if (key.upArrow) {
6171
+ setFocusedControl("date");
6172
+ return;
6173
+ }
6174
+ if (key.leftArrow) {
6175
+ setFocusedControl("meta");
6176
+ return;
6177
+ }
6178
+ if (key.downArrow) {
6179
+ setFocusedControl("start");
6180
+ return;
6181
+ }
6182
+ if (key.tab && !key.shift) {
6183
+ setFocusedControl("start");
6184
+ return;
6185
+ }
6186
+ if (key.tab && key.shift) {
6187
+ setFocusedControl("meta");
6188
+ return;
6189
+ }
6190
+ } else if (focusedControl === "start") {
6191
+ if (key.upArrow) {
6192
+ setFocusedControl("meta");
6193
+ return;
6194
+ }
6195
+ if (key.downArrow || key.tab && !key.shift) {
6196
+ setFocusedControl("tabs");
6197
+ return;
6198
+ }
6199
+ if (key.tab && key.shift) {
6200
+ setFocusedControl("resume");
6201
+ return;
6202
+ }
6203
+ }
6204
+ if (input === " " || key.return) {
6205
+ switch (focusedControl) {
6206
+ case "platform":
6207
+ cyclePlatform();
6208
+ break;
6209
+ case "choice":
6210
+ cycleChoice();
6211
+ break;
6212
+ case "limit":
6213
+ cycleLimit();
6214
+ break;
6215
+ case "date":
6216
+ cycleDate();
6217
+ break;
6218
+ case "meta":
6219
+ toggleMetadata();
6220
+ break;
6221
+ case "resume":
6222
+ toggleResume();
6223
+ break;
6224
+ case "start":
6225
+ startQueue();
6226
+ break;
6227
+ }
6228
+ return;
6229
+ }
6230
+ if (input === "p" || input === "P") {
6231
+ cyclePlatform();
6232
+ return;
6233
+ }
6234
+ if (input === "c" || input === "C") {
6235
+ cycleChoice();
6236
+ return;
6237
+ }
6238
+ if (input === "l" || input === "L") {
6239
+ cycleLimit();
6240
+ return;
6241
+ }
6242
+ if (input === "d" || input === "D") {
6243
+ cycleDate();
6244
+ return;
6245
+ }
6246
+ if (input === "m" || input === "M") {
6247
+ toggleMetadata();
6248
+ return;
6249
+ }
6250
+ if (input === "r" || input === "R") {
6251
+ toggleResume();
6252
+ return;
6048
6253
  }
6049
6254
  }
6050
6255
  }, { isActive: Boolean(process.stdin.isTTY) });
@@ -6055,6 +6260,7 @@ function BatchView({
6055
6260
  targets.push({
6056
6261
  match: "Links / Handles",
6057
6262
  padX: 2,
6263
+ padY: 0,
6058
6264
  action: () => {
6059
6265
  setInputField("text");
6060
6266
  setFocusedControl("input");
@@ -6063,24 +6269,22 @@ function BatchView({
6063
6269
  targets.push({
6064
6270
  match: "File (.txt)",
6065
6271
  padX: 2,
6272
+ padY: 0,
6066
6273
  action: () => {
6067
6274
  setInputField("file");
6068
6275
  setFocusedControl("input");
6069
6276
  }
6070
6277
  });
6071
6278
  targets.push({
6072
- match: "Links or @handles",
6279
+ match: "download",
6073
6280
  padX: 2,
6074
- action: () => setFocusedControl("input")
6075
- });
6076
- targets.push({
6077
- match: "Batch file (.txt)",
6078
- padX: 2,
6079
- action: () => setFocusedControl("input")
6281
+ padY: 1,
6282
+ action: startQueue
6080
6283
  });
6081
6284
  targets.push({
6082
6285
  match: "Platform:",
6083
6286
  padX: 2,
6287
+ padY: 0,
6084
6288
  action: () => {
6085
6289
  setFocusedControl("platform");
6086
6290
  cyclePlatform();
@@ -6089,6 +6293,7 @@ function BatchView({
6089
6293
  targets.push({
6090
6294
  match: "Media:",
6091
6295
  padX: 2,
6296
+ padY: 0,
6092
6297
  action: () => {
6093
6298
  setFocusedControl("choice");
6094
6299
  cycleChoice();
@@ -6097,6 +6302,7 @@ function BatchView({
6097
6302
  targets.push({
6098
6303
  match: "Posts:",
6099
6304
  padX: 2,
6305
+ padY: 0,
6100
6306
  action: () => {
6101
6307
  setFocusedControl("limit");
6102
6308
  cycleLimit();
@@ -6105,6 +6311,7 @@ function BatchView({
6105
6311
  targets.push({
6106
6312
  match: "Date:",
6107
6313
  padX: 2,
6314
+ padY: 0,
6108
6315
  action: () => {
6109
6316
  setFocusedControl("date");
6110
6317
  cycleDate();
@@ -6113,6 +6320,7 @@ function BatchView({
6113
6320
  targets.push({
6114
6321
  match: "Meta:",
6115
6322
  padX: 2,
6323
+ padY: 0,
6116
6324
  action: () => {
6117
6325
  setFocusedControl("meta");
6118
6326
  toggleMetadata();
@@ -6121,14 +6329,16 @@ function BatchView({
6121
6329
  targets.push({
6122
6330
  match: "Resume:",
6123
6331
  padX: 2,
6332
+ padY: 0,
6124
6333
  action: () => {
6125
6334
  setFocusedControl("resume");
6126
6335
  toggleResume();
6127
6336
  }
6128
6337
  });
6129
6338
  targets.push({
6130
- match: "Start Queue",
6339
+ match: "Start Batch Queue",
6131
6340
  padX: 3,
6341
+ padY: 0,
6132
6342
  action: () => {
6133
6343
  setFocusedControl("start");
6134
6344
  startQueue();
@@ -6214,60 +6424,79 @@ function BatchView({
6214
6424
  startQueue,
6215
6425
  outputDir
6216
6426
  ]);
6427
+ const panelWidth = Math.max(64, boxWidth);
6428
+ const inputFrameWidth = panelWidth - 18;
6429
+ const innerContentWidth = panelWidth - 6;
6430
+ const colWidth = Math.floor((innerContentWidth - 4) / 2);
6217
6431
  const currentItem = queueItems[currentIndex];
6218
6432
  const completedCount = queueItems.filter((i) => i.status === "success" || i.status === "failed").length;
6219
6433
  const totalCount = queueItems.length > 0 ? queueItems.length : 1;
6220
6434
  const percent = Math.min(100, Math.floor(completedCount / totalCount * 100));
6221
6435
  return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", alignItems: "center", children: [
6222
- phase === "input" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
6436
+ phase === "input" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue", width: panelWidth, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", alignItems: "center", paddingY: 1, children: [
6223
6437
  /* @__PURE__ */ jsxs14(Box14, { marginBottom: 1, justifyContent: "center", children: [
6224
- /* @__PURE__ */ jsx17(
6438
+ /* @__PURE__ */ jsx17(Box14, { marginRight: 2, children: /* @__PURE__ */ jsx17(
6225
6439
  Text16,
6226
6440
  {
6227
6441
  bold: true,
6228
6442
  color: inputField === "text" ? theme.primary : theme.gray,
6229
- inverse: focusedControl === "tabs" && inputField === "text",
6230
- children: inputField === "text" ? "\u25CF Links / Handles" : "\u25CB Links / Handles"
6443
+ inverse: inputField === "text",
6444
+ children: " Links / Handles "
6231
6445
  }
6232
- ),
6233
- /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: " \xB7 " }),
6234
- /* @__PURE__ */ jsx17(
6446
+ ) }),
6447
+ /* @__PURE__ */ jsx17(Box14, { children: /* @__PURE__ */ jsx17(
6235
6448
  Text16,
6236
6449
  {
6237
6450
  bold: true,
6238
6451
  color: inputField === "file" ? theme.primary : theme.gray,
6239
- inverse: focusedControl === "tabs" && inputField === "file",
6240
- children: inputField === "file" ? "\u25CF File (.txt)" : "\u25CB File (.txt)"
6452
+ inverse: inputField === "file",
6453
+ children: " File (.txt) "
6241
6454
  }
6242
- )
6455
+ ) })
6243
6456
  ] }),
6244
- inputField === "text" ? /* @__PURE__ */ jsx17(FramedInput, { title: "Links or @handles", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
6245
- TextInput,
6457
+ inputField === "text" ? /* @__PURE__ */ jsx17(
6458
+ FramedInput,
6246
6459
  {
6247
- value: rawText,
6248
- onChange: setRawText,
6249
- onSubmit: startQueue,
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")
6256
- }
6257
- ) }) : /* @__PURE__ */ jsx17(FramedInput, { title: "Batch file (.txt)", width: Math.max(56, boxWidth - 4), children: /* @__PURE__ */ jsx17(
6258
- TextInput,
6460
+ title: "Links or @handles",
6461
+ width: inputFrameWidth,
6462
+ button: "download",
6463
+ children: /* @__PURE__ */ jsx17(
6464
+ TextInput,
6465
+ {
6466
+ value: rawText,
6467
+ onChange: setRawText,
6468
+ onSubmit: startQueue,
6469
+ placeholder: "@user1, @user2, tiktok.com/@user3\u2026",
6470
+ width: inputFrameWidth - 4,
6471
+ focus: focusedControl === "input",
6472
+ onArrowDown: () => setFocusedControl("platform"),
6473
+ onArrowUp: () => setFocusedControl("tabs"),
6474
+ onTab: () => setFocusedControl("platform")
6475
+ }
6476
+ )
6477
+ }
6478
+ ) : /* @__PURE__ */ jsx17(
6479
+ FramedInput,
6259
6480
  {
6260
- value: filePath,
6261
- onChange: setFilePath,
6262
- onSubmit: startQueue,
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")
6481
+ title: "Batch file (.txt)",
6482
+ width: inputFrameWidth,
6483
+ button: "download",
6484
+ children: /* @__PURE__ */ jsx17(
6485
+ TextInput,
6486
+ {
6487
+ value: filePath,
6488
+ onChange: setFilePath,
6489
+ onSubmit: startQueue,
6490
+ placeholder: "e.g. creators.txt or C:\\path\\creators.txt",
6491
+ width: inputFrameWidth - 4,
6492
+ focus: focusedControl === "input",
6493
+ onArrowDown: () => setFocusedControl("platform"),
6494
+ onArrowUp: () => setFocusedControl("tabs"),
6495
+ onTab: () => setFocusedControl("platform")
6496
+ }
6497
+ )
6269
6498
  }
6270
- ) }),
6499
+ ),
6271
6500
  errorMessage ? /* @__PURE__ */ jsx17(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: "red", children: [
6272
6501
  "\u2717 ",
6273
6502
  errorMessage
@@ -6276,10 +6505,11 @@ function BatchView({
6276
6505
  Box14,
6277
6506
  {
6278
6507
  flexDirection: "column",
6508
+ width: innerContentWidth,
6279
6509
  marginTop: 1,
6280
6510
  borderStyle: "round",
6281
- borderColor: focusedControl !== "input" && focusedControl !== "tabs" ? theme.primary : theme.gray,
6282
- borderDimColor: focusedControl === "input" || focusedControl === "tabs",
6511
+ borderColor: focusedControl !== "input" && focusedControl !== "tabs" && focusedControl !== "start" ? theme.primary : theme.gray,
6512
+ borderDimColor: focusedControl === "input" || focusedControl === "tabs" || focusedControl === "start",
6283
6513
  paddingX: 1,
6284
6514
  children: focusedControl === "custom-limit" ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
6285
6515
  /* @__PURE__ */ jsx17(Text16, { bold: true, color: theme.primary, children: "Set post limit (e.g. 24, all):" }),
@@ -6291,7 +6521,7 @@ function BatchView({
6291
6521
  onSubmit: (val) => {
6292
6522
  const parsed = parseLimit(val);
6293
6523
  setLimit(parsed);
6294
- setFocusedControl("start");
6524
+ setFocusedControl("limit");
6295
6525
  },
6296
6526
  width: 24
6297
6527
  }
@@ -6307,110 +6537,106 @@ function BatchView({
6307
6537
  onSubmit: (val) => {
6308
6538
  const trimmed = val.trim();
6309
6539
  setDateFilter(trimmed ? trimmed : "all");
6310
- setFocusedControl("start");
6540
+ setFocusedControl("date");
6311
6541
  },
6312
6542
  width: 24
6313
6543
  }
6314
6544
  ) }),
6315
6545
  /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "\u21B5 confirm \xB7 esc cancel" })
6316
6546
  ] }) : /* @__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
- " ",
6547
+ /* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", width: "100%", children: [
6548
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6549
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[p] Platform: " }),
6321
6550
  /* @__PURE__ */ jsx17(
6322
6551
  Text16,
6323
6552
  {
6324
- color: theme.primary,
6325
6553
  bold: true,
6554
+ color: theme.primary,
6326
6555
  inverse: focusedControl === "platform",
6327
- children: defaultPlatform.toUpperCase()
6556
+ children: ` ${defaultPlatform.toUpperCase()} `
6328
6557
  }
6329
6558
  )
6330
6559
  ] }),
6331
- /* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
6332
- "[c] Media:",
6333
- " ",
6560
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6561
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[c] Media: " }),
6334
6562
  /* @__PURE__ */ jsx17(
6335
6563
  Text16,
6336
6564
  {
6337
- color: theme.primary,
6338
6565
  bold: true,
6566
+ color: theme.primary,
6339
6567
  inverse: focusedControl === "choice",
6340
- children: choice === "all" ? "EVERYTHING" : choice.toUpperCase()
6568
+ children: ` ${choice === "all" ? "EVERYTHING" : choice.toUpperCase()} `
6341
6569
  }
6342
6570
  )
6343
- ] }),
6344
- /* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
6345
- "[l] Posts:",
6346
- " ",
6571
+ ] })
6572
+ ] }),
6573
+ /* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", width: "100%", marginTop: 1, children: [
6574
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6575
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[l] Posts: " }),
6347
6576
  /* @__PURE__ */ jsx17(
6348
6577
  Text16,
6349
6578
  {
6350
- color: theme.primary,
6351
6579
  bold: true,
6580
+ color: theme.primary,
6352
6581
  inverse: focusedControl === "limit",
6353
- children: limit ? `${limit}` : "ALL"
6582
+ children: ` ${limit ? String(limit) : "ALL"} `
6354
6583
  }
6355
6584
  )
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
- " ",
6585
+ ] }),
6586
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6587
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[d] Date: " }),
6362
6588
  /* @__PURE__ */ jsx17(
6363
6589
  Text16,
6364
6590
  {
6365
- color: theme.primary,
6366
6591
  bold: true,
6592
+ color: theme.primary,
6367
6593
  inverse: focusedControl === "date",
6368
- children: dateFilter.toUpperCase()
6594
+ children: ` ${dateFilter.toUpperCase()} `
6369
6595
  }
6370
6596
  )
6371
- ] }),
6372
- /* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
6373
- "[m] Meta:",
6374
- " ",
6597
+ ] })
6598
+ ] }),
6599
+ /* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", width: "100%", marginTop: 1, children: [
6600
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6601
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[m] Meta: " }),
6375
6602
  /* @__PURE__ */ jsx17(
6376
6603
  Text16,
6377
6604
  {
6378
- color: theme.primary,
6379
6605
  bold: true,
6606
+ color: theme.primary,
6380
6607
  inverse: focusedControl === "meta",
6381
- children: writeMetadata ? "ON" : "OFF"
6608
+ children: ` ${writeMetadata ? "ON" : "OFF"} `
6382
6609
  }
6383
6610
  )
6384
6611
  ] }),
6385
- /* @__PURE__ */ jsxs14(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: [
6386
- "[r] Resume:",
6387
- " ",
6612
+ /* @__PURE__ */ jsxs14(Box14, { width: colWidth, children: [
6613
+ /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[r] Resume: " }),
6388
6614
  /* @__PURE__ */ jsx17(
6389
6615
  Text16,
6390
6616
  {
6391
- color: theme.primary,
6392
6617
  bold: true,
6618
+ color: theme.primary,
6393
6619
  inverse: focusedControl === "resume",
6394
- children: resume ? "ON" : "OFF"
6620
+ children: ` ${resume ? "ON" : "OFF"} `
6395
6621
  }
6396
6622
  )
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
- )
6623
+ ] })
6407
6624
  ] })
6408
6625
  ] })
6409
6626
  }
6410
6627
  ),
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" }) })
6628
+ /* @__PURE__ */ jsx17(Box14, { justifyContent: "center", marginTop: 1, children: /* @__PURE__ */ jsx17(
6629
+ Text16,
6630
+ {
6631
+ bold: true,
6632
+ color: theme.primary,
6633
+ inverse: focusedControl === "start",
6634
+ children: " \u21B5 Start Batch Queue "
6635
+ }
6636
+ ) }),
6637
+ /* @__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 or click download to start" : focusedControl === "tabs" ? "Space to switch mode \xB7 \u2193 to edit input" : "\u2190/\u2192/Tab select \xB7 Space/Enter toggle \xB7 \u21B5 start queue \xB7 \u2191 edit input" }) })
6412
6638
  ] }) }),
6413
- phase === "running" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Running", width: Math.max(60, boxWidth), children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
6639
+ phase === "running" && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Running", width: panelWidth, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
6414
6640
  /* @__PURE__ */ jsxs14(Box14, { justifyContent: "space-between", marginBottom: 1, children: [
6415
6641
  /* @__PURE__ */ jsxs14(Text16, { color: theme.primary, bold: true, children: [
6416
6642
  "Account ",
@@ -6423,7 +6649,7 @@ function BatchView({
6423
6649
  ] }),
6424
6650
  /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: isCooldown ? "\u23F3 Cooldown active" : "\u25B6 Downloading" })
6425
6651
  ] }),
6426
- /* @__PURE__ */ jsx17(ProgressBar, { percent, width: 54 }),
6652
+ /* @__PURE__ */ jsx17(ProgressBar, { percent, width: panelWidth - 10 }),
6427
6653
  /* @__PURE__ */ jsx17(Gap2, {}),
6428
6654
  currentItem ? /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", borderStyle: "round", borderColor: theme.primary, paddingX: 1, paddingY: 1, children: [
6429
6655
  /* @__PURE__ */ jsxs14(Box14, { children: [
@@ -6445,7 +6671,7 @@ function BatchView({
6445
6671
  /* @__PURE__ */ jsx17(Gap2, {}),
6446
6672
  /* @__PURE__ */ jsx17(Text16, { color: theme.gray, dimColor: theme.dimSecondary, children: "[esc] Stop queue and return" })
6447
6673
  ] }) }),
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: [
6674
+ phase === "done" && result && /* @__PURE__ */ jsx17(Panel, { title: "Batch Queue Completed", width: panelWidth, children: /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingY: 1, children: [
6449
6675
  /* @__PURE__ */ jsxs14(Text16, { bold: true, color: theme.primary, children: [
6450
6676
  "\u2713 Successfully processed ",
6451
6677
  result.total,
@@ -6649,6 +6875,7 @@ function InnerApp({
6649
6875
  const [clipboardUrl, setClipboardUrl] = useState9(void 0);
6650
6876
  const [settingsFocus, setSettingsFocus] = useState9("cookies");
6651
6877
  const [batchClickTargets, setBatchClickTargets] = useState9([]);
6878
+ const [watcherClickTargets, setWatcherClickTargets] = useState9([]);
6652
6879
  const columns = stdout?.columns && stdout.columns > 0 ? stdout.columns : 80;
6653
6880
  const boxWidth = Math.max(14, Math.min(64, columns - 6));
6654
6881
  const contentWidth = Math.max(10, Math.min(columns - 4, 78));
@@ -6800,8 +7027,11 @@ function InnerApp({
6800
7027
  if (key.ctrl && (input === "w" || input === "W")) {
6801
7028
  if (phase.name === "watcher") {
6802
7029
  setPhase({ name: "input" });
6803
- } else if (phase.name === "input") {
7030
+ return;
7031
+ }
7032
+ if (phase.name === "input" && urlInput.length === 0) {
6804
7033
  setPhase({ name: "watcher" });
7034
+ return;
6805
7035
  }
6806
7036
  return;
6807
7037
  }
@@ -6919,6 +7149,9 @@ function InnerApp({
6919
7149
  if (phase.name === "batch") {
6920
7150
  targets.push(...batchClickTargets);
6921
7151
  }
7152
+ if (phase.name === "watcher") {
7153
+ targets.push(...watcherClickTargets);
7154
+ }
6922
7155
  for (const [key, label] of hints) {
6923
7156
  const action = hintAction(key);
6924
7157
  if (action) targets.push({ match: `${key} ${label}`, action });
@@ -6939,7 +7172,8 @@ function InnerApp({
6939
7172
  handlePlatformSelect,
6940
7173
  handleModeSelect,
6941
7174
  resetToInput,
6942
- batchClickTargets
7175
+ batchClickTargets,
7176
+ watcherClickTargets
6943
7177
  ]);
6944
7178
  useMouseClick(
6945
7179
  (x, y) => {
@@ -7066,7 +7300,8 @@ function InnerApp({
7066
7300
  theme,
7067
7301
  gapComponent: Gap,
7068
7302
  defaultChoice: initialChoice,
7069
- defaultWriteMetadata: effectiveWriteMetadata
7303
+ defaultWriteMetadata: effectiveWriteMetadata,
7304
+ onRegisterClickTargets: setWatcherClickTargets
7070
7305
  }
7071
7306
  ),
7072
7307
  phase.name === "batch" && /* @__PURE__ */ jsx18(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-nami",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "Open Nami: terminal-first bulk social media profile downloader for Instagram, TikTok, Facebook & X.",
5
5
  "type": "module",
6
6
  "bin": {