summd 0.1.5 → 0.1.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/url-to-md.js +51 -19
  2. package/package.json +1 -1
package/dist/url-to-md.js CHANGED
@@ -78,29 +78,61 @@ async function fetchYouTubeTitle(url, videoId) {
78
78
  catch { }
79
79
  return `YouTube: ${videoId}`;
80
80
  }
81
- // yt-dlpworks from any IP, supports auth/geo-block via --cookies-from-browser
81
+ // Browser cookie sources tried in order, first one that succeeds is used.
82
+ // Cookies bypass bot-detection and geo-blocks; required on most IPs.
83
+ const BROWSERS = ['chrome', 'chromium', 'firefox', 'safari', 'edge'];
84
+ // yt-dlp — uses browser cookies by default; falls back to no-cookies for public videos.
85
+ // --sub-langs all: accept whatever subtitle language the video provides, no preference.
82
86
  async function ytDlpTranscript(url, videoId) {
83
87
  const dir = tmpdir();
84
- const outTemplate = join(dir, videoId); // output: {videoId}.en.json3
85
- try {
86
- await execFileAsync('yt-dlp', [
87
- '--write-subs',
88
- '--write-auto-subs',
89
- '--sub-langs', 'en',
90
- '--sub-format', 'json3',
91
- '--skip-download',
92
- '--quiet',
93
- '--no-progress',
94
- '-o', outTemplate,
95
- url,
96
- ], { timeout: 30_000 });
88
+ const outTemplate = join(dir, videoId);
89
+ const run = (cookieArgs) => execFileAsync('yt-dlp', [
90
+ '--write-subs',
91
+ '--write-auto-subs',
92
+ '--sub-langs', 'all', // accept any language — no hardcoded preference
93
+ '--sub-format', 'json3',
94
+ '--skip-download',
95
+ '--quiet',
96
+ '--no-progress',
97
+ ...cookieArgs,
98
+ '-o', outTemplate,
99
+ url,
100
+ ], { timeout: 30_000 });
101
+ // Try with browser cookies first (handles bot-detection, auth, geo-block).
102
+ // Fall back to no-cookies only if no browser is available.
103
+ let ran = false;
104
+ for (const browser of BROWSERS) {
105
+ try {
106
+ await run(['--cookies-from-browser', browser]);
107
+ ran = true;
108
+ break;
109
+ }
110
+ catch (e) {
111
+ const err = e;
112
+ if (err.code === 'ENOENT')
113
+ return { transcript: null, reason: 'not-installed' };
114
+ const stderr = err.stderr ?? '';
115
+ // Cookie access failed (browser not installed / locked DB) — try next browser
116
+ if (stderr.includes('browser') || stderr.includes('cookie') || stderr.includes('Could not find'))
117
+ continue;
118
+ // yt-dlp ran but failed for another reason (video unavailable, no captions…)
119
+ ran = true;
120
+ break;
121
+ }
97
122
  }
98
- catch (e) {
99
- // Distinguish "yt-dlp not in PATH" from "ran but video has no captions"
100
- const isNotFound = e.code === 'ENOENT';
101
- return { transcript: null, reason: isNotFound ? 'not-installed' : 'no-transcript' };
123
+ // No browser found with usable cookies — try without (works for fully public videos)
124
+ if (!ran) {
125
+ try {
126
+ await run([]);
127
+ }
128
+ catch (e) {
129
+ const err = e;
130
+ if (err.code === 'ENOENT')
131
+ return { transcript: null, reason: 'not-installed' };
132
+ return { transcript: null, reason: 'no-transcript' };
133
+ }
102
134
  }
103
- // Find output file: {videoId}.en.json3, {videoId}.en-US.json3, etc.
135
+ // Read the first valid output file; clean up all temp files regardless
104
136
  try {
105
137
  const files = readdirSync(dir).filter(f => f.startsWith(videoId) && f.endsWith('.json3'));
106
138
  for (const file of files) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "summd",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "CLI for sum.md — Sum to anything.",
5
5
  "license": "MIT",
6
6
  "bin": {