offcourse 1.0.0 → 1.1.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 (280) hide show
  1. package/README.md +107 -8
  2. package/dist/cli/commands/config.js.map +1 -1
  3. package/dist/cli/commands/inspect.js +1 -1
  4. package/dist/cli/commands/inspect.js.map +1 -1
  5. package/dist/cli/commands/sync.d.ts +1 -2
  6. package/dist/cli/commands/sync.d.ts.map +1 -1
  7. package/dist/cli/commands/sync.js +17 -15
  8. package/dist/cli/commands/sync.js.map +1 -1
  9. package/dist/cli/commands/syncHighLevel.d.ts +1 -2
  10. package/dist/cli/commands/syncHighLevel.d.ts.map +1 -1
  11. package/dist/cli/commands/syncHighLevel.js +8 -9
  12. package/dist/cli/commands/syncHighLevel.js.map +1 -1
  13. package/dist/cli/commands/syncLearningSuite.d.ts +35 -0
  14. package/dist/cli/commands/syncLearningSuite.d.ts.map +1 -0
  15. package/dist/cli/commands/syncLearningSuite.js +765 -0
  16. package/dist/cli/commands/syncLearningSuite.js.map +1 -0
  17. package/dist/cli/index.js +39 -1
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/config/configManager.d.ts.map +1 -1
  20. package/dist/config/configManager.js +4 -0
  21. package/dist/config/configManager.js.map +1 -1
  22. package/dist/downloader/hlsDownloader.d.ts +10 -4
  23. package/dist/downloader/hlsDownloader.d.ts.map +1 -1
  24. package/dist/downloader/hlsDownloader.js +60 -29
  25. package/dist/downloader/hlsDownloader.js.map +1 -1
  26. package/dist/downloader/hlsValidator.d.ts.map +1 -1
  27. package/dist/downloader/hlsValidator.js +6 -2
  28. package/dist/downloader/hlsValidator.js.map +1 -1
  29. package/dist/downloader/index.d.ts +7 -0
  30. package/dist/downloader/index.d.ts.map +1 -1
  31. package/dist/downloader/index.js +9 -6
  32. package/dist/downloader/index.js.map +1 -1
  33. package/dist/downloader/loomDownloader.d.ts +1 -1
  34. package/dist/downloader/loomDownloader.d.ts.map +1 -1
  35. package/dist/downloader/loomDownloader.js +32 -27
  36. package/dist/downloader/loomDownloader.js.map +1 -1
  37. package/dist/downloader/queue.d.ts +4 -4
  38. package/dist/downloader/queue.d.ts.map +1 -1
  39. package/dist/downloader/queue.js.map +1 -1
  40. package/dist/downloader/vimeoDownloader.d.ts.map +1 -1
  41. package/dist/downloader/vimeoDownloader.js +7 -3
  42. package/dist/downloader/vimeoDownloader.js.map +1 -1
  43. package/dist/scraper/extractor.d.ts +4 -0
  44. package/dist/scraper/extractor.d.ts.map +1 -1
  45. package/dist/scraper/extractor.js +79 -79
  46. package/dist/scraper/extractor.js.map +1 -1
  47. package/dist/scraper/highlevel/extractor.d.ts +11 -19
  48. package/dist/scraper/highlevel/extractor.d.ts.map +1 -1
  49. package/dist/scraper/highlevel/extractor.js +72 -85
  50. package/dist/scraper/highlevel/extractor.js.map +1 -1
  51. package/dist/scraper/highlevel/navigator.d.ts +3 -10
  52. package/dist/scraper/highlevel/navigator.d.ts.map +1 -1
  53. package/dist/scraper/highlevel/navigator.js +140 -127
  54. package/dist/scraper/highlevel/navigator.js.map +1 -1
  55. package/dist/scraper/highlevel/schemas.d.ts +188 -0
  56. package/dist/scraper/highlevel/schemas.d.ts.map +1 -0
  57. package/dist/scraper/highlevel/schemas.js +139 -0
  58. package/dist/scraper/highlevel/schemas.js.map +1 -0
  59. package/dist/scraper/learningsuite/extractor.d.ts +50 -0
  60. package/dist/scraper/learningsuite/extractor.d.ts.map +1 -0
  61. package/dist/scraper/learningsuite/extractor.js +429 -0
  62. package/dist/scraper/learningsuite/extractor.js.map +1 -0
  63. package/dist/scraper/learningsuite/index.d.ts +4 -0
  64. package/dist/scraper/learningsuite/index.d.ts.map +1 -0
  65. package/dist/scraper/{ghl → learningsuite}/index.js +1 -1
  66. package/dist/scraper/learningsuite/index.js.map +1 -0
  67. package/dist/scraper/learningsuite/navigator.d.ts +122 -0
  68. package/dist/scraper/learningsuite/navigator.d.ts.map +1 -0
  69. package/dist/scraper/learningsuite/navigator.js +736 -0
  70. package/dist/scraper/learningsuite/navigator.js.map +1 -0
  71. package/dist/scraper/learningsuite/schemas.d.ts +270 -0
  72. package/dist/scraper/learningsuite/schemas.d.ts.map +1 -0
  73. package/dist/scraper/learningsuite/schemas.js +147 -0
  74. package/dist/scraper/learningsuite/schemas.js.map +1 -0
  75. package/dist/scraper/navigator.d.ts +14 -11
  76. package/dist/scraper/navigator.d.ts.map +1 -1
  77. package/dist/scraper/navigator.js +61 -104
  78. package/dist/scraper/navigator.js.map +1 -1
  79. package/dist/scraper/schemas.d.ts +57 -0
  80. package/dist/scraper/schemas.d.ts.map +1 -0
  81. package/dist/scraper/schemas.js +135 -0
  82. package/dist/scraper/schemas.js.map +1 -0
  83. package/dist/scraper/videoInterceptor.d.ts +4 -0
  84. package/dist/scraper/videoInterceptor.d.ts.map +1 -1
  85. package/dist/scraper/videoInterceptor.js +66 -51
  86. package/dist/scraper/videoInterceptor.js.map +1 -1
  87. package/dist/shared/auth.d.ts +9 -9
  88. package/dist/shared/auth.d.ts.map +1 -1
  89. package/dist/shared/auth.js +24 -38
  90. package/dist/shared/auth.js.map +1 -1
  91. package/dist/shared/firebase.d.ts +60 -0
  92. package/dist/shared/firebase.d.ts.map +1 -0
  93. package/dist/shared/firebase.js +102 -0
  94. package/dist/shared/firebase.js.map +1 -0
  95. package/dist/shared/fs.d.ts.map +1 -1
  96. package/dist/shared/fs.js +4 -0
  97. package/dist/shared/fs.js.map +1 -1
  98. package/dist/shared/index.d.ts +3 -0
  99. package/dist/shared/index.d.ts.map +1 -1
  100. package/dist/shared/index.js +3 -0
  101. package/dist/shared/index.js.map +1 -1
  102. package/dist/shared/slug.d.ts +11 -0
  103. package/dist/shared/slug.d.ts.map +1 -0
  104. package/{src/shared/slug.ts → dist/shared/slug.js} +10 -11
  105. package/dist/shared/slug.js.map +1 -0
  106. package/dist/shared/url.d.ts +43 -0
  107. package/dist/shared/url.d.ts.map +1 -0
  108. package/{src/shared/url.ts → dist/shared/url.js} +12 -15
  109. package/dist/shared/url.js.map +1 -0
  110. package/dist/state/database.d.ts +1 -0
  111. package/dist/state/database.d.ts.map +1 -1
  112. package/dist/state/database.js +3 -0
  113. package/dist/state/database.js.map +1 -1
  114. package/dist/storage/fileSystem.d.ts +17 -17
  115. package/dist/storage/fileSystem.d.ts.map +1 -1
  116. package/dist/storage/fileSystem.js +39 -31
  117. package/dist/storage/fileSystem.js.map +1 -1
  118. package/package.json +5 -2
  119. package/.github/workflows/ci.yml +0 -50
  120. package/.husky/commit-msg +0 -2
  121. package/.husky/pre-commit +0 -1
  122. package/.husky/pre-push +0 -3
  123. package/.prettierrc +0 -8
  124. package/.release-it.json +0 -23
  125. package/ARCHITECTURE.md +0 -233
  126. package/CHANGELOG.md +0 -78
  127. package/commitlint.config.js +0 -4
  128. package/dist/ai/openRouter.d.ts +0 -47
  129. package/dist/ai/openRouter.d.ts.map +0 -1
  130. package/dist/ai/openRouter.js +0 -116
  131. package/dist/ai/openRouter.js.map +0 -1
  132. package/dist/ai/transcriptPolisher.d.ts +0 -24
  133. package/dist/ai/transcriptPolisher.d.ts.map +0 -1
  134. package/dist/ai/transcriptPolisher.js +0 -89
  135. package/dist/ai/transcriptPolisher.js.map +0 -1
  136. package/dist/cli/commands/enrich.d.ts +0 -14
  137. package/dist/cli/commands/enrich.d.ts.map +0 -1
  138. package/dist/cli/commands/enrich.js +0 -271
  139. package/dist/cli/commands/enrich.js.map +0 -1
  140. package/dist/cli/commands/syncGhl.d.ts +0 -20
  141. package/dist/cli/commands/syncGhl.d.ts.map +0 -1
  142. package/dist/cli/commands/syncGhl.js +0 -483
  143. package/dist/cli/commands/syncGhl.js.map +0 -1
  144. package/dist/cli/commands/syncHighLevel.test.d.ts +0 -2
  145. package/dist/cli/commands/syncHighLevel.test.d.ts.map +0 -1
  146. package/dist/cli/commands/syncHighLevel.test.js +0 -102
  147. package/dist/cli/commands/syncHighLevel.test.js.map +0 -1
  148. package/dist/config/paths.test.d.ts +0 -2
  149. package/dist/config/paths.test.d.ts.map +0 -1
  150. package/dist/config/paths.test.js +0 -70
  151. package/dist/config/paths.test.js.map +0 -1
  152. package/dist/config/schema.test.d.ts +0 -2
  153. package/dist/config/schema.test.d.ts.map +0 -1
  154. package/dist/config/schema.test.js +0 -151
  155. package/dist/config/schema.test.js.map +0 -1
  156. package/dist/downloader/hlsDownloader.test.d.ts +0 -2
  157. package/dist/downloader/hlsDownloader.test.d.ts.map +0 -1
  158. package/dist/downloader/hlsDownloader.test.js +0 -116
  159. package/dist/downloader/hlsDownloader.test.js.map +0 -1
  160. package/dist/downloader/loomDownloader.test.d.ts +0 -2
  161. package/dist/downloader/loomDownloader.test.d.ts.map +0 -1
  162. package/dist/downloader/loomDownloader.test.js +0 -36
  163. package/dist/downloader/loomDownloader.test.js.map +0 -1
  164. package/dist/downloader/queue.test.d.ts +0 -2
  165. package/dist/downloader/queue.test.d.ts.map +0 -1
  166. package/dist/downloader/queue.test.js +0 -158
  167. package/dist/downloader/queue.test.js.map +0 -1
  168. package/dist/downloader/videoDownloader.d.ts +0 -32
  169. package/dist/downloader/videoDownloader.d.ts.map +0 -1
  170. package/dist/downloader/videoDownloader.js +0 -173
  171. package/dist/downloader/videoDownloader.js.map +0 -1
  172. package/dist/downloader/vimeoDownloader.test.d.ts +0 -2
  173. package/dist/downloader/vimeoDownloader.test.d.ts.map +0 -1
  174. package/dist/downloader/vimeoDownloader.test.js +0 -51
  175. package/dist/downloader/vimeoDownloader.test.js.map +0 -1
  176. package/dist/scraper/auth.d.ts +0 -29
  177. package/dist/scraper/auth.d.ts.map +0 -1
  178. package/dist/scraper/auth.js +0 -115
  179. package/dist/scraper/auth.js.map +0 -1
  180. package/dist/scraper/extractor.test.d.ts +0 -2
  181. package/dist/scraper/extractor.test.d.ts.map +0 -1
  182. package/dist/scraper/extractor.test.js +0 -65
  183. package/dist/scraper/extractor.test.js.map +0 -1
  184. package/dist/scraper/ghl/auth.d.ts +0 -25
  185. package/dist/scraper/ghl/auth.d.ts.map +0 -1
  186. package/dist/scraper/ghl/auth.js +0 -187
  187. package/dist/scraper/ghl/auth.js.map +0 -1
  188. package/dist/scraper/ghl/extractor.d.ts +0 -96
  189. package/dist/scraper/ghl/extractor.d.ts.map +0 -1
  190. package/dist/scraper/ghl/extractor.js +0 -345
  191. package/dist/scraper/ghl/extractor.js.map +0 -1
  192. package/dist/scraper/ghl/index.d.ts +0 -4
  193. package/dist/scraper/ghl/index.d.ts.map +0 -1
  194. package/dist/scraper/ghl/index.js.map +0 -1
  195. package/dist/scraper/ghl/navigator.d.ts +0 -93
  196. package/dist/scraper/ghl/navigator.d.ts.map +0 -1
  197. package/dist/scraper/ghl/navigator.js +0 -447
  198. package/dist/scraper/ghl/navigator.js.map +0 -1
  199. package/dist/scraper/highlevel/auth.d.ts +0 -25
  200. package/dist/scraper/highlevel/auth.d.ts.map +0 -1
  201. package/dist/scraper/highlevel/auth.js +0 -189
  202. package/dist/scraper/highlevel/auth.js.map +0 -1
  203. package/dist/scraper/highlevel/extractor.test.d.ts +0 -2
  204. package/dist/scraper/highlevel/extractor.test.d.ts.map +0 -1
  205. package/dist/scraper/highlevel/extractor.test.js +0 -101
  206. package/dist/scraper/highlevel/extractor.test.js.map +0 -1
  207. package/dist/scraper/highlevel/navigator.test.d.ts +0 -2
  208. package/dist/scraper/highlevel/navigator.test.d.ts.map +0 -1
  209. package/dist/scraper/highlevel/navigator.test.js +0 -78
  210. package/dist/scraper/highlevel/navigator.test.js.map +0 -1
  211. package/dist/scraper/navigator.test.d.ts +0 -2
  212. package/dist/scraper/navigator.test.d.ts.map +0 -1
  213. package/dist/scraper/navigator.test.js +0 -63
  214. package/dist/scraper/navigator.test.js.map +0 -1
  215. package/dist/scraper/skoolApi.d.ts +0 -17
  216. package/dist/scraper/skoolApi.d.ts.map +0 -1
  217. package/dist/scraper/skoolApi.js +0 -72
  218. package/dist/scraper/skoolApi.js.map +0 -1
  219. package/dist/state/database.test.d.ts +0 -2
  220. package/dist/state/database.test.d.ts.map +0 -1
  221. package/dist/state/database.test.js +0 -34
  222. package/dist/state/database.test.js.map +0 -1
  223. package/dist/transcription/whisperService.d.ts +0 -27
  224. package/dist/transcription/whisperService.d.ts.map +0 -1
  225. package/dist/transcription/whisperService.js +0 -102
  226. package/dist/transcription/whisperService.js.map +0 -1
  227. package/eslint.config.js +0 -55
  228. package/src/__fixtures__/highlevel-post-response.json +0 -68
  229. package/src/__fixtures__/hls-master-playlist.m3u8 +0 -24
  230. package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +0 -38
  231. package/src/cli/commands/config.ts +0 -74
  232. package/src/cli/commands/inspect.ts +0 -441
  233. package/src/cli/commands/login.ts +0 -68
  234. package/src/cli/commands/status.ts +0 -147
  235. package/src/cli/commands/sync.ts +0 -1235
  236. package/src/cli/commands/syncHighLevel.test.ts +0 -144
  237. package/src/cli/commands/syncHighLevel.ts +0 -639
  238. package/src/cli/index.ts +0 -121
  239. package/src/config/configManager.ts +0 -75
  240. package/src/config/paths.test.ts +0 -83
  241. package/src/config/paths.ts +0 -36
  242. package/src/config/schema.test.ts +0 -173
  243. package/src/config/schema.ts +0 -65
  244. package/src/downloader/hlsDownloader.test.ts +0 -148
  245. package/src/downloader/hlsDownloader.ts +0 -327
  246. package/src/downloader/hlsValidator.ts +0 -196
  247. package/src/downloader/index.ts +0 -122
  248. package/src/downloader/loomDownloader.test.ts +0 -43
  249. package/src/downloader/loomDownloader.ts +0 -742
  250. package/src/downloader/queue.test.ts +0 -199
  251. package/src/downloader/queue.ts +0 -118
  252. package/src/downloader/vimeoDownloader.test.ts +0 -62
  253. package/src/downloader/vimeoDownloader.ts +0 -722
  254. package/src/scraper/extractor.test.ts +0 -124
  255. package/src/scraper/extractor.ts +0 -757
  256. package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +0 -41
  257. package/src/scraper/highlevel/extractor.test.ts +0 -134
  258. package/src/scraper/highlevel/extractor.ts +0 -537
  259. package/src/scraper/highlevel/index.ts +0 -2
  260. package/src/scraper/highlevel/navigator.test.ts +0 -110
  261. package/src/scraper/highlevel/navigator.ts +0 -668
  262. package/src/scraper/highlevel/schemas.ts +0 -183
  263. package/src/scraper/navigator.test.ts +0 -122
  264. package/src/scraper/navigator.ts +0 -355
  265. package/src/scraper/schemas.ts +0 -177
  266. package/src/scraper/videoInterceptor.ts +0 -435
  267. package/src/shared/auth.test.ts +0 -58
  268. package/src/shared/auth.ts +0 -251
  269. package/src/shared/firebase.ts +0 -151
  270. package/src/shared/fs.ts +0 -80
  271. package/src/shared/http.ts +0 -34
  272. package/src/shared/index.ts +0 -6
  273. package/src/shared/url.test.ts +0 -122
  274. package/src/state/database.test.ts +0 -49
  275. package/src/state/database.ts +0 -919
  276. package/src/state/index.ts +0 -14
  277. package/src/storage/fileSystem.test.ts +0 -64
  278. package/src/storage/fileSystem.ts +0 -175
  279. package/tsconfig.json +0 -28
  280. package/vitest.config.ts +0 -29
@@ -1,173 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- /**
4
- * Checks if yt-dlp is available on the system.
5
- */
6
- export async function isYtDlpAvailable() {
7
- return new Promise((resolve) => {
8
- const proc = spawn("yt-dlp", ["--version"], { shell: true });
9
- proc.on("close", (code) => {
10
- resolve(code === 0);
11
- });
12
- proc.on("error", () => {
13
- resolve(false);
14
- });
15
- });
16
- }
17
- /**
18
- * Maps our quality setting to yt-dlp format selector.
19
- */
20
- function getFormatSelector(quality) {
21
- const qualityMap = {
22
- highest: "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best",
23
- lowest: "worstvideo[ext=mp4]+worstaudio[ext=m4a]/worst[ext=mp4]/worst",
24
- "1080p": "bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[height<=1080][ext=mp4]",
25
- "720p": "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]",
26
- "480p": "bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best[height<=480][ext=mp4]",
27
- };
28
- return qualityMap[quality];
29
- }
30
- /**
31
- * Normalizes various video URLs to formats yt-dlp can handle.
32
- */
33
- export function normalizeVideoUrl(embedUrl, videoType) {
34
- switch (videoType) {
35
- case "loom": {
36
- // Convert Loom embed URL to regular URL
37
- // https://www.loom.com/embed/abc123 -> https://www.loom.com/share/abc123
38
- const videoId = embedUrl.match(/loom\.com\/embed\/([a-f0-9]+)/)?.[1];
39
- if (videoId) {
40
- return `https://www.loom.com/share/${videoId}`;
41
- }
42
- return embedUrl;
43
- }
44
- case "vimeo": {
45
- // Convert Vimeo player URL to regular URL
46
- // https://player.vimeo.com/video/123456 -> https://vimeo.com/123456
47
- const videoId = embedUrl.match(/vimeo\.com\/(?:video\/)?(\d+)/)?.[1];
48
- if (videoId) {
49
- return `https://vimeo.com/${videoId}`;
50
- }
51
- return embedUrl;
52
- }
53
- case "youtube": {
54
- // Convert YouTube embed URL to regular URL
55
- // https://www.youtube.com/embed/abc123 -> https://www.youtube.com/watch?v=abc123
56
- const videoId = embedUrl.match(/(?:embed\/|v=|youtu\.be\/)([^?&]+)/)?.[1];
57
- if (videoId) {
58
- return `https://www.youtube.com/watch?v=${videoId}`;
59
- }
60
- return embedUrl;
61
- }
62
- default:
63
- return embedUrl;
64
- }
65
- }
66
- /**
67
- * Downloads a video using yt-dlp.
68
- */
69
- export async function downloadVideo(url, outputPath, options = {}) {
70
- const { quality = "highest", videoType, onProgress } = options;
71
- // Check if already downloaded
72
- if (existsSync(outputPath)) {
73
- return {
74
- success: true,
75
- filePath: outputPath,
76
- error: null,
77
- };
78
- }
79
- // Normalize the URL for yt-dlp
80
- const normalizedUrl = normalizeVideoUrl(url, videoType ?? null);
81
- const args = [
82
- normalizedUrl,
83
- "-f",
84
- getFormatSelector(quality),
85
- "-o",
86
- outputPath,
87
- "--no-playlist",
88
- "--no-warnings",
89
- "--progress",
90
- "--newline", // Print progress on new lines
91
- ];
92
- // Add referer for embedded videos
93
- if (videoType === "loom") {
94
- args.push("--referer", "https://www.skool.com/");
95
- }
96
- else if (videoType === "vimeo") {
97
- args.push("--referer", "https://www.skool.com/");
98
- }
99
- return new Promise((resolve) => {
100
- const proc = spawn("yt-dlp", args, { shell: true });
101
- let errorOutput = "";
102
- proc.stdout.on("data", (data) => {
103
- const output = data.toString();
104
- // Parse progress from yt-dlp output
105
- // Format: [download] 45.2% of 123.45MiB at 1.23MiB/s ETA 01:23
106
- const progressMatch = output.match(/(\d+\.?\d*)%/);
107
- if (progressMatch?.[1] && onProgress) {
108
- onProgress(parseFloat(progressMatch[1]));
109
- }
110
- });
111
- proc.stderr.on("data", (data) => {
112
- errorOutput += data.toString();
113
- });
114
- proc.on("close", (code) => {
115
- if (code === 0 && existsSync(outputPath)) {
116
- resolve({
117
- success: true,
118
- filePath: outputPath,
119
- error: null,
120
- });
121
- }
122
- else {
123
- resolve({
124
- success: false,
125
- filePath: null,
126
- error: errorOutput || `yt-dlp exited with code ${code}`,
127
- });
128
- }
129
- });
130
- proc.on("error", (err) => {
131
- resolve({
132
- success: false,
133
- filePath: null,
134
- error: err.message,
135
- });
136
- });
137
- });
138
- }
139
- /**
140
- * Gets video info without downloading.
141
- */
142
- export async function getVideoInfo(url, videoType) {
143
- const normalizedUrl = normalizeVideoUrl(url, videoType);
144
- return new Promise((resolve) => {
145
- const proc = spawn("yt-dlp", ["--dump-json", "--no-warnings", normalizedUrl], { shell: true });
146
- let output = "";
147
- proc.stdout.on("data", (data) => {
148
- output += data.toString();
149
- });
150
- proc.on("close", (code) => {
151
- if (code === 0) {
152
- try {
153
- const info = JSON.parse(output);
154
- resolve({
155
- title: info.title ?? "Unknown",
156
- duration: info.duration ?? 0,
157
- formats: info.formats?.map((f) => f.format_id) ?? [],
158
- });
159
- }
160
- catch {
161
- resolve(null);
162
- }
163
- }
164
- else {
165
- resolve(null);
166
- }
167
- });
168
- proc.on("error", () => {
169
- resolve(null);
170
- });
171
- });
172
- }
173
- //# sourceMappingURL=videoDownloader.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"videoDownloader.js","sourceRoot":"","sources":["../../src/downloader/videoDownloader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AASrC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAE7D,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,OAAO,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACpB,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,OAAqB;IAC9C,MAAM,UAAU,GAAiC;QAC/C,OAAO,EAAE,0DAA0D;QACnE,MAAM,EAAE,8DAA8D;QACtE,OAAO,EAAE,iFAAiF;QAC1F,MAAM,EAAE,+EAA+E;QACvF,MAAM,EAAE,+EAA+E;KACxF,CAAC;IAEF,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,SAAgF;IAEhF,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,wCAAwC;YACxC,yEAAyE;YACzE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,8BAA8B,OAAO,EAAE,CAAC;YACjD,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,0CAA0C;YAC1C,oEAAoE;YACpE,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,+BAA+B,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrE,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,qBAAqB,OAAO,EAAE,CAAC;YACxC,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,2CAA2C;YAC3C,iFAAiF;YACjF,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,oCAAoC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC1E,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,mCAAmC,OAAO,EAAE,CAAC;YACtD,CAAC;YACD,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED;YACE,OAAO,QAAQ,CAAC;IACpB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAW,EACX,UAAkB,EAClB,UAKI,EAAE;IAEN,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAE/D,8BAA8B;IAC9B,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,UAAU;YACpB,KAAK,EAAE,IAAI;SACZ,CAAC;IACJ,CAAC;IAED,+BAA+B;IAC/B,MAAM,aAAa,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,IAAI,IAAI,CAAC,CAAC;IAEhE,MAAM,IAAI,GAAG;QACX,aAAa;QACb,IAAI;QACJ,iBAAiB,CAAC,OAAO,CAAC;QAC1B,IAAI;QACJ,UAAU;QACV,eAAe;QACf,eAAe;QACf,YAAY;QACZ,WAAW,EAAE,8BAA8B;KAC5C,CAAC;IAEF,kCAAkC;IAClC,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,wBAAwB,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpD,IAAI,WAAW,GAAG,EAAE,CAAC;QAErB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACtC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YAE/B,oCAAoC;YACpC,gEAAgE;YAChE,MAAM,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;YACnD,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC,IAAI,UAAU,EAAE,CAAC;gBACrC,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACtC,WAAW,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBACzC,OAAO,CAAC;oBACN,OAAO,EAAE,IAAI;oBACb,QAAQ,EAAE,UAAU;oBACpB,KAAK,EAAE,IAAI;iBACZ,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC;oBACN,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,IAAI;oBACd,KAAK,EAAE,WAAW,IAAI,2BAA2B,IAAI,EAAE;iBACxD,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,OAAO,CAAC;gBACN,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,GAAG,CAAC,OAAO;aACnB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAW,EACX,SAAgF;IAEhF,MAAM,aAAa,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAExD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,aAAa,EAAE,eAAe,EAAE,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/F,IAAI,MAAM,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACtC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAI7B,CAAC;oBACF,OAAO,CAAC;wBACN,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,SAAS;wBAC9B,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,CAAC;wBAC5B,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE;qBACrD,CAAC,CAAC;gBACL,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACpB,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=vimeoDownloader.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vimeoDownloader.test.d.ts","sourceRoot":"","sources":["../../src/downloader/vimeoDownloader.test.ts"],"names":[],"mappings":""}
@@ -1,51 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { extractVimeoId } from "./vimeoDownloader.js";
3
- describe("extractVimeoId", () => {
4
- it("extracts ID from standard vimeo.com URL", () => {
5
- const url = "https://vimeo.com/123456789";
6
- expect(extractVimeoId(url)).toBe("123456789");
7
- });
8
- it("extracts ID from vimeo.com/video URL", () => {
9
- const url = "https://vimeo.com/video/123456789";
10
- expect(extractVimeoId(url)).toBe("123456789");
11
- });
12
- it("extracts ID from player.vimeo.com URL", () => {
13
- const url = "https://player.vimeo.com/video/987654321";
14
- expect(extractVimeoId(url)).toBe("987654321");
15
- });
16
- it("extracts ID from channel URL", () => {
17
- const url = "https://vimeo.com/channels/staffpicks/123456789";
18
- expect(extractVimeoId(url)).toBe("123456789");
19
- });
20
- it("extracts ID from groups URL", () => {
21
- const url = "https://vimeo.com/groups/shortfilms/videos/123456789";
22
- expect(extractVimeoId(url)).toBe("123456789");
23
- });
24
- it("extracts ID from URL with query params", () => {
25
- const url = "https://vimeo.com/123456789?share=copy&autoplay=1";
26
- expect(extractVimeoId(url)).toBe("123456789");
27
- });
28
- it("extracts ID from URL with hash for unlisted videos", () => {
29
- const url = "https://vimeo.com/123456789/abcdef1234";
30
- expect(extractVimeoId(url)).toBe("123456789");
31
- });
32
- it("extracts ID from player URL with h parameter", () => {
33
- const url = "https://player.vimeo.com/video/123456789?h=abcdef1234";
34
- expect(extractVimeoId(url)).toBe("123456789");
35
- });
36
- it("returns null for non-Vimeo URL", () => {
37
- expect(extractVimeoId("https://youtube.com/watch?v=abc123")).toBeNull();
38
- expect(extractVimeoId("https://loom.com/embed/abc123")).toBeNull();
39
- });
40
- it("returns null for Vimeo homepage", () => {
41
- expect(extractVimeoId("https://vimeo.com")).toBeNull();
42
- expect(extractVimeoId("https://vimeo.com/")).toBeNull();
43
- });
44
- it("returns null for empty string", () => {
45
- expect(extractVimeoId("")).toBeNull();
46
- });
47
- it("returns null for invalid string", () => {
48
- expect(extractVimeoId("not-a-url")).toBeNull();
49
- });
50
- });
51
- //# sourceMappingURL=vimeoDownloader.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vimeoDownloader.test.js","sourceRoot":"","sources":["../../src/downloader/vimeoDownloader.test.ts"],"names":[],"mappings":"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"}
@@ -1,29 +0,0 @@
1
- import { Browser, BrowserContext, Page } from "playwright";
2
- export interface AuthSession {
3
- context: BrowserContext;
4
- page: Page;
5
- }
6
- /**
7
- * Checks if a valid session exists for the given domain.
8
- */
9
- export declare function hasValidSession(domain: string): boolean;
10
- /**
11
- * Performs interactive login by opening a browser window.
12
- * The user logs in manually, and we capture the session.
13
- */
14
- export declare function performInteractiveLogin(domain: string, loginUrl: string): Promise<AuthSession>;
15
- /**
16
- * Gets an authenticated session, either from cache or via interactive login.
17
- */
18
- export declare function getAuthenticatedSession(domain: string, loginUrl: string, options?: {
19
- forceLogin?: boolean;
20
- headless?: boolean;
21
- }): Promise<{
22
- browser: Browser;
23
- session: AuthSession;
24
- }>;
25
- /**
26
- * Clears the session for a domain.
27
- */
28
- export declare function clearSession(domain: string): boolean;
29
- //# sourceMappingURL=auth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/scraper/auth.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAY,IAAI,EAAE,MAAM,YAAY,CAAC;AAGrE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAGvD;AA0BD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAkCtB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC,CA2CrD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOpD"}
@@ -1,115 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { dirname } from "node:path";
3
- import { chromium } from "playwright";
4
- import { getSessionPath, SESSIONS_DIR } from "../config/paths.js";
5
- /**
6
- * Checks if a valid session exists for the given domain.
7
- */
8
- export function hasValidSession(domain) {
9
- const sessionPath = getSessionPath(domain);
10
- return existsSync(sessionPath);
11
- }
12
- /**
13
- * Loads an existing session from disk.
14
- */
15
- async function loadSession(browser, domain) {
16
- const sessionPath = getSessionPath(domain);
17
- const storageState = JSON.parse(readFileSync(sessionPath, "utf-8"));
18
- return browser.newContext({ storageState });
19
- }
20
- /**
21
- * Saves the current session to disk.
22
- */
23
- async function saveSession(context, domain) {
24
- const sessionPath = getSessionPath(domain);
25
- const dir = dirname(sessionPath);
26
- if (!existsSync(dir)) {
27
- mkdirSync(dir, { recursive: true });
28
- }
29
- const storageState = await context.storageState();
30
- writeFileSync(sessionPath, JSON.stringify(storageState, null, 2), "utf-8");
31
- }
32
- /**
33
- * Performs interactive login by opening a browser window.
34
- * The user logs in manually, and we capture the session.
35
- */
36
- export async function performInteractiveLogin(domain, loginUrl) {
37
- // Ensure sessions directory exists
38
- if (!existsSync(SESSIONS_DIR)) {
39
- mkdirSync(SESSIONS_DIR, { recursive: true });
40
- }
41
- const browser = await chromium.launch({
42
- headless: false, // Must be visible for user interaction
43
- });
44
- const context = await browser.newContext({
45
- viewport: { width: 1280, height: 800 },
46
- });
47
- const page = await context.newPage();
48
- await page.goto(loginUrl);
49
- console.log("\n🔐 Browser opened. Please log in manually.");
50
- console.log(" The window will close automatically after successful login.\n");
51
- // Wait for navigation away from login page (indicates successful login)
52
- await page.waitForURL((url) => !url.pathname.includes("/login"), {
53
- timeout: 300000, // 5 minutes to complete login
54
- });
55
- // Give the page a moment to fully load after login
56
- await page.waitForLoadState("networkidle");
57
- // Save the session
58
- await saveSession(context, domain);
59
- console.log("✅ Login successful! Session saved.\n");
60
- return { context, page };
61
- }
62
- /**
63
- * Gets an authenticated session, either from cache or via interactive login.
64
- */
65
- export async function getAuthenticatedSession(domain, loginUrl, options = {}) {
66
- const browser = await chromium.launch({
67
- headless: options.headless ?? false,
68
- });
69
- // Try to use existing session
70
- if (!options.forceLogin && hasValidSession(domain)) {
71
- try {
72
- const context = await loadSession(browser, domain);
73
- const page = await context.newPage();
74
- // Verify session is still valid by navigating
75
- await page.goto(`https://${domain}`);
76
- // Check if we got redirected to login
77
- const currentUrl = page.url();
78
- if (currentUrl.includes("/login")) {
79
- console.log("⚠️ Session expired, need to re-login...");
80
- await context.close();
81
- }
82
- else {
83
- console.log("✅ Using cached session");
84
- return { browser, session: { context, page } };
85
- }
86
- }
87
- catch (error) {
88
- console.log("⚠️ Failed to load session, need to re-login...", error);
89
- }
90
- }
91
- // Need fresh login
92
- await browser.close();
93
- const session = await performInteractiveLogin(domain, loginUrl);
94
- // Reopen browser with saved session for headless operation if needed
95
- const newBrowser = await chromium.launch({
96
- headless: options.headless ?? false,
97
- });
98
- const context = await loadSession(newBrowser, domain);
99
- const page = await context.newPage();
100
- // Close the interactive session
101
- await session.context.browser()?.close();
102
- return { browser: newBrowser, session: { context, page } };
103
- }
104
- /**
105
- * Clears the session for a domain.
106
- */
107
- export function clearSession(domain) {
108
- const sessionPath = getSessionPath(domain);
109
- if (existsSync(sessionPath)) {
110
- unlinkSync(sessionPath);
111
- return true;
112
- }
113
- return false;
114
- }
115
- //# sourceMappingURL=auth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/scraper/auth.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=extractor.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extractor.test.d.ts","sourceRoot":"","sources":["../../src/scraper/extractor.test.ts"],"names":[],"mappings":""}
@@ -1,65 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { extractLoomVideoId, formatMarkdown } from "./extractor.js";
3
- describe("extractLoomVideoId", () => {
4
- it("extracts ID from embed URL", () => {
5
- const url = "https://www.loom.com/embed/abc123def456";
6
- expect(extractLoomVideoId(url)).toBe("abc123def456");
7
- });
8
- it("extracts ID from embed URL with query params", () => {
9
- const url = "https://www.loom.com/embed/abc123def456?autoplay=1";
10
- expect(extractLoomVideoId(url)).toBe("abc123def456");
11
- });
12
- it("returns null for invalid URL", () => {
13
- expect(extractLoomVideoId("https://youtube.com/watch?v=123")).toBeNull();
14
- });
15
- it("returns null for non-embed loom URL", () => {
16
- // Note: extractLoomVideoId only handles embed URLs
17
- expect(extractLoomVideoId("https://loom.com/share/abc123")).toBeNull();
18
- });
19
- it("returns null for empty string", () => {
20
- expect(extractLoomVideoId("")).toBeNull();
21
- });
22
- it("handles URL without www prefix", () => {
23
- const url = "https://loom.com/embed/abc123def456";
24
- expect(extractLoomVideoId(url)).toBe("abc123def456");
25
- });
26
- });
27
- describe("formatMarkdown", () => {
28
- it("creates markdown with title", () => {
29
- const result = formatMarkdown("My Lesson", "", null, null);
30
- expect(result).toBe("# My Lesson");
31
- });
32
- it("includes video link when present", () => {
33
- const result = formatMarkdown("My Lesson", "", "https://loom.com/embed/123", "loom");
34
- expect(result).toContain("# My Lesson");
35
- expect(result).toContain("📺 Loom: https://loom.com/embed/123");
36
- });
37
- it("includes content when present", () => {
38
- const result = formatMarkdown("My Lesson", "Some content here", null, null);
39
- expect(result).toContain("# My Lesson");
40
- expect(result).toContain("Some content here");
41
- });
42
- it("capitalizes video type label", () => {
43
- const result = formatMarkdown("Test", "", "https://example.com", "vimeo");
44
- expect(result).toContain("Vimeo:");
45
- });
46
- it("uses generic 'Video' label when type is null", () => {
47
- const result = formatMarkdown("Test", "", "https://example.com", null);
48
- expect(result).toContain("Video:");
49
- });
50
- it("cleans up excessive newlines", () => {
51
- const result = formatMarkdown("Test", "Line 1\n\n\n\n\nLine 2", null, null);
52
- expect(result).not.toContain("\n\n\n");
53
- });
54
- it("combines all parts correctly", () => {
55
- const result = formatMarkdown("Full Lesson", "This is the lesson content.", "https://vimeo.com/123", "vimeo");
56
- expect(result).toContain("# Full Lesson");
57
- expect(result).toContain("📺 Vimeo: https://vimeo.com/123");
58
- expect(result).toContain("This is the lesson content.");
59
- });
60
- it("trims final result", () => {
61
- const result = formatMarkdown("Test", "Content ", null, null);
62
- expect(result).not.toMatch(/\s+$/);
63
- });
64
- });
65
- //# sourceMappingURL=extractor.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"extractor.test.js","sourceRoot":"","sources":["../../src/scraper/extractor.test.ts"],"names":[],"mappings":"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"}
@@ -1,25 +0,0 @@
1
- import type { Browser, BrowserContext, Page } from "playwright";
2
- export interface GHLAuthSession {
3
- context: BrowserContext;
4
- page: Page;
5
- }
6
- /**
7
- * Checks if a valid GHL session exists for the given domain.
8
- */
9
- export declare function hasValidGHLSession(domain: string): boolean;
10
- /**
11
- * Performs interactive login for GHL by opening a browser window.
12
- * The user logs in manually, and we capture the session.
13
- */
14
- export declare function performGHLInteractiveLogin(domain: string, portalUrl: string): Promise<GHLAuthSession>;
15
- /**
16
- * Gets an authenticated GHL session, either from cache or via interactive login.
17
- */
18
- export declare function getGHLAuthenticatedSession(domain: string, portalUrl: string, options?: {
19
- forceLogin?: boolean;
20
- headless?: boolean;
21
- }): Promise<{
22
- browser: Browser;
23
- session: GHLAuthSession;
24
- }>;
25
- //# sourceMappingURL=auth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/scraper/ghl/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIhE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,cAAc,CAAC;IACxB,IAAI,EAAE,IAAI,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAG1D;AAoED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC,CAgEzB;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAiExD"}