offcourse 1.0.0 → 1.0.1

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 (258) hide show
  1. package/dist/cli/commands/config.js.map +1 -1
  2. package/dist/cli/commands/inspect.js +1 -1
  3. package/dist/cli/commands/inspect.js.map +1 -1
  4. package/dist/cli/commands/sync.d.ts +1 -2
  5. package/dist/cli/commands/sync.d.ts.map +1 -1
  6. package/dist/cli/commands/sync.js +13 -14
  7. package/dist/cli/commands/sync.js.map +1 -1
  8. package/dist/cli/commands/syncHighLevel.d.ts +1 -2
  9. package/dist/cli/commands/syncHighLevel.d.ts.map +1 -1
  10. package/dist/cli/commands/syncHighLevel.js +4 -8
  11. package/dist/cli/commands/syncHighLevel.js.map +1 -1
  12. package/dist/cli/index.js +1 -1
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/config/configManager.d.ts.map +1 -1
  15. package/dist/config/configManager.js +4 -0
  16. package/dist/config/configManager.js.map +1 -1
  17. package/dist/downloader/hlsDownloader.d.ts.map +1 -1
  18. package/dist/downloader/hlsDownloader.js +23 -14
  19. package/dist/downloader/hlsDownloader.js.map +1 -1
  20. package/dist/downloader/hlsValidator.d.ts.map +1 -1
  21. package/dist/downloader/hlsValidator.js +6 -2
  22. package/dist/downloader/hlsValidator.js.map +1 -1
  23. package/dist/downloader/index.d.ts +3 -0
  24. package/dist/downloader/index.d.ts.map +1 -1
  25. package/dist/downloader/index.js +3 -0
  26. package/dist/downloader/index.js.map +1 -1
  27. package/dist/downloader/loomDownloader.d.ts.map +1 -1
  28. package/dist/downloader/loomDownloader.js +23 -20
  29. package/dist/downloader/loomDownloader.js.map +1 -1
  30. package/dist/downloader/queue.d.ts +4 -4
  31. package/dist/downloader/queue.d.ts.map +1 -1
  32. package/dist/downloader/queue.js.map +1 -1
  33. package/dist/downloader/vimeoDownloader.d.ts.map +1 -1
  34. package/dist/downloader/vimeoDownloader.js +7 -3
  35. package/dist/downloader/vimeoDownloader.js.map +1 -1
  36. package/dist/scraper/extractor.d.ts +4 -0
  37. package/dist/scraper/extractor.d.ts.map +1 -1
  38. package/dist/scraper/extractor.js +79 -79
  39. package/dist/scraper/extractor.js.map +1 -1
  40. package/dist/scraper/highlevel/extractor.d.ts +11 -19
  41. package/dist/scraper/highlevel/extractor.d.ts.map +1 -1
  42. package/dist/scraper/highlevel/extractor.js +72 -85
  43. package/dist/scraper/highlevel/extractor.js.map +1 -1
  44. package/dist/scraper/highlevel/navigator.d.ts +3 -10
  45. package/dist/scraper/highlevel/navigator.d.ts.map +1 -1
  46. package/dist/scraper/highlevel/navigator.js +140 -127
  47. package/dist/scraper/highlevel/navigator.js.map +1 -1
  48. package/dist/scraper/highlevel/schemas.d.ts +188 -0
  49. package/dist/scraper/highlevel/schemas.d.ts.map +1 -0
  50. package/dist/scraper/highlevel/schemas.js +139 -0
  51. package/dist/scraper/highlevel/schemas.js.map +1 -0
  52. package/dist/scraper/navigator.d.ts +14 -11
  53. package/dist/scraper/navigator.d.ts.map +1 -1
  54. package/dist/scraper/navigator.js +61 -104
  55. package/dist/scraper/navigator.js.map +1 -1
  56. package/dist/scraper/schemas.d.ts +57 -0
  57. package/dist/scraper/schemas.d.ts.map +1 -0
  58. package/dist/scraper/schemas.js +135 -0
  59. package/dist/scraper/schemas.js.map +1 -0
  60. package/dist/scraper/videoInterceptor.d.ts +4 -0
  61. package/dist/scraper/videoInterceptor.d.ts.map +1 -1
  62. package/dist/scraper/videoInterceptor.js +66 -51
  63. package/dist/scraper/videoInterceptor.js.map +1 -1
  64. package/dist/shared/auth.d.ts +9 -9
  65. package/dist/shared/auth.d.ts.map +1 -1
  66. package/dist/shared/auth.js +24 -38
  67. package/dist/shared/auth.js.map +1 -1
  68. package/dist/shared/firebase.d.ts +60 -0
  69. package/dist/shared/firebase.d.ts.map +1 -0
  70. package/dist/shared/firebase.js +102 -0
  71. package/dist/shared/firebase.js.map +1 -0
  72. package/dist/shared/fs.d.ts.map +1 -1
  73. package/dist/shared/fs.js +4 -0
  74. package/dist/shared/fs.js.map +1 -1
  75. package/dist/shared/index.d.ts +3 -0
  76. package/dist/shared/index.d.ts.map +1 -1
  77. package/dist/shared/index.js +3 -0
  78. package/dist/shared/index.js.map +1 -1
  79. package/dist/shared/slug.d.ts +11 -0
  80. package/dist/shared/slug.d.ts.map +1 -0
  81. package/{src/shared/slug.ts → dist/shared/slug.js} +10 -11
  82. package/dist/shared/slug.js.map +1 -0
  83. package/dist/shared/url.d.ts +43 -0
  84. package/dist/shared/url.d.ts.map +1 -0
  85. package/{src/shared/url.ts → dist/shared/url.js} +12 -15
  86. package/dist/shared/url.js.map +1 -0
  87. package/dist/state/database.d.ts +1 -0
  88. package/dist/state/database.d.ts.map +1 -1
  89. package/dist/state/database.js +3 -0
  90. package/dist/state/database.js.map +1 -1
  91. package/dist/storage/fileSystem.d.ts +17 -17
  92. package/dist/storage/fileSystem.d.ts.map +1 -1
  93. package/dist/storage/fileSystem.js +39 -31
  94. package/dist/storage/fileSystem.js.map +1 -1
  95. package/package.json +5 -2
  96. package/.github/workflows/ci.yml +0 -50
  97. package/.husky/commit-msg +0 -2
  98. package/.husky/pre-commit +0 -1
  99. package/.husky/pre-push +0 -3
  100. package/.prettierrc +0 -8
  101. package/.release-it.json +0 -23
  102. package/ARCHITECTURE.md +0 -233
  103. package/CHANGELOG.md +0 -78
  104. package/commitlint.config.js +0 -4
  105. package/dist/ai/openRouter.d.ts +0 -47
  106. package/dist/ai/openRouter.d.ts.map +0 -1
  107. package/dist/ai/openRouter.js +0 -116
  108. package/dist/ai/openRouter.js.map +0 -1
  109. package/dist/ai/transcriptPolisher.d.ts +0 -24
  110. package/dist/ai/transcriptPolisher.d.ts.map +0 -1
  111. package/dist/ai/transcriptPolisher.js +0 -89
  112. package/dist/ai/transcriptPolisher.js.map +0 -1
  113. package/dist/cli/commands/enrich.d.ts +0 -14
  114. package/dist/cli/commands/enrich.d.ts.map +0 -1
  115. package/dist/cli/commands/enrich.js +0 -271
  116. package/dist/cli/commands/enrich.js.map +0 -1
  117. package/dist/cli/commands/syncGhl.d.ts +0 -20
  118. package/dist/cli/commands/syncGhl.d.ts.map +0 -1
  119. package/dist/cli/commands/syncGhl.js +0 -483
  120. package/dist/cli/commands/syncGhl.js.map +0 -1
  121. package/dist/cli/commands/syncHighLevel.test.d.ts +0 -2
  122. package/dist/cli/commands/syncHighLevel.test.d.ts.map +0 -1
  123. package/dist/cli/commands/syncHighLevel.test.js +0 -102
  124. package/dist/cli/commands/syncHighLevel.test.js.map +0 -1
  125. package/dist/config/paths.test.d.ts +0 -2
  126. package/dist/config/paths.test.d.ts.map +0 -1
  127. package/dist/config/paths.test.js +0 -70
  128. package/dist/config/paths.test.js.map +0 -1
  129. package/dist/config/schema.test.d.ts +0 -2
  130. package/dist/config/schema.test.d.ts.map +0 -1
  131. package/dist/config/schema.test.js +0 -151
  132. package/dist/config/schema.test.js.map +0 -1
  133. package/dist/downloader/hlsDownloader.test.d.ts +0 -2
  134. package/dist/downloader/hlsDownloader.test.d.ts.map +0 -1
  135. package/dist/downloader/hlsDownloader.test.js +0 -116
  136. package/dist/downloader/hlsDownloader.test.js.map +0 -1
  137. package/dist/downloader/loomDownloader.test.d.ts +0 -2
  138. package/dist/downloader/loomDownloader.test.d.ts.map +0 -1
  139. package/dist/downloader/loomDownloader.test.js +0 -36
  140. package/dist/downloader/loomDownloader.test.js.map +0 -1
  141. package/dist/downloader/queue.test.d.ts +0 -2
  142. package/dist/downloader/queue.test.d.ts.map +0 -1
  143. package/dist/downloader/queue.test.js +0 -158
  144. package/dist/downloader/queue.test.js.map +0 -1
  145. package/dist/downloader/videoDownloader.d.ts +0 -32
  146. package/dist/downloader/videoDownloader.d.ts.map +0 -1
  147. package/dist/downloader/videoDownloader.js +0 -173
  148. package/dist/downloader/videoDownloader.js.map +0 -1
  149. package/dist/downloader/vimeoDownloader.test.d.ts +0 -2
  150. package/dist/downloader/vimeoDownloader.test.d.ts.map +0 -1
  151. package/dist/downloader/vimeoDownloader.test.js +0 -51
  152. package/dist/downloader/vimeoDownloader.test.js.map +0 -1
  153. package/dist/scraper/auth.d.ts +0 -29
  154. package/dist/scraper/auth.d.ts.map +0 -1
  155. package/dist/scraper/auth.js +0 -115
  156. package/dist/scraper/auth.js.map +0 -1
  157. package/dist/scraper/extractor.test.d.ts +0 -2
  158. package/dist/scraper/extractor.test.d.ts.map +0 -1
  159. package/dist/scraper/extractor.test.js +0 -65
  160. package/dist/scraper/extractor.test.js.map +0 -1
  161. package/dist/scraper/ghl/auth.d.ts +0 -25
  162. package/dist/scraper/ghl/auth.d.ts.map +0 -1
  163. package/dist/scraper/ghl/auth.js +0 -187
  164. package/dist/scraper/ghl/auth.js.map +0 -1
  165. package/dist/scraper/ghl/extractor.d.ts +0 -96
  166. package/dist/scraper/ghl/extractor.d.ts.map +0 -1
  167. package/dist/scraper/ghl/extractor.js +0 -345
  168. package/dist/scraper/ghl/extractor.js.map +0 -1
  169. package/dist/scraper/ghl/index.d.ts +0 -4
  170. package/dist/scraper/ghl/index.d.ts.map +0 -1
  171. package/dist/scraper/ghl/index.js +0 -4
  172. package/dist/scraper/ghl/index.js.map +0 -1
  173. package/dist/scraper/ghl/navigator.d.ts +0 -93
  174. package/dist/scraper/ghl/navigator.d.ts.map +0 -1
  175. package/dist/scraper/ghl/navigator.js +0 -447
  176. package/dist/scraper/ghl/navigator.js.map +0 -1
  177. package/dist/scraper/highlevel/auth.d.ts +0 -25
  178. package/dist/scraper/highlevel/auth.d.ts.map +0 -1
  179. package/dist/scraper/highlevel/auth.js +0 -189
  180. package/dist/scraper/highlevel/auth.js.map +0 -1
  181. package/dist/scraper/highlevel/extractor.test.d.ts +0 -2
  182. package/dist/scraper/highlevel/extractor.test.d.ts.map +0 -1
  183. package/dist/scraper/highlevel/extractor.test.js +0 -101
  184. package/dist/scraper/highlevel/extractor.test.js.map +0 -1
  185. package/dist/scraper/highlevel/navigator.test.d.ts +0 -2
  186. package/dist/scraper/highlevel/navigator.test.d.ts.map +0 -1
  187. package/dist/scraper/highlevel/navigator.test.js +0 -78
  188. package/dist/scraper/highlevel/navigator.test.js.map +0 -1
  189. package/dist/scraper/navigator.test.d.ts +0 -2
  190. package/dist/scraper/navigator.test.d.ts.map +0 -1
  191. package/dist/scraper/navigator.test.js +0 -63
  192. package/dist/scraper/navigator.test.js.map +0 -1
  193. package/dist/scraper/skoolApi.d.ts +0 -17
  194. package/dist/scraper/skoolApi.d.ts.map +0 -1
  195. package/dist/scraper/skoolApi.js +0 -72
  196. package/dist/scraper/skoolApi.js.map +0 -1
  197. package/dist/state/database.test.d.ts +0 -2
  198. package/dist/state/database.test.d.ts.map +0 -1
  199. package/dist/state/database.test.js +0 -34
  200. package/dist/state/database.test.js.map +0 -1
  201. package/dist/transcription/whisperService.d.ts +0 -27
  202. package/dist/transcription/whisperService.d.ts.map +0 -1
  203. package/dist/transcription/whisperService.js +0 -102
  204. package/dist/transcription/whisperService.js.map +0 -1
  205. package/eslint.config.js +0 -55
  206. package/src/__fixtures__/highlevel-post-response.json +0 -68
  207. package/src/__fixtures__/hls-master-playlist.m3u8 +0 -24
  208. package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +0 -38
  209. package/src/cli/commands/config.ts +0 -74
  210. package/src/cli/commands/inspect.ts +0 -441
  211. package/src/cli/commands/login.ts +0 -68
  212. package/src/cli/commands/status.ts +0 -147
  213. package/src/cli/commands/sync.ts +0 -1235
  214. package/src/cli/commands/syncHighLevel.test.ts +0 -144
  215. package/src/cli/commands/syncHighLevel.ts +0 -639
  216. package/src/cli/index.ts +0 -121
  217. package/src/config/configManager.ts +0 -75
  218. package/src/config/paths.test.ts +0 -83
  219. package/src/config/paths.ts +0 -36
  220. package/src/config/schema.test.ts +0 -173
  221. package/src/config/schema.ts +0 -65
  222. package/src/downloader/hlsDownloader.test.ts +0 -148
  223. package/src/downloader/hlsDownloader.ts +0 -327
  224. package/src/downloader/hlsValidator.ts +0 -196
  225. package/src/downloader/index.ts +0 -122
  226. package/src/downloader/loomDownloader.test.ts +0 -43
  227. package/src/downloader/loomDownloader.ts +0 -742
  228. package/src/downloader/queue.test.ts +0 -199
  229. package/src/downloader/queue.ts +0 -118
  230. package/src/downloader/vimeoDownloader.test.ts +0 -62
  231. package/src/downloader/vimeoDownloader.ts +0 -722
  232. package/src/scraper/extractor.test.ts +0 -124
  233. package/src/scraper/extractor.ts +0 -757
  234. package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +0 -41
  235. package/src/scraper/highlevel/extractor.test.ts +0 -134
  236. package/src/scraper/highlevel/extractor.ts +0 -537
  237. package/src/scraper/highlevel/index.ts +0 -2
  238. package/src/scraper/highlevel/navigator.test.ts +0 -110
  239. package/src/scraper/highlevel/navigator.ts +0 -668
  240. package/src/scraper/highlevel/schemas.ts +0 -183
  241. package/src/scraper/navigator.test.ts +0 -122
  242. package/src/scraper/navigator.ts +0 -355
  243. package/src/scraper/schemas.ts +0 -177
  244. package/src/scraper/videoInterceptor.ts +0 -435
  245. package/src/shared/auth.test.ts +0 -58
  246. package/src/shared/auth.ts +0 -251
  247. package/src/shared/firebase.ts +0 -151
  248. package/src/shared/fs.ts +0 -80
  249. package/src/shared/http.ts +0 -34
  250. package/src/shared/index.ts +0 -6
  251. package/src/shared/url.test.ts +0 -122
  252. package/src/state/database.test.ts +0 -49
  253. package/src/state/database.ts +0 -919
  254. package/src/state/index.ts +0 -14
  255. package/src/storage/fileSystem.test.ts +0 -64
  256. package/src/storage/fileSystem.ts +0 -175
  257. package/tsconfig.json +0 -28
  258. package/vitest.config.ts +0 -29
@@ -1,199 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { AsyncQueue } from "./queue.js";
3
-
4
- describe("AsyncQueue", () => {
5
- it("processes items in order", async () => {
6
- const processed: string[] = [];
7
- const queue = new AsyncQueue<string>({
8
- concurrency: 1,
9
- maxRetries: 0,
10
- });
11
-
12
- queue.add("1", "first");
13
- queue.add("2", "second");
14
- queue.add("3", "third");
15
-
16
- await queue.process(async (item) => {
17
- processed.push(item);
18
- });
19
-
20
- expect(processed).toEqual(["first", "second", "third"]);
21
- });
22
-
23
- it("tracks completed and failed counts", async () => {
24
- const queue = new AsyncQueue<string>({
25
- concurrency: 1,
26
- maxRetries: 0,
27
- });
28
-
29
- queue.add("1", "success");
30
- queue.add("2", "fail");
31
- queue.add("3", "success");
32
-
33
- const result = await queue.process(async (item) => {
34
- if (item === "fail") {
35
- throw new Error("Intentional failure");
36
- }
37
- });
38
-
39
- expect(result.completed).toBe(2);
40
- expect(result.failed).toBe(1);
41
- expect(result.errors).toHaveLength(1);
42
- expect(result.errors[0]?.id).toBe("2");
43
- });
44
-
45
- it("retries failed items up to maxRetries", async () => {
46
- let attempts = 0;
47
- const queue = new AsyncQueue<string>({
48
- concurrency: 1,
49
- maxRetries: 3,
50
- });
51
-
52
- queue.add("1", "retry-test");
53
-
54
- await queue.process(async () => {
55
- attempts++;
56
- if (attempts < 3) {
57
- throw new Error("Not yet");
58
- }
59
- });
60
-
61
- expect(attempts).toBe(3);
62
- });
63
-
64
- it("adds multiple items with addAll", async () => {
65
- const queue = new AsyncQueue<number>({
66
- concurrency: 1,
67
- maxRetries: 0,
68
- });
69
-
70
- queue.addAll([
71
- { id: "a", data: 1 },
72
- { id: "b", data: 2 },
73
- { id: "c", data: 3 },
74
- ]);
75
-
76
- const sum = { value: 0 };
77
- await queue.process(async (item) => {
78
- sum.value += item;
79
- });
80
-
81
- expect(sum.value).toBe(6);
82
- });
83
-
84
- it("reports progress during processing", async () => {
85
- const progressCalls: { completed: number; total: number }[] = [];
86
-
87
- const queue = new AsyncQueue<string>({
88
- concurrency: 1,
89
- maxRetries: 0,
90
- onProgress: (completed, total) => {
91
- progressCalls.push({ completed, total });
92
- },
93
- });
94
-
95
- queue.add("1", "a");
96
- queue.add("2", "b");
97
- queue.add("3", "c");
98
-
99
- await queue.process(async () => {
100
- // no-op
101
- });
102
-
103
- expect(progressCalls.length).toBeGreaterThan(0);
104
- // Last call should have all completed
105
- const lastCall = progressCalls.at(-1);
106
- expect(lastCall?.completed).toBe(3);
107
- expect(lastCall?.total).toBe(3);
108
- });
109
-
110
- it("returns correct status", async () => {
111
- const queue = new AsyncQueue<string>({
112
- concurrency: 1,
113
- maxRetries: 0,
114
- });
115
-
116
- queue.add("1", "a");
117
- queue.add("2", "b");
118
-
119
- const beforeStatus = queue.getStatus();
120
- expect(beforeStatus.pending).toBe(2);
121
- expect(beforeStatus.completed).toBe(0);
122
-
123
- await queue.process(async () => {});
124
-
125
- const afterStatus = queue.getStatus();
126
- expect(afterStatus.pending).toBe(0);
127
- expect(afterStatus.completed).toBe(2);
128
- });
129
-
130
- it("handles concurrent processing", async () => {
131
- const processing = new Set<string>();
132
- let maxConcurrent = 0;
133
-
134
- const queue = new AsyncQueue<string>({
135
- concurrency: 2,
136
- maxRetries: 0,
137
- });
138
-
139
- queue.addAll([
140
- { id: "1", data: "a" },
141
- { id: "2", data: "b" },
142
- { id: "3", data: "c" },
143
- { id: "4", data: "d" },
144
- ]);
145
-
146
- await queue.process(async (_item, id) => {
147
- processing.add(id);
148
- maxConcurrent = Math.max(maxConcurrent, processing.size);
149
- // Simulate async work
150
- await new Promise((r) => setTimeout(r, 10));
151
- processing.delete(id);
152
- });
153
-
154
- expect(maxConcurrent).toBeLessThanOrEqual(2);
155
- });
156
-
157
- it("handles empty queue", async () => {
158
- const queue = new AsyncQueue<string>({
159
- concurrency: 1,
160
- maxRetries: 0,
161
- });
162
-
163
- const result = await queue.process(async () => {});
164
-
165
- expect(result.completed).toBe(0);
166
- expect(result.failed).toBe(0);
167
- expect(result.errors).toEqual([]);
168
- });
169
-
170
- it("captures error messages correctly", async () => {
171
- const queue = new AsyncQueue<string>({
172
- concurrency: 1,
173
- maxRetries: 0,
174
- });
175
-
176
- queue.add("1", "test");
177
-
178
- const result = await queue.process(async () => {
179
- throw new Error("Specific error message");
180
- });
181
-
182
- expect(result.errors[0]?.error).toBe("Specific error message");
183
- });
184
-
185
- it("handles non-Error throws", async () => {
186
- const queue = new AsyncQueue<string>({
187
- concurrency: 1,
188
- maxRetries: 0,
189
- });
190
-
191
- queue.add("1", "test");
192
-
193
- const result = await queue.process(async () => {
194
- throw "String error";
195
- });
196
-
197
- expect(result.errors[0]?.error).toBe("String error");
198
- });
199
- });
@@ -1,118 +0,0 @@
1
- import PQueue from "p-queue";
2
-
3
- export interface QueueItem<T> {
4
- id: string;
5
- data: T;
6
- status: "pending" | "processing" | "completed" | "failed";
7
- error?: string;
8
- retries: number;
9
- }
10
-
11
- export interface QueueOptions {
12
- concurrency: number;
13
- maxRetries: number;
14
- onProgress?: ((completed: number, total: number, current?: string) => void) | undefined;
15
- }
16
-
17
- /**
18
- * An async queue for processing items with concurrency control.
19
- * Uses p-queue internally for battle-tested concurrency handling.
20
- */
21
- export class AsyncQueue<T> {
22
- private items: QueueItem<T>[] = [];
23
- private readonly queue: PQueue;
24
- private readonly maxRetries: number;
25
- private readonly onProgress:
26
- | ((completed: number, total: number, current?: string) => void)
27
- | undefined;
28
-
29
- constructor(options: QueueOptions) {
30
- this.queue = new PQueue({ concurrency: options.concurrency });
31
- this.maxRetries = options.maxRetries;
32
- this.onProgress = options.onProgress;
33
- }
34
-
35
- /**
36
- * Adds an item to the queue.
37
- */
38
- add(id: string, data: T): void {
39
- this.items.push({
40
- id,
41
- data,
42
- status: "pending",
43
- retries: 0,
44
- });
45
- }
46
-
47
- /**
48
- * Adds multiple items to the queue.
49
- */
50
- addAll(items: { id: string; data: T }[]): void {
51
- for (const item of items) {
52
- this.add(item.id, item.data);
53
- }
54
- }
55
-
56
- /**
57
- * Processes all items in the queue using the provided handler.
58
- */
59
- async process(
60
- handler: (item: T, id: string) => Promise<void>
61
- ): Promise<{ completed: number; failed: number; errors: { id: string; error: string }[] }> {
62
- const errors: { id: string; error: string }[] = [];
63
-
64
- const processItem = async (item: QueueItem<T>): Promise<void> => {
65
- item.status = "processing";
66
-
67
- // maxRetries=0 means try once, maxRetries=3 means try up to 3 times total
68
- const maxAttempts = Math.max(1, this.maxRetries);
69
-
70
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
71
- try {
72
- await handler(item.data, item.id);
73
- item.status = "completed";
74
- this.reportProgress();
75
- return;
76
- } catch (error) {
77
- item.retries = attempt + 1;
78
- if (attempt >= maxAttempts - 1) {
79
- item.status = "failed";
80
- item.error = error instanceof Error ? error.message : String(error);
81
- errors.push({ id: item.id, error: item.error });
82
- this.reportProgress();
83
- }
84
- }
85
- }
86
- };
87
-
88
- // Add all items to the p-queue
89
- await this.queue.addAll(this.items.map((item) => () => processItem(item)));
90
-
91
- const completed = this.items.filter((i) => i.status === "completed").length;
92
- const failed = this.items.filter((i) => i.status === "failed").length;
93
-
94
- return { completed, failed, errors };
95
- }
96
-
97
- private reportProgress(): void {
98
- if (!this.onProgress) return;
99
-
100
- const completed = this.items.filter((i) => i.status === "completed").length;
101
- const total = this.items.length;
102
- const current = this.items.find((i) => i.status === "processing");
103
-
104
- this.onProgress(completed, total, current?.id);
105
- }
106
-
107
- /**
108
- * Gets the current queue status.
109
- */
110
- getStatus(): { pending: number; processing: number; completed: number; failed: number } {
111
- return {
112
- pending: this.items.filter((i) => i.status === "pending").length,
113
- processing: this.items.filter((i) => i.status === "processing").length,
114
- completed: this.items.filter((i) => i.status === "completed").length,
115
- failed: this.items.filter((i) => i.status === "failed").length,
116
- };
117
- }
118
- }
@@ -1,62 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { extractVimeoId } from "./vimeoDownloader.js";
3
-
4
- describe("extractVimeoId", () => {
5
- it("extracts ID from standard vimeo.com URL", () => {
6
- const url = "https://vimeo.com/123456789";
7
- expect(extractVimeoId(url)).toBe("123456789");
8
- });
9
-
10
- it("extracts ID from vimeo.com/video URL", () => {
11
- const url = "https://vimeo.com/video/123456789";
12
- expect(extractVimeoId(url)).toBe("123456789");
13
- });
14
-
15
- it("extracts ID from player.vimeo.com URL", () => {
16
- const url = "https://player.vimeo.com/video/987654321";
17
- expect(extractVimeoId(url)).toBe("987654321");
18
- });
19
-
20
- it("extracts ID from channel URL", () => {
21
- const url = "https://vimeo.com/channels/staffpicks/123456789";
22
- expect(extractVimeoId(url)).toBe("123456789");
23
- });
24
-
25
- it("extracts ID from groups URL", () => {
26
- const url = "https://vimeo.com/groups/shortfilms/videos/123456789";
27
- expect(extractVimeoId(url)).toBe("123456789");
28
- });
29
-
30
- it("extracts ID from URL with query params", () => {
31
- const url = "https://vimeo.com/123456789?share=copy&autoplay=1";
32
- expect(extractVimeoId(url)).toBe("123456789");
33
- });
34
-
35
- it("extracts ID from URL with hash for unlisted videos", () => {
36
- const url = "https://vimeo.com/123456789/abcdef1234";
37
- expect(extractVimeoId(url)).toBe("123456789");
38
- });
39
-
40
- it("extracts ID from player URL with h parameter", () => {
41
- const url = "https://player.vimeo.com/video/123456789?h=abcdef1234";
42
- expect(extractVimeoId(url)).toBe("123456789");
43
- });
44
-
45
- it("returns null for non-Vimeo URL", () => {
46
- expect(extractVimeoId("https://youtube.com/watch?v=abc123")).toBeNull();
47
- expect(extractVimeoId("https://loom.com/embed/abc123")).toBeNull();
48
- });
49
-
50
- it("returns null for Vimeo homepage", () => {
51
- expect(extractVimeoId("https://vimeo.com")).toBeNull();
52
- expect(extractVimeoId("https://vimeo.com/")).toBeNull();
53
- });
54
-
55
- it("returns null for empty string", () => {
56
- expect(extractVimeoId("")).toBeNull();
57
- });
58
-
59
- it("returns null for invalid string", () => {
60
- expect(extractVimeoId("not-a-url")).toBeNull();
61
- });
62
- });