open-nami 1.5.1 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +447 -48
  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.5.1",
12
+ version: "1.6.0",
13
13
  description: "Open Nami: terminal-first bulk social media profile downloader for Instagram, TikTok, Facebook & X.",
14
14
  type: "module",
15
15
  bin: {
@@ -749,9 +749,21 @@ function loadConfig(configPath = getDefaultConfigPath()) {
749
749
  const raw = fs.readFileSync(configPath, "utf8");
750
750
  const parsed = JSON.parse(raw);
751
751
  if (parsed && typeof parsed === "object") {
752
- const rawBrowser = typeof parsed.cookiesFromBrowser === "string" ? parsed.cookiesFromBrowser.trim().toLowerCase() : void 0;
753
- const validBrowsers = ["chrome", "edge", "brave", "firefox", "none"];
754
- const cookiesFromBrowser = rawBrowser && validBrowsers.includes(rawBrowser) ? rawBrowser : void 0;
752
+ let cookiesFromBrowser = "auto";
753
+ if (typeof parsed.cookiesFromBrowser === "string") {
754
+ const trimmed = parsed.cookiesFromBrowser.trim();
755
+ const lower = trimmed.toLowerCase();
756
+ if (lower === "none") {
757
+ cookiesFromBrowser = "none";
758
+ } else if (lower === "auto" || trimmed === "") {
759
+ cookiesFromBrowser = "auto";
760
+ } else {
761
+ const knownBrowsers = ["chrome", "edge", "brave", "firefox", "helium", "opera", "vivaldi"];
762
+ cookiesFromBrowser = knownBrowsers.includes(lower) ? lower : trimmed;
763
+ }
764
+ } else {
765
+ cookiesFromBrowser = "auto";
766
+ }
755
767
  return {
756
768
  theme: typeof parsed.theme === "string" ? parsed.theme : void 0,
757
769
  cookiesDir: typeof parsed.cookiesDir === "string" ? parsed.cookiesDir.trim() : void 0,
@@ -784,9 +796,10 @@ import path4 from "path";
784
796
  import os3 from "os";
785
797
 
786
798
  // src/lib/cookies/browser-bridge.ts
799
+ import { execSync } from "child_process";
787
800
  import fs2 from "fs";
788
- import path3 from "path";
789
801
  import os2 from "os";
802
+ import path3 from "path";
790
803
  function listDetectedBrowsers() {
791
804
  const isWin = process.platform === "win32";
792
805
  const isMac = process.platform === "darwin";
@@ -795,30 +808,91 @@ function listDetectedBrowsers() {
795
808
  {
796
809
  id: "chrome",
797
810
  name: "Google Chrome",
798
- winDir: path3.join(process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"), "Google", "Chrome", "User Data"),
811
+ winDir: path3.join(
812
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
813
+ "Google",
814
+ "Chrome",
815
+ "User Data"
816
+ ),
799
817
  macDir: path3.join(home, "Library", "Application Support", "Google", "Chrome"),
800
- linuxDir: path3.join(home, ".config", "google-chrome")
818
+ linuxDir: path3.join(home, ".config", "google-chrome"),
819
+ engine: "chrome"
801
820
  },
802
821
  {
803
822
  id: "edge",
804
823
  name: "Microsoft Edge",
805
- winDir: path3.join(process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"), "Microsoft", "Edge", "User Data"),
824
+ winDir: path3.join(
825
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
826
+ "Microsoft",
827
+ "Edge",
828
+ "User Data"
829
+ ),
806
830
  macDir: path3.join(home, "Library", "Application Support", "Microsoft Edge"),
807
- linuxDir: path3.join(home, ".config", "microsoft-edge")
831
+ linuxDir: path3.join(home, ".config", "microsoft-edge"),
832
+ engine: "edge"
808
833
  },
809
834
  {
810
835
  id: "brave",
811
836
  name: "Brave Browser",
812
- winDir: path3.join(process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"), "BraveSoftware", "Brave-Browser", "User Data"),
837
+ winDir: path3.join(
838
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
839
+ "BraveSoftware",
840
+ "Brave-Browser",
841
+ "User Data"
842
+ ),
813
843
  macDir: path3.join(home, "Library", "Application Support", "BraveSoftware", "Brave-Browser"),
814
- linuxDir: path3.join(home, ".config", "BraveSoftware", "Brave-Browser")
844
+ linuxDir: path3.join(home, ".config", "BraveSoftware", "Brave-Browser"),
845
+ engine: "brave"
815
846
  },
816
847
  {
817
848
  id: "firefox",
818
849
  name: "Mozilla Firefox",
819
- winDir: path3.join(process.env.APPDATA || path3.join(home, "AppData", "Roaming"), "Mozilla", "Firefox", "Profiles"),
850
+ winDir: path3.join(
851
+ process.env.APPDATA || path3.join(home, "AppData", "Roaming"),
852
+ "Mozilla",
853
+ "Firefox",
854
+ "Profiles"
855
+ ),
820
856
  macDir: path3.join(home, "Library", "Application Support", "Firefox", "Profiles"),
821
- linuxDir: path3.join(home, ".mozilla", "firefox")
857
+ linuxDir: path3.join(home, ".mozilla", "firefox"),
858
+ engine: "firefox"
859
+ },
860
+ {
861
+ id: "helium",
862
+ name: "Helium",
863
+ winDir: path3.join(
864
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
865
+ "imput",
866
+ "Helium",
867
+ "User Data"
868
+ ),
869
+ macDir: path3.join(home, "Library", "Application Support", "net.imput.Helium"),
870
+ linuxDir: path3.join(home, ".config", "helium"),
871
+ engine: "chrome"
872
+ },
873
+ {
874
+ id: "opera",
875
+ name: "Opera",
876
+ winDir: path3.join(
877
+ process.env.APPDATA || path3.join(home, "AppData", "Roaming"),
878
+ "Opera Software",
879
+ "Opera Stable"
880
+ ),
881
+ macDir: path3.join(home, "Library", "Application Support", "com.operasoftware.Opera"),
882
+ linuxDir: path3.join(home, ".config", "opera"),
883
+ engine: "opera"
884
+ },
885
+ {
886
+ id: "vivaldi",
887
+ name: "Vivaldi",
888
+ winDir: path3.join(
889
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
890
+ "Vivaldi",
891
+ "User Data"
892
+ ),
893
+ macDir: path3.join(home, "Library", "Application Support", "Vivaldi"),
894
+ linuxDir: path3.join(home, ".config", "vivaldi"),
895
+ engine: "vivaldi"
822
896
  }
823
897
  ];
824
898
  return candidates.map((c) => {
@@ -827,10 +901,313 @@ function listDetectedBrowsers() {
827
901
  id: c.id,
828
902
  name: c.name,
829
903
  profileDir,
830
- available: fs2.existsSync(profileDir)
904
+ available: fs2.existsSync(profileDir),
905
+ engine: c.engine
831
906
  };
832
907
  });
833
908
  }
909
+ function parseWindowsDefaultBrowserProgId(rawOutput) {
910
+ if (!rawOutput) return null;
911
+ const lines = rawOutput.split(/\r?\n/);
912
+ const pattern = /^\s*ProgId\s+REG_\w+\s+(\S.*)$/i;
913
+ for (const line of lines) {
914
+ const match = line.match(pattern);
915
+ if (match && match[1]) {
916
+ const progId = match[1].trim();
917
+ if (progId) return progId;
918
+ }
919
+ }
920
+ return null;
921
+ }
922
+ function mapProgIdToBrowserId(progId, commandOutput, platformOverride = "win32") {
923
+ const p = (progId || "").trim();
924
+ const pLower = p.toLowerCase();
925
+ const cmd = (commandOutput || "").toLowerCase();
926
+ const isWin = platformOverride === "win32";
927
+ const isMac = platformOverride === "darwin";
928
+ const home = os2.homedir();
929
+ const heliumDir = isWin ? path3.join(
930
+ process.env.LOCALAPPDATA || path3.join(home, "AppData", "Local"),
931
+ "imput",
932
+ "Helium",
933
+ "User Data"
934
+ ) : isMac ? path3.join(home, "Library", "Application Support", "net.imput.Helium") : path3.join(home, ".config", "helium");
935
+ if (pLower.includes("helium") || cmd.includes("helium")) {
936
+ return {
937
+ id: "helium",
938
+ name: "Helium",
939
+ engine: "chrome",
940
+ profileDir: heliumDir
941
+ };
942
+ }
943
+ if (pLower.startsWith("chromehtml") || pLower.includes("chrome") || cmd.includes("chrome.exe")) {
944
+ return {
945
+ id: "chrome",
946
+ name: "Google Chrome",
947
+ engine: "chrome"
948
+ };
949
+ }
950
+ if (pLower.startsWith("msedge") || pLower.includes("edge") || pLower.startsWith("appxq0fevzme2pys62n3e0fbqsw5cj08ege9") || cmd.includes("msedge.exe")) {
951
+ return {
952
+ id: "edge",
953
+ name: "Microsoft Edge",
954
+ engine: "edge"
955
+ };
956
+ }
957
+ if (pLower.startsWith("brave") || pLower.includes("brave") || cmd.includes("brave.exe")) {
958
+ return {
959
+ id: "brave",
960
+ name: "Brave Browser",
961
+ engine: "brave"
962
+ };
963
+ }
964
+ if (pLower.startsWith("firefox") || pLower.includes("firefox") || cmd.includes("firefox.exe")) {
965
+ return {
966
+ id: "firefox",
967
+ name: "Mozilla Firefox",
968
+ engine: "firefox"
969
+ };
970
+ }
971
+ if (pLower.startsWith("opera") || pLower.includes("opera") || cmd.includes("opera.exe")) {
972
+ return {
973
+ id: "opera",
974
+ name: "Opera",
975
+ engine: "opera"
976
+ };
977
+ }
978
+ if (pLower.startsWith("vivaldi") || pLower.includes("vivaldi") || cmd.includes("vivaldi.exe")) {
979
+ return {
980
+ id: "vivaldi",
981
+ name: "Vivaldi",
982
+ engine: "vivaldi"
983
+ };
984
+ }
985
+ return {
986
+ id: pLower || "chromium",
987
+ name: p || "Chromium",
988
+ engine: "chromium"
989
+ };
990
+ }
991
+ function parseMacDefaultBrowserBundleId(rawOutput) {
992
+ if (!rawOutput) return null;
993
+ const blocks = rawOutput.split(/[{}]/);
994
+ let httpBundle = null;
995
+ for (const block of blocks) {
996
+ const isHttps = /LSHandlerURLScheme\s*=\s*https\b/i.test(block);
997
+ const isHttp = /LSHandlerURLScheme\s*=\s*http\b/i.test(block);
998
+ if (!isHttps && !isHttp) continue;
999
+ const roleMatch = block.match(/LSHandlerRole(?:All|Viewer)\s*=\s*["']?([^"';\s]+)["']?/i);
1000
+ if (roleMatch && roleMatch[1]) {
1001
+ const bundleId = roleMatch[1].trim();
1002
+ if (isHttps) {
1003
+ return bundleId;
1004
+ }
1005
+ if (!httpBundle) {
1006
+ httpBundle = bundleId;
1007
+ }
1008
+ }
1009
+ }
1010
+ return httpBundle;
1011
+ }
1012
+ function mapBundleIdToBrowserId(bundleId) {
1013
+ const lower = bundleId.toLowerCase();
1014
+ if (lower.includes("helium")) {
1015
+ const home = os2.homedir();
1016
+ return {
1017
+ id: "helium",
1018
+ name: "Helium",
1019
+ engine: "chrome",
1020
+ profileDir: path3.join(home, "Library", "Application Support", "net.imput.Helium")
1021
+ };
1022
+ }
1023
+ if (lower.includes("chrome")) {
1024
+ return { id: "chrome", name: "Google Chrome", engine: "chrome" };
1025
+ }
1026
+ if (lower.includes("edge")) {
1027
+ return { id: "edge", name: "Microsoft Edge", engine: "edge" };
1028
+ }
1029
+ if (lower.includes("brave")) {
1030
+ return { id: "brave", name: "Brave Browser", engine: "brave" };
1031
+ }
1032
+ if (lower.includes("firefox")) {
1033
+ return { id: "firefox", name: "Mozilla Firefox", engine: "firefox" };
1034
+ }
1035
+ if (lower.includes("opera")) {
1036
+ return { id: "opera", name: "Opera", engine: "opera" };
1037
+ }
1038
+ if (lower.includes("vivaldi")) {
1039
+ return { id: "vivaldi", name: "Vivaldi", engine: "vivaldi" };
1040
+ }
1041
+ if (lower.includes("safari")) {
1042
+ return { id: "safari", name: "Safari", engine: "safari" };
1043
+ }
1044
+ return { id: lower, name: bundleId, engine: "chromium" };
1045
+ }
1046
+ function parseLinuxDefaultBrowserDesktop(rawOutput) {
1047
+ if (!rawOutput) return null;
1048
+ const lines = rawOutput.split(/\r?\n/);
1049
+ for (const line of lines) {
1050
+ const trimmed = line.trim();
1051
+ if (trimmed && !trimmed.startsWith("ERROR:") && !trimmed.includes("not found")) {
1052
+ return trimmed;
1053
+ }
1054
+ }
1055
+ return null;
1056
+ }
1057
+ function mapLinuxDesktopToBrowserId(desktopFile) {
1058
+ const lower = desktopFile.toLowerCase();
1059
+ if (lower.includes("helium")) {
1060
+ const home = os2.homedir();
1061
+ return {
1062
+ id: "helium",
1063
+ name: "Helium",
1064
+ engine: "chrome",
1065
+ profileDir: path3.join(home, ".config", "helium")
1066
+ };
1067
+ }
1068
+ if (lower.includes("chrome")) {
1069
+ return { id: "chrome", name: "Google Chrome", engine: "chrome" };
1070
+ }
1071
+ if (lower.includes("edge")) {
1072
+ return { id: "edge", name: "Microsoft Edge", engine: "edge" };
1073
+ }
1074
+ if (lower.includes("brave")) {
1075
+ return { id: "brave", name: "Brave Browser", engine: "brave" };
1076
+ }
1077
+ if (lower.includes("firefox")) {
1078
+ return { id: "firefox", name: "Mozilla Firefox", engine: "firefox" };
1079
+ }
1080
+ if (lower.includes("opera")) {
1081
+ return { id: "opera", name: "Opera", engine: "opera" };
1082
+ }
1083
+ if (lower.includes("vivaldi")) {
1084
+ return { id: "vivaldi", name: "Vivaldi", engine: "vivaldi" };
1085
+ }
1086
+ return { id: lower.replace(/\.desktop$/, ""), name: desktopFile, engine: "chromium" };
1087
+ }
1088
+ function queryWindows(execute, platformOverride) {
1089
+ let out = execute(
1090
+ 'reg query "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\https\\UserChoice" /v ProgId'
1091
+ );
1092
+ let progId = parseWindowsDefaultBrowserProgId(out);
1093
+ if (!progId) {
1094
+ out = execute(
1095
+ 'reg query "HKCU\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice" /v ProgId'
1096
+ );
1097
+ progId = parseWindowsDefaultBrowserProgId(out);
1098
+ }
1099
+ if (progId) {
1100
+ const cmdOut = execute(`reg query "HKCR\\${progId}\\shell\\open\\command"`);
1101
+ return mapProgIdToBrowserId(progId, cmdOut, platformOverride ?? "win32");
1102
+ }
1103
+ return null;
1104
+ }
1105
+ function queryMac(execute) {
1106
+ const out = execute(
1107
+ "defaults read com.apple.LaunchServices/com.apple.launchservices.secure LSHandlers"
1108
+ );
1109
+ const bundleId = parseMacDefaultBrowserBundleId(out);
1110
+ if (bundleId) {
1111
+ return mapBundleIdToBrowserId(bundleId);
1112
+ }
1113
+ return null;
1114
+ }
1115
+ function queryLinux(execute) {
1116
+ let out = execute("xdg-settings get default-web-browser");
1117
+ let desktop = parseLinuxDefaultBrowserDesktop(out);
1118
+ if (!desktop) {
1119
+ out = execute("xdg-mime query default x-scheme-handler/https");
1120
+ desktop = parseLinuxDefaultBrowserDesktop(out);
1121
+ }
1122
+ if (!desktop) {
1123
+ out = execute("xdg-mime query default x-scheme-handler/http");
1124
+ desktop = parseLinuxDefaultBrowserDesktop(out);
1125
+ }
1126
+ if (desktop) {
1127
+ return mapLinuxDesktopToBrowserId(desktop);
1128
+ }
1129
+ return null;
1130
+ }
1131
+ function detectSystemDefaultBrowser(execFn, platformOverride) {
1132
+ const platform = platformOverride ?? process.platform;
1133
+ const execute = execFn ?? ((cmd) => {
1134
+ try {
1135
+ return execSync(cmd, {
1136
+ encoding: "utf8",
1137
+ stdio: ["pipe", "pipe", "ignore"],
1138
+ timeout: 2500
1139
+ });
1140
+ } catch {
1141
+ return "";
1142
+ }
1143
+ });
1144
+ let detectedInfo = null;
1145
+ if (platform === "win32") {
1146
+ detectedInfo = queryWindows(execute, platform);
1147
+ } else if (platform === "darwin") {
1148
+ detectedInfo = queryMac(execute);
1149
+ } else if (platform === "linux") {
1150
+ detectedInfo = queryLinux(execute);
1151
+ }
1152
+ if (!detectedInfo && execFn && !platformOverride) {
1153
+ if (platform !== "win32") detectedInfo = queryWindows(execute, "win32");
1154
+ if (!detectedInfo && platform !== "darwin") detectedInfo = queryMac(execute);
1155
+ if (!detectedInfo && platform !== "linux") detectedInfo = queryLinux(execute);
1156
+ }
1157
+ const allBrowsers = listDetectedBrowsers();
1158
+ if (detectedInfo) {
1159
+ const matched = allBrowsers.find((b) => b.id === detectedInfo.id);
1160
+ if (matched) {
1161
+ if (detectedInfo.profileDir) {
1162
+ return {
1163
+ ...matched,
1164
+ profileDir: detectedInfo.profileDir,
1165
+ available: fs2.existsSync(detectedInfo.profileDir)
1166
+ };
1167
+ }
1168
+ return matched;
1169
+ }
1170
+ const profDir = detectedInfo.profileDir || "";
1171
+ return {
1172
+ id: detectedInfo.id,
1173
+ name: detectedInfo.name || detectedInfo.id,
1174
+ profileDir: profDir,
1175
+ available: profDir ? fs2.existsSync(profDir) : false,
1176
+ engine: detectedInfo.engine
1177
+ };
1178
+ }
1179
+ const availableFallback = allBrowsers.find((b) => b.available);
1180
+ return availableFallback || null;
1181
+ }
1182
+ function resolveBrowserCookieArg(browser) {
1183
+ if (!browser) {
1184
+ return null;
1185
+ }
1186
+ if (typeof browser === "string") {
1187
+ const trimmed = browser.trim();
1188
+ if (!trimmed || trimmed.toLowerCase() === "none") {
1189
+ return null;
1190
+ }
1191
+ if (trimmed.toLowerCase() === "helium") {
1192
+ const detectedHelium = listDetectedBrowsers().find((b) => b.id === "helium");
1193
+ const profileDir = detectedHelium?.profileDir;
1194
+ return profileDir ? `chrome:${profileDir}` : "chrome";
1195
+ }
1196
+ if (trimmed.toLowerCase() === "auto") {
1197
+ const defaultBrowser = detectSystemDefaultBrowser();
1198
+ return resolveBrowserCookieArg(defaultBrowser);
1199
+ }
1200
+ return trimmed;
1201
+ }
1202
+ if (!browser.id || browser.id.toLowerCase() === "none") {
1203
+ return null;
1204
+ }
1205
+ if (browser.id.toLowerCase() === "helium") {
1206
+ const profileDir = browser.profileDir || listDetectedBrowsers().find((b) => b.id === "helium")?.profileDir;
1207
+ return profileDir ? `chrome:${profileDir}` : "chrome";
1208
+ }
1209
+ return browser.id;
1210
+ }
834
1211
 
835
1212
  // src/lib/cookies.ts
836
1213
  var CANDIDATE_DIRS = [
@@ -4471,7 +4848,9 @@ async function dispatchDownload(options) {
4471
4848
  const { profile, choice, onProgress } = options;
4472
4849
  const targetDir = options.outputDir || resolveDefaultDownloadDir(profile.platform, profile.username);
4473
4850
  await fs13.mkdir(targetDir, { recursive: true });
4474
- const cookiesFromBrowser = options.cookiesFromBrowser ?? loadConfig().cookiesFromBrowser;
4851
+ const rawBrowserPref = options.cookiesFromBrowser ?? loadConfig().cookiesFromBrowser ?? "auto";
4852
+ const resolvedBrowserArg = resolveBrowserCookieArg(rawBrowserPref);
4853
+ const cookiesFromBrowser = resolvedBrowserArg ?? void 0;
4475
4854
  defaultTaskManager.events.emit("job:start", { profile, choice, outputDir: targetDir });
4476
4855
  const masterCookie = findCookieFile(profile.platform);
4477
4856
  const cookieCopy = masterCookie ? await createSafeCookieCopy(masterCookie) : null;
@@ -4594,25 +4973,31 @@ async function dispatchDownload(options) {
4594
4973
  }
4595
4974
  };
4596
4975
  const runNative = options.runnerOverrides?.nativeRunner ?? defaultRunNative;
4597
- const runGdl = options.runnerOverrides?.gdlRunner ?? ((subDir) => runGalleryDl({
4598
- profile,
4599
- targetDir,
4600
- subDir,
4601
- cookiePath: cookieCopy?.filePath,
4602
- cookiesFromBrowser,
4603
- signal: options.signal,
4604
- writeMetadata: options.writeMetadata,
4605
- onProgress: handleProgress
4606
- }));
4607
- const runYt = options.runnerOverrides?.ytRunner ?? (() => runYtDlp({
4608
- profile,
4609
- targetDir,
4610
- cookiePath: cookieCopy?.filePath,
4611
- cookiesFromBrowser,
4612
- signal: options.signal,
4613
- writeMetadata: options.writeMetadata,
4614
- onProgress: handleProgress
4615
- }));
4976
+ const runGdl = (subDir) => {
4977
+ const runnerOpts = {
4978
+ profile,
4979
+ targetDir,
4980
+ subDir,
4981
+ cookiePath: cookieCopy?.filePath,
4982
+ cookiesFromBrowser,
4983
+ signal: options.signal,
4984
+ writeMetadata: options.writeMetadata,
4985
+ onProgress: handleProgress
4986
+ };
4987
+ return options.runnerOverrides?.gdlRunner ? options.runnerOverrides.gdlRunner(subDir, runnerOpts) : runGalleryDl(runnerOpts);
4988
+ };
4989
+ const runYt = () => {
4990
+ const runnerOpts = {
4991
+ profile,
4992
+ targetDir,
4993
+ cookiePath: cookieCopy?.filePath,
4994
+ cookiesFromBrowser,
4995
+ signal: options.signal,
4996
+ writeMetadata: options.writeMetadata,
4997
+ onProgress: handleProgress
4998
+ };
4999
+ return options.runnerOverrides?.ytRunner ? options.runnerOverrides.ytRunner(runnerOpts) : runYtDlp(runnerOpts);
5000
+ };
4616
5001
  for (const job of jobs) {
4617
5002
  if (options.signal?.aborted) break;
4618
5003
  if (globalLimit !== void 0 && totalDownloaded >= globalLimit) break;
@@ -5223,10 +5608,24 @@ function expandDir(dir) {
5223
5608
  }
5224
5609
  function resolveBrowserOptions(detected) {
5225
5610
  const available = detected.filter((b) => b.available !== false);
5226
- return ["none", ...available.map((b) => b.id)];
5611
+ return ["auto", "none", ...available.map((b) => b.id)];
5612
+ }
5613
+ function formatBrowserFeedback(cookiesFromBrowser, detectedBrowsers = [], defaultBrowser) {
5614
+ if (cookiesFromBrowser === "auto") {
5615
+ if (defaultBrowser) {
5616
+ return `system default: ${defaultBrowser.name} (auto-extract session cookies)`;
5617
+ }
5618
+ return "system default: none detected (falls back to cookie files)";
5619
+ }
5620
+ if (!cookiesFromBrowser || cookiesFromBrowser === "none") {
5621
+ return "manual cookie files only";
5622
+ }
5623
+ const found = detectedBrowsers.find((b) => b.id === cookiesFromBrowser);
5624
+ const browserName = found ? found.name : cookiesFromBrowser;
5625
+ return `live session cookies from ${browserName}`;
5227
5626
  }
5228
5627
  function cycleBrowserOption(current, options, forward = true) {
5229
- if (options.length === 0) return "none";
5628
+ if (options.length === 0) return "auto";
5230
5629
  const idx = options.indexOf(current);
5231
5630
  const currentIndex = idx === -1 ? 0 : idx;
5232
5631
  const nextIdx = forward ? (currentIndex + 1) % options.length : (currentIndex - 1 + options.length) % options.length;
@@ -5357,9 +5756,11 @@ function SettingsView({
5357
5756
  onCancel,
5358
5757
  doctorChecker,
5359
5758
  initialReport,
5360
- browsers: browsersProp
5759
+ browsers: browsersProp,
5760
+ defaultBrowser: defaultBrowserProp,
5761
+ initialConfig: initialConfigProp
5361
5762
  }) {
5362
- const initialConfig = useMemo2(() => loadConfig(), []);
5763
+ const initialConfig = useMemo2(() => initialConfigProp ?? loadConfig(), [initialConfigProp]);
5363
5764
  const [internalFocus, setInternalFocus] = useState6("cookies");
5364
5765
  const focusedField = controlledFocus ?? internalFocus;
5365
5766
  const setField = useCallback(
@@ -5369,6 +5770,9 @@ function SettingsView({
5369
5770
  },
5370
5771
  [onFocusChange]
5371
5772
  );
5773
+ const defaultBrowser = useMemo2(() => {
5774
+ return defaultBrowserProp !== void 0 ? defaultBrowserProp : detectSystemDefaultBrowser();
5775
+ }, [defaultBrowserProp]);
5372
5776
  const detectedBrowsers = useMemo2(() => {
5373
5777
  return browsersProp ?? listDetectedBrowsers();
5374
5778
  }, [browsersProp]);
@@ -5377,7 +5781,7 @@ function SettingsView({
5377
5781
  }, [detectedBrowsers]);
5378
5782
  const [cookiesDir, setCookiesDir] = useState6(initialConfig.cookiesDir ?? "");
5379
5783
  const [cookiesFromBrowser, setCookiesFromBrowser] = useState6(
5380
- initialConfig.cookiesFromBrowser ?? "none"
5784
+ initialConfig.cookiesFromBrowser ?? "auto"
5381
5785
  );
5382
5786
  const [downloadDir, setDownloadDir] = useState6(initialConfig.downloadDir ?? "");
5383
5787
  const [writeMetadata, setWriteMetadata] = useState6(Boolean(initialConfig.writeMetadata));
@@ -5433,13 +5837,8 @@ function SettingsView({
5433
5837
  onSave();
5434
5838
  }, [cookiesDir, cookiesFromBrowser, downloadDir, writeMetadata, defaultLimit, onSave]);
5435
5839
  const browserFeedback = useMemo2(() => {
5436
- if (!cookiesFromBrowser || cookiesFromBrowser === "none") {
5437
- return "manual cookie files only";
5438
- }
5439
- const found = detectedBrowsers.find((b) => b.id === cookiesFromBrowser);
5440
- const browserName = found ? found.name : cookiesFromBrowser;
5441
- return `live session cookies from ${browserName}`;
5442
- }, [cookiesFromBrowser, detectedBrowsers]);
5840
+ return formatBrowserFeedback(cookiesFromBrowser, detectedBrowsers, defaultBrowser);
5841
+ }, [cookiesFromBrowser, detectedBrowsers, defaultBrowser]);
5443
5842
  const cookieFeedback = useMemo2(() => {
5444
5843
  const dir = cookiesDir.trim();
5445
5844
  if (!dir) {
@@ -5483,7 +5882,7 @@ function SettingsView({
5483
5882
  }, [focusedField, setField]);
5484
5883
  const cycleBrowser = useCallback((forward = true) => {
5485
5884
  setCookiesFromBrowser((prev) => {
5486
- const next = cycleBrowserOption(prev ?? "none", browserOptions, forward);
5885
+ const next = cycleBrowserOption(prev ?? "auto", browserOptions, forward);
5487
5886
  return next;
5488
5887
  });
5489
5888
  }, [browserOptions]);
@@ -5584,7 +5983,7 @@ function SettingsView({
5584
5983
  focusedField === "browser" ? "\u25CF " : "\u25CB ",
5585
5984
  "Browser Cookie Bridge"
5586
5985
  ] }),
5587
- /* @__PURE__ */ jsx15(Text14, { color: cookiesFromBrowser && cookiesFromBrowser !== "none" ? theme.primary : theme.gray, bold: true, children: `[${(cookiesFromBrowser ?? "none").toUpperCase()}]` })
5986
+ /* @__PURE__ */ jsx15(Text14, { color: cookiesFromBrowser && cookiesFromBrowser !== "none" ? theme.primary : theme.gray, bold: true, children: `[${(cookiesFromBrowser ?? "auto").toUpperCase()}]` })
5588
5987
  ]
5589
5988
  }
5590
5989
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-nami",
3
- "version": "1.5.1",
3
+ "version": "1.6.0",
4
4
  "description": "Open Nami: terminal-first bulk social media profile downloader for Instagram, TikTok, Facebook & X.",
5
5
  "type": "module",
6
6
  "bin": {