@mkterswingman/5mghost-yonder 0.0.33 → 0.0.34

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/README.md CHANGED
@@ -18,8 +18,8 @@ The bootstrap installer:
18
18
  - installs required runtimes (`playwright`, `yt-dlp`, `ffmpeg`)
19
19
  - runs `yt-mcp setup`
20
20
  - runs `yt-mcp smoke` to verify MCP startup and authenticated remote access
21
- - first tries a headless YouTube cookie import from your local Chrome/Edge session
22
- - only asks to open a visible browser for YouTube login if the headless import fails
21
+ - opens a dedicated Playwright browser profile for YouTube login
22
+ - keeps cookie refresh inside the same dedicated profile (does not import system Chrome/Edge profiles)
23
23
  - in unattended installs, defaults to OAuth auth mode and defaults to headed cookie setup after the prompt timeout
24
24
  - in installer mode, OAuth waits up to `180s` and prints PAT fallback commands before waiting
25
25
  - if auth is still incomplete after `setup`, the installer stops before smoke tests and YouTube cookie setup instead of pretending the install fully passed
@@ -57,7 +57,7 @@ Media download runtime expectations:
57
57
  - `smoke` — run the installer smoke checks (`search_videos`, plus `validate_cookies` with `--subtitles`)
58
58
  - `runtime` — install, update, or check required runtimes
59
59
  - `check` — inspect shared auth, runtime status, and YouTube cookies
60
- - `setup-cookies` — first try importing an existing YouTube login from the most recently active local Chrome/Edge profile on macOS or Windows with a headless real-browser CDP probe, then fall back to manual browser login
60
+ - `setup-cookies` — open a dedicated Playwright browser profile for manual YouTube login and save cookies locally
61
61
  - `uninstall` — remove MCP registrations and local `~/.yt-mcp` config
62
62
  - `update` — update the main package and required runtimes
63
63
  - `version` — print the installed version
@@ -421,6 +421,9 @@ export function parseSetupCookiesArgs(argv) {
421
421
  export async function runSetupCookies(overrides = {}, options = {}) {
422
422
  const deps = buildSetupCookiesDeps(overrides);
423
423
  deps.log("\n🍪 YouTube Cookie Setup\n");
424
+ if (options.importOnly && !options.headed) {
425
+ throw new Error("setup-cookies --import-only mode is no longer supported. Use headed login instead.");
426
+ }
424
427
  deps.ensureConfigDir();
425
428
  let chromium;
426
429
  try {
@@ -429,23 +432,5 @@ export async function runSetupCookies(overrides = {}, options = {}) {
429
432
  catch {
430
433
  throw new Error("Playwright runtime is not installed.\nRun: yt-mcp runtime install");
431
434
  }
432
- if (!options.headed) {
433
- let imported = false;
434
- try {
435
- imported = await deps.tryImportBrowserCookies(chromium, deps);
436
- }
437
- catch (err) {
438
- if (!(err instanceof BrowserProfileLockedError) || options.importOnly) {
439
- throw err;
440
- }
441
- deps.log(`${err.message}\n`);
442
- }
443
- if (imported) {
444
- return;
445
- }
446
- }
447
- if (options.importOnly && !options.headed) {
448
- throw new Error("No reusable YouTube session found in local Chrome/Edge profiles");
449
- }
450
435
  await deps.runManualCookieSetup(chromium, deps);
451
436
  }
@@ -34,11 +34,24 @@ export async function downloadOneItem(input) {
34
34
  await deps.rm(input.item.output_dir, { recursive: true, force: true });
35
35
  await deps.mkdir(input.item.output_dir, { recursive: true });
36
36
  await deps.mkdir(subtitlesDir, { recursive: true });
37
- const metadata = await deps.fetchMetadata({
37
+ const metadataInput = {
38
38
  sourceUrl: input.item.source_url,
39
39
  videoId: input.item.video_id,
40
40
  title: input.item.title,
41
- });
41
+ };
42
+ let metadata;
43
+ try {
44
+ metadata = await deps.fetchMetadata(metadataInput);
45
+ }
46
+ catch (error) {
47
+ const failureKind = classifyRefreshableFailure(error);
48
+ if (failureKind != null && failureKind !== "RATE_LIMITED" && await deps.refreshCookies()) {
49
+ metadata = await deps.fetchMetadata(metadataInput);
50
+ }
51
+ else {
52
+ throw error;
53
+ }
54
+ }
42
55
  const result = {
43
56
  video_file: null,
44
57
  metadata_file: metadataFile,
@@ -63,7 +76,7 @@ export async function downloadOneItem(input) {
63
76
  });
64
77
  }
65
78
  catch (error) {
66
- const failureKind = classifyVideoDownloadError(error);
79
+ const failureKind = classifyRefreshableFailure(error);
67
80
  if (failureKind != null && failureKind !== "RATE_LIMITED" && await deps.refreshCookies()) {
68
81
  result.video_file = await deps.downloadVideo({
69
82
  sourceUrl: input.item.source_url,
@@ -311,7 +324,7 @@ function sortSubtitleFiles(files) {
311
324
  .sort(([left], [right]) => left.localeCompare(right))
312
325
  .map(([format, paths]) => [format, [...paths].sort()]));
313
326
  }
314
- function classifyVideoDownloadError(error) {
327
+ function classifyRefreshableFailure(error) {
315
328
  const message = error instanceof Error ? error.message : String(error);
316
329
  return classifyYtDlpFailure(message);
317
330
  }
@@ -1,19 +1,15 @@
1
1
  /**
2
- * Cookie auto-refresh with three-tier fallback.
2
+ * Cookie auto-refresh with two-tier fallback.
3
3
  *
4
4
  * Tier 1: Headless Playwright refresh using existing browser-profile.
5
5
  * If Google session is still valid, cookies are extracted automatically.
6
6
  *
7
- * Tier 2: Re-import from system Chrome/Edge (headless, about:blank).
8
- * Copies the real browser profile to a temp dir and reads cookies via CDP
9
- * without making any network requests (avoids Google token rotation).
10
- *
11
- * Tier 3: Open a headed browser for manual user login.
7
+ * Tier 2: Open a headed browser for manual user login.
12
8
  * Blocks the MCP tool call for up to ~2 minutes while the user logs in.
13
- * Creates browser-profile so Tier 1 works next time.
9
+ * Uses the dedicated yt-mcp profile so refresh never touches system profiles.
14
10
  */
15
11
  /**
16
- * Attempt to refresh YouTube cookies through a three-tier fallback chain.
12
+ * Attempt to refresh YouTube cookies through the dedicated two-tier fallback chain.
17
13
  *
18
14
  * @returns true if cookies were refreshed, false if all tiers failed.
19
15
  */
@@ -1,16 +1,12 @@
1
1
  /**
2
- * Cookie auto-refresh with three-tier fallback.
2
+ * Cookie auto-refresh with two-tier fallback.
3
3
  *
4
4
  * Tier 1: Headless Playwright refresh using existing browser-profile.
5
5
  * If Google session is still valid, cookies are extracted automatically.
6
6
  *
7
- * Tier 2: Re-import from system Chrome/Edge (headless, about:blank).
8
- * Copies the real browser profile to a temp dir and reads cookies via CDP
9
- * without making any network requests (avoids Google token rotation).
10
- *
11
- * Tier 3: Open a headed browser for manual user login.
7
+ * Tier 2: Open a headed browser for manual user login.
12
8
  * Blocks the MCP tool call for up to ~2 minutes while the user logs in.
13
- * Creates browser-profile so Tier 1 works next time.
9
+ * Uses the dedicated yt-mcp profile so refresh never touches system profiles.
14
10
  */
15
11
  import { existsSync } from "node:fs";
16
12
  import { PATHS, ensureConfigDir } from "./config.js";
@@ -18,7 +14,7 @@ import { detectBrowserChannel, hasYouTubeSession, saveCookiesToDisk, } from "../
18
14
  import { hasSIDCookies } from "./cookies.js";
19
15
  const HEADLESS_TIMEOUT_MS = 30_000;
20
16
  /**
21
- * Attempt to refresh YouTube cookies through a three-tier fallback chain.
17
+ * Attempt to refresh YouTube cookies through the dedicated two-tier fallback chain.
22
18
  *
23
19
  * @returns true if cookies were refreshed, false if all tiers failed.
24
20
  */
@@ -30,13 +26,8 @@ export async function tryHeadlessRefresh() {
30
26
  if (tier1)
31
27
  return true;
32
28
  }
33
- // Tier 2: Re-import from system browser (headless, no network requests)
34
- const tier2 = await tryReimportFromSystemBrowser();
35
- if (tier2)
36
- return true;
37
- // Tier 3: Open headed browser for manual login
38
- const tier3 = await tryHeadedManualLogin();
39
- return tier3;
29
+ // Tier 2: Open headed browser for manual login
30
+ return tryHeadedManualLogin();
40
31
  }
41
32
  /**
42
33
  * Tier 1: Use existing browser-profile with Playwright to refresh cookies.
@@ -84,42 +75,9 @@ async function tryPlaywrightRefresh() {
84
75
  }
85
76
  }
86
77
  /**
87
- * Tier 2: Re-import cookies from the user's system Chrome/Edge.
88
- * Uses headless Chrome with about:blank to avoid triggering Google token rotation.
89
- */
90
- async function tryReimportFromSystemBrowser() {
91
- try {
92
- const pw = await import("playwright");
93
- const { tryImportBrowserCookies, saveCookiesAndClose, readImportedBrowserCookies, } = await import("../cli/setupCookies.js");
94
- const { findImportableBrowserProfileCandidates, prepareImportedBrowserWorkspace, cleanupImportedBrowserWorkspace, } = await import("./browserProfileImport.js");
95
- const deps = {
96
- ensureConfigDir,
97
- loadChromium: async () => pw.chromium,
98
- detectBrowserChannel,
99
- hasYouTubeSession,
100
- saveCookiesAndClose,
101
- // Why: waitForLogin is unused in import path but required by SetupCookiesDeps type
102
- waitForLogin: async () => null,
103
- findImportableBrowserProfileCandidates,
104
- prepareImportedBrowserWorkspace,
105
- cleanupImportedBrowserWorkspace,
106
- readImportedBrowserCookies,
107
- tryImportBrowserCookies,
108
- // Why: runManualCookieSetup is unused in import path but required by type
109
- runManualCookieSetup: async () => { },
110
- // Why: silent logging during auto-refresh — user doesn't see MCP server stdout
111
- log: () => { },
112
- };
113
- return await tryImportBrowserCookies(pw.chromium, deps);
114
- }
115
- catch {
116
- return false;
117
- }
118
- }
119
- /**
120
- * Tier 3: Open a headed browser for the user to manually log in.
78
+ * Tier 2: Open a headed browser for the user to manually log in.
121
79
  * Blocks the MCP tool call for up to ~2 minutes.
122
- * Creates browser-profile so Tier 1 works for future refreshes.
80
+ * Uses the dedicated yt-mcp browser-profile for future Tier 1 refreshes.
123
81
  */
124
82
  async function tryHeadedManualLogin() {
125
83
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mkterswingman/5mghost-yonder",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "description": "Internal MCP client with local data tools and remote API proxy",
5
5
  "type": "module",
6
6
  "bin": {