offcourse 0.0.2 → 1.0.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 (284) hide show
  1. package/.github/workflows/ci.yml +50 -0
  2. package/.husky/commit-msg +2 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.husky/pre-push +3 -0
  5. package/.prettierrc +8 -0
  6. package/.release-it.json +23 -0
  7. package/ARCHITECTURE.md +233 -0
  8. package/CHANGELOG.md +78 -0
  9. package/README.md +255 -20
  10. package/commitlint.config.js +4 -0
  11. package/dist/ai/openRouter.d.ts +47 -0
  12. package/dist/ai/openRouter.d.ts.map +1 -0
  13. package/dist/ai/openRouter.js +116 -0
  14. package/dist/ai/openRouter.js.map +1 -0
  15. package/dist/ai/transcriptPolisher.d.ts +24 -0
  16. package/dist/ai/transcriptPolisher.d.ts.map +1 -0
  17. package/dist/ai/transcriptPolisher.js +89 -0
  18. package/dist/ai/transcriptPolisher.js.map +1 -0
  19. package/dist/cli/commands/config.d.ts +13 -0
  20. package/dist/cli/commands/config.d.ts.map +1 -0
  21. package/dist/cli/commands/config.js +66 -0
  22. package/dist/cli/commands/config.js.map +1 -0
  23. package/dist/cli/commands/enrich.d.ts +14 -0
  24. package/dist/cli/commands/enrich.d.ts.map +1 -0
  25. package/dist/cli/commands/enrich.js +271 -0
  26. package/dist/cli/commands/enrich.js.map +1 -0
  27. package/dist/cli/commands/inspect.d.ts +11 -0
  28. package/dist/cli/commands/inspect.d.ts.map +1 -0
  29. package/dist/cli/commands/inspect.js +365 -0
  30. package/dist/cli/commands/inspect.js.map +1 -0
  31. package/dist/cli/commands/login.d.ts +12 -0
  32. package/dist/cli/commands/login.d.ts.map +1 -0
  33. package/dist/cli/commands/login.js +55 -0
  34. package/dist/cli/commands/login.js.map +1 -0
  35. package/dist/cli/commands/status.d.ts +15 -0
  36. package/dist/cli/commands/status.d.ts.map +1 -0
  37. package/dist/cli/commands/status.js +118 -0
  38. package/dist/cli/commands/status.js.map +1 -0
  39. package/dist/cli/commands/sync.d.ts +16 -0
  40. package/dist/cli/commands/sync.d.ts.map +1 -0
  41. package/dist/cli/commands/sync.js +922 -0
  42. package/dist/cli/commands/sync.js.map +1 -0
  43. package/dist/cli/commands/syncGhl.d.ts +20 -0
  44. package/dist/cli/commands/syncGhl.d.ts.map +1 -0
  45. package/dist/cli/commands/syncGhl.js +483 -0
  46. package/dist/cli/commands/syncGhl.js.map +1 -0
  47. package/dist/cli/commands/syncHighLevel.d.ts +24 -0
  48. package/dist/cli/commands/syncHighLevel.d.ts.map +1 -0
  49. package/dist/cli/commands/syncHighLevel.js +483 -0
  50. package/dist/cli/commands/syncHighLevel.js.map +1 -0
  51. package/dist/cli/commands/syncHighLevel.test.d.ts +2 -0
  52. package/dist/cli/commands/syncHighLevel.test.d.ts.map +1 -0
  53. package/dist/cli/commands/syncHighLevel.test.js +102 -0
  54. package/dist/cli/commands/syncHighLevel.test.js.map +1 -0
  55. package/dist/cli/index.d.ts +3 -0
  56. package/dist/cli/index.d.ts.map +1 -0
  57. package/dist/cli/index.js +106 -0
  58. package/dist/cli/index.js.map +1 -0
  59. package/dist/config/configManager.d.ts +31 -0
  60. package/dist/config/configManager.d.ts.map +1 -0
  61. package/dist/config/configManager.js +64 -0
  62. package/dist/config/configManager.js.map +1 -0
  63. package/dist/config/paths.d.ts +21 -0
  64. package/dist/config/paths.d.ts.map +1 -0
  65. package/dist/config/paths.js +33 -0
  66. package/dist/config/paths.js.map +1 -0
  67. package/dist/config/paths.test.d.ts +2 -0
  68. package/dist/config/paths.test.d.ts.map +1 -0
  69. package/dist/config/paths.test.js +70 -0
  70. package/dist/config/paths.test.js.map +1 -0
  71. package/dist/config/schema.d.ts +60 -0
  72. package/dist/config/schema.d.ts.map +1 -0
  73. package/dist/config/schema.js +50 -0
  74. package/dist/config/schema.js.map +1 -0
  75. package/dist/config/schema.test.d.ts +2 -0
  76. package/dist/config/schema.test.d.ts.map +1 -0
  77. package/dist/config/schema.test.js +151 -0
  78. package/dist/config/schema.test.js.map +1 -0
  79. package/dist/downloader/hlsDownloader.d.ts +58 -0
  80. package/dist/downloader/hlsDownloader.d.ts.map +1 -0
  81. package/dist/downloader/hlsDownloader.js +254 -0
  82. package/dist/downloader/hlsDownloader.js.map +1 -0
  83. package/dist/downloader/hlsDownloader.test.d.ts +2 -0
  84. package/dist/downloader/hlsDownloader.test.d.ts.map +1 -0
  85. package/dist/downloader/hlsDownloader.test.js +116 -0
  86. package/dist/downloader/hlsDownloader.test.js.map +1 -0
  87. package/dist/downloader/hlsValidator.d.ts +35 -0
  88. package/dist/downloader/hlsValidator.d.ts.map +1 -0
  89. package/dist/downloader/hlsValidator.js +148 -0
  90. package/dist/downloader/hlsValidator.js.map +1 -0
  91. package/dist/downloader/index.d.ts +26 -0
  92. package/dist/downloader/index.d.ts.map +1 -0
  93. package/dist/downloader/index.js +52 -0
  94. package/dist/downloader/index.js.map +1 -0
  95. package/dist/downloader/loomDownloader.d.ts +56 -0
  96. package/dist/downloader/loomDownloader.d.ts.map +1 -0
  97. package/dist/downloader/loomDownloader.js +559 -0
  98. package/dist/downloader/loomDownloader.js.map +1 -0
  99. package/dist/downloader/loomDownloader.test.d.ts +2 -0
  100. package/dist/downloader/loomDownloader.test.d.ts.map +1 -0
  101. package/dist/downloader/loomDownloader.test.js +36 -0
  102. package/dist/downloader/loomDownloader.test.js.map +1 -0
  103. package/dist/downloader/queue.d.ts +56 -0
  104. package/dist/downloader/queue.d.ts.map +1 -0
  105. package/dist/downloader/queue.js +88 -0
  106. package/dist/downloader/queue.js.map +1 -0
  107. package/dist/downloader/queue.test.d.ts +2 -0
  108. package/dist/downloader/queue.test.d.ts.map +1 -0
  109. package/dist/downloader/queue.test.js +158 -0
  110. package/dist/downloader/queue.test.js.map +1 -0
  111. package/dist/downloader/videoDownloader.d.ts +32 -0
  112. package/dist/downloader/videoDownloader.d.ts.map +1 -0
  113. package/dist/downloader/videoDownloader.js +173 -0
  114. package/dist/downloader/videoDownloader.js.map +1 -0
  115. package/dist/downloader/vimeoDownloader.d.ts +52 -0
  116. package/dist/downloader/vimeoDownloader.d.ts.map +1 -0
  117. package/dist/downloader/vimeoDownloader.js +565 -0
  118. package/dist/downloader/vimeoDownloader.js.map +1 -0
  119. package/dist/downloader/vimeoDownloader.test.d.ts +2 -0
  120. package/dist/downloader/vimeoDownloader.test.d.ts.map +1 -0
  121. package/dist/downloader/vimeoDownloader.test.js +51 -0
  122. package/dist/downloader/vimeoDownloader.test.js.map +1 -0
  123. package/dist/scraper/auth.d.ts +29 -0
  124. package/dist/scraper/auth.d.ts.map +1 -0
  125. package/dist/scraper/auth.js +115 -0
  126. package/dist/scraper/auth.js.map +1 -0
  127. package/dist/scraper/extractor.d.ts +49 -0
  128. package/dist/scraper/extractor.d.ts.map +1 -0
  129. package/dist/scraper/extractor.js +627 -0
  130. package/dist/scraper/extractor.js.map +1 -0
  131. package/dist/scraper/extractor.test.d.ts +2 -0
  132. package/dist/scraper/extractor.test.d.ts.map +1 -0
  133. package/dist/scraper/extractor.test.js +65 -0
  134. package/dist/scraper/extractor.test.js.map +1 -0
  135. package/dist/scraper/ghl/auth.d.ts +25 -0
  136. package/dist/scraper/ghl/auth.d.ts.map +1 -0
  137. package/dist/scraper/ghl/auth.js +187 -0
  138. package/dist/scraper/ghl/auth.js.map +1 -0
  139. package/dist/scraper/ghl/extractor.d.ts +96 -0
  140. package/dist/scraper/ghl/extractor.d.ts.map +1 -0
  141. package/dist/scraper/ghl/extractor.js +345 -0
  142. package/dist/scraper/ghl/extractor.js.map +1 -0
  143. package/dist/scraper/ghl/index.d.ts +4 -0
  144. package/dist/scraper/ghl/index.d.ts.map +1 -0
  145. package/dist/scraper/ghl/index.js +4 -0
  146. package/dist/scraper/ghl/index.js.map +1 -0
  147. package/dist/scraper/ghl/navigator.d.ts +93 -0
  148. package/dist/scraper/ghl/navigator.d.ts.map +1 -0
  149. package/dist/scraper/ghl/navigator.js +447 -0
  150. package/dist/scraper/ghl/navigator.js.map +1 -0
  151. package/dist/scraper/highlevel/auth.d.ts +25 -0
  152. package/dist/scraper/highlevel/auth.d.ts.map +1 -0
  153. package/dist/scraper/highlevel/auth.js +189 -0
  154. package/dist/scraper/highlevel/auth.js.map +1 -0
  155. package/dist/scraper/highlevel/extractor.d.ts +97 -0
  156. package/dist/scraper/highlevel/extractor.d.ts.map +1 -0
  157. package/dist/scraper/highlevel/extractor.js +386 -0
  158. package/dist/scraper/highlevel/extractor.js.map +1 -0
  159. package/dist/scraper/highlevel/extractor.test.d.ts +2 -0
  160. package/dist/scraper/highlevel/extractor.test.d.ts.map +1 -0
  161. package/dist/scraper/highlevel/extractor.test.js +101 -0
  162. package/dist/scraper/highlevel/extractor.test.js.map +1 -0
  163. package/dist/scraper/highlevel/index.d.ts +3 -0
  164. package/dist/scraper/highlevel/index.d.ts.map +1 -0
  165. package/dist/scraper/highlevel/index.js +3 -0
  166. package/dist/scraper/highlevel/index.js.map +1 -0
  167. package/dist/scraper/highlevel/navigator.d.ts +93 -0
  168. package/dist/scraper/highlevel/navigator.d.ts.map +1 -0
  169. package/dist/scraper/highlevel/navigator.js +492 -0
  170. package/dist/scraper/highlevel/navigator.js.map +1 -0
  171. package/dist/scraper/highlevel/navigator.test.d.ts +2 -0
  172. package/dist/scraper/highlevel/navigator.test.d.ts.map +1 -0
  173. package/dist/scraper/highlevel/navigator.test.js +78 -0
  174. package/dist/scraper/highlevel/navigator.test.js.map +1 -0
  175. package/dist/scraper/navigator.d.ts +65 -0
  176. package/dist/scraper/navigator.d.ts.map +1 -0
  177. package/dist/scraper/navigator.js +300 -0
  178. package/dist/scraper/navigator.js.map +1 -0
  179. package/dist/scraper/navigator.test.d.ts +2 -0
  180. package/dist/scraper/navigator.test.d.ts.map +1 -0
  181. package/dist/scraper/navigator.test.js +63 -0
  182. package/dist/scraper/navigator.test.js.map +1 -0
  183. package/dist/scraper/skoolApi.d.ts +17 -0
  184. package/dist/scraper/skoolApi.d.ts.map +1 -0
  185. package/dist/scraper/skoolApi.js +72 -0
  186. package/dist/scraper/skoolApi.js.map +1 -0
  187. package/dist/scraper/videoInterceptor.d.ts +19 -0
  188. package/dist/scraper/videoInterceptor.d.ts.map +1 -0
  189. package/dist/scraper/videoInterceptor.js +315 -0
  190. package/dist/scraper/videoInterceptor.js.map +1 -0
  191. package/dist/shared/auth.d.ts +58 -0
  192. package/dist/shared/auth.d.ts.map +1 -0
  193. package/dist/shared/auth.js +211 -0
  194. package/dist/shared/auth.js.map +1 -0
  195. package/dist/shared/fs.d.ts +31 -0
  196. package/dist/shared/fs.d.ts.map +1 -0
  197. package/dist/shared/fs.js +73 -0
  198. package/dist/shared/fs.js.map +1 -0
  199. package/dist/shared/http.d.ts +15 -0
  200. package/dist/shared/http.d.ts.map +1 -0
  201. package/dist/shared/http.js +31 -0
  202. package/dist/shared/http.js.map +1 -0
  203. package/dist/shared/index.d.ts +4 -0
  204. package/dist/shared/index.d.ts.map +1 -0
  205. package/dist/shared/index.js +4 -0
  206. package/dist/shared/index.js.map +1 -0
  207. package/dist/state/database.d.ts +245 -0
  208. package/dist/state/database.d.ts.map +1 -0
  209. package/dist/state/database.js +676 -0
  210. package/dist/state/database.js.map +1 -0
  211. package/dist/state/database.test.d.ts +2 -0
  212. package/dist/state/database.test.d.ts.map +1 -0
  213. package/dist/state/database.test.js +34 -0
  214. package/dist/state/database.test.js.map +1 -0
  215. package/dist/state/index.d.ts +2 -0
  216. package/dist/state/index.d.ts.map +1 -0
  217. package/dist/state/index.js +2 -0
  218. package/dist/state/index.js.map +1 -0
  219. package/dist/storage/fileSystem.d.ts +56 -0
  220. package/dist/storage/fileSystem.d.ts.map +1 -0
  221. package/dist/storage/fileSystem.js +121 -0
  222. package/dist/storage/fileSystem.js.map +1 -0
  223. package/dist/transcription/whisperService.d.ts +27 -0
  224. package/dist/transcription/whisperService.d.ts.map +1 -0
  225. package/dist/transcription/whisperService.js +102 -0
  226. package/dist/transcription/whisperService.js.map +1 -0
  227. package/eslint.config.js +55 -0
  228. package/package.json +68 -11
  229. package/src/__fixtures__/highlevel-post-response.json +68 -0
  230. package/src/__fixtures__/hls-master-playlist.m3u8 +24 -0
  231. package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +38 -0
  232. package/src/cli/commands/config.ts +74 -0
  233. package/src/cli/commands/inspect.ts +441 -0
  234. package/src/cli/commands/login.ts +68 -0
  235. package/src/cli/commands/status.ts +147 -0
  236. package/src/cli/commands/sync.ts +1235 -0
  237. package/src/cli/commands/syncHighLevel.test.ts +144 -0
  238. package/src/cli/commands/syncHighLevel.ts +639 -0
  239. package/src/cli/index.ts +121 -0
  240. package/src/config/configManager.ts +75 -0
  241. package/src/config/paths.test.ts +83 -0
  242. package/src/config/paths.ts +36 -0
  243. package/src/config/schema.test.ts +173 -0
  244. package/src/config/schema.ts +65 -0
  245. package/src/downloader/hlsDownloader.test.ts +148 -0
  246. package/src/downloader/hlsDownloader.ts +327 -0
  247. package/src/downloader/hlsValidator.ts +196 -0
  248. package/src/downloader/index.ts +122 -0
  249. package/src/downloader/loomDownloader.test.ts +43 -0
  250. package/src/downloader/loomDownloader.ts +742 -0
  251. package/src/downloader/queue.test.ts +199 -0
  252. package/src/downloader/queue.ts +118 -0
  253. package/src/downloader/vimeoDownloader.test.ts +62 -0
  254. package/src/downloader/vimeoDownloader.ts +722 -0
  255. package/src/scraper/extractor.test.ts +124 -0
  256. package/src/scraper/extractor.ts +757 -0
  257. package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +41 -0
  258. package/src/scraper/highlevel/extractor.test.ts +134 -0
  259. package/src/scraper/highlevel/extractor.ts +537 -0
  260. package/src/scraper/highlevel/index.ts +2 -0
  261. package/src/scraper/highlevel/navigator.test.ts +110 -0
  262. package/src/scraper/highlevel/navigator.ts +668 -0
  263. package/src/scraper/highlevel/schemas.ts +183 -0
  264. package/src/scraper/navigator.test.ts +122 -0
  265. package/src/scraper/navigator.ts +355 -0
  266. package/src/scraper/schemas.ts +177 -0
  267. package/src/scraper/videoInterceptor.ts +435 -0
  268. package/src/shared/auth.test.ts +58 -0
  269. package/src/shared/auth.ts +251 -0
  270. package/src/shared/firebase.ts +151 -0
  271. package/src/shared/fs.ts +80 -0
  272. package/src/shared/http.ts +34 -0
  273. package/src/shared/index.ts +6 -0
  274. package/src/shared/slug.ts +26 -0
  275. package/src/shared/url.test.ts +122 -0
  276. package/src/shared/url.ts +57 -0
  277. package/src/state/database.test.ts +49 -0
  278. package/src/state/database.ts +919 -0
  279. package/src/state/index.ts +14 -0
  280. package/src/storage/fileSystem.test.ts +64 -0
  281. package/src/storage/fileSystem.ts +175 -0
  282. package/tsconfig.json +28 -0
  283. package/vitest.config.ts +29 -0
  284. package/cli.js +0 -45
@@ -0,0 +1,676 @@
1
+ import Database from "better-sqlite3";
2
+ import { existsSync, mkdirSync } from "node:fs";
3
+ import { dirname, join } from "node:path";
4
+ import { CACHE_DIR } from "../config/paths.js";
5
+ /**
6
+ * Lesson sync status.
7
+ */
8
+ export const LessonStatus = {
9
+ PENDING: "pending",
10
+ SCANNED: "scanned",
11
+ VALIDATED: "validated",
12
+ DOWNLOADED: "downloaded",
13
+ ERROR: "error",
14
+ SKIPPED: "skipped",
15
+ };
16
+ /**
17
+ * Video types supported by the tool.
18
+ */
19
+ export const VideoType = {
20
+ LOOM: "loom",
21
+ VIMEO: "vimeo",
22
+ YOUTUBE: "youtube",
23
+ WISTIA: "wistia",
24
+ NATIVE: "native",
25
+ UNKNOWN: "unknown",
26
+ };
27
+ /**
28
+ * Get the database directory path.
29
+ */
30
+ export function getDbDir() {
31
+ return CACHE_DIR;
32
+ }
33
+ /**
34
+ * Get the database file path for a course.
35
+ */
36
+ export function getDbPath(communitySlug) {
37
+ const safeSlug = communitySlug.replace(/[^a-zA-Z0-9-]/g, "_");
38
+ return join(getDbDir(), `${safeSlug}.db`);
39
+ }
40
+ /**
41
+ * Extract community slug from a Skool URL.
42
+ */
43
+ export function extractCommunitySlug(url) {
44
+ const match = /skool\.com\/([^/]+)/.exec(url);
45
+ return match?.[1] ?? "unknown";
46
+ }
47
+ /**
48
+ * Database manager for course state persistence.
49
+ */
50
+ export class CourseDatabase {
51
+ db;
52
+ constructor(communitySlug) {
53
+ const dbPath = getDbPath(communitySlug);
54
+ // Ensure directory exists
55
+ const dir = dirname(dbPath);
56
+ if (!existsSync(dir)) {
57
+ mkdirSync(dir, { recursive: true });
58
+ }
59
+ this.db = new Database(dbPath);
60
+ this.db.pragma("journal_mode = WAL");
61
+ this.initSchema();
62
+ }
63
+ /**
64
+ * Initialize database schema.
65
+ */
66
+ initSchema() {
67
+ this.db.exec(`
68
+ CREATE TABLE IF NOT EXISTS metadata (
69
+ key TEXT PRIMARY KEY,
70
+ value TEXT NOT NULL
71
+ );
72
+
73
+ CREATE TABLE IF NOT EXISTS modules (
74
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
75
+ slug TEXT UNIQUE NOT NULL,
76
+ name TEXT NOT NULL,
77
+ position INTEGER NOT NULL,
78
+ is_locked INTEGER DEFAULT 0,
79
+ created_at TEXT DEFAULT (datetime('now')),
80
+ updated_at TEXT DEFAULT (datetime('now'))
81
+ );
82
+
83
+ CREATE TABLE IF NOT EXISTS lessons (
84
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
85
+ module_id INTEGER NOT NULL,
86
+ slug TEXT NOT NULL,
87
+ name TEXT NOT NULL,
88
+ url TEXT NOT NULL,
89
+ position INTEGER NOT NULL,
90
+ is_locked INTEGER DEFAULT 0,
91
+ status TEXT DEFAULT 'pending',
92
+ video_type TEXT,
93
+ video_url TEXT,
94
+ hls_url TEXT,
95
+ error_message TEXT,
96
+ error_code TEXT,
97
+ last_scanned_at TEXT,
98
+ last_downloaded_at TEXT,
99
+ video_file_size INTEGER,
100
+ created_at TEXT DEFAULT (datetime('now')),
101
+ updated_at TEXT DEFAULT (datetime('now')),
102
+ FOREIGN KEY (module_id) REFERENCES modules(id),
103
+ UNIQUE(module_id, slug)
104
+ );
105
+
106
+ CREATE INDEX IF NOT EXISTS idx_lessons_status ON lessons(status);
107
+ CREATE INDEX IF NOT EXISTS idx_lessons_module ON lessons(module_id);
108
+ CREATE INDEX IF NOT EXISTS idx_lessons_locked ON lessons(is_locked);
109
+ `);
110
+ // Run migrations for existing databases
111
+ this.runMigrations();
112
+ }
113
+ /**
114
+ * Run database migrations for schema updates.
115
+ */
116
+ runMigrations() {
117
+ const tableInfo = this.db.prepare("PRAGMA table_info(lessons)").all();
118
+ // Migration: Add is_locked column if it doesn't exist
119
+ const hasIsLocked = tableInfo.some((col) => col.name === "is_locked");
120
+ if (!hasIsLocked) {
121
+ this.db.exec("ALTER TABLE lessons ADD COLUMN is_locked INTEGER DEFAULT 0");
122
+ }
123
+ // Migration: Add retry_count column if it doesn't exist
124
+ const hasRetryCount = tableInfo.some((col) => col.name === "retry_count");
125
+ if (!hasRetryCount) {
126
+ this.db.exec("ALTER TABLE lessons ADD COLUMN retry_count INTEGER DEFAULT 0");
127
+ }
128
+ }
129
+ /**
130
+ * Close the database connection.
131
+ */
132
+ close() {
133
+ this.db.close();
134
+ }
135
+ // ============================================
136
+ // Metadata Operations
137
+ // ============================================
138
+ /**
139
+ * Set a metadata value.
140
+ */
141
+ setMetadata(key, value) {
142
+ const stmt = this.db.prepare(`
143
+ INSERT INTO metadata (key, value) VALUES (?, ?)
144
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value
145
+ `);
146
+ stmt.run(key, value);
147
+ }
148
+ /**
149
+ * Get a metadata value.
150
+ */
151
+ getMetadata(key) {
152
+ const stmt = this.db.prepare("SELECT value FROM metadata WHERE key = ?");
153
+ const row = stmt.get(key);
154
+ return row?.value ?? null;
155
+ }
156
+ /**
157
+ * Get all course metadata.
158
+ */
159
+ getCourseMetadata() {
160
+ return {
161
+ name: this.getMetadata("course_name") ?? "Unknown Course",
162
+ url: this.getMetadata("course_url") ?? "",
163
+ lastSyncAt: this.getMetadata("last_sync_at"),
164
+ totalModules: this.getModuleCount(),
165
+ totalLessons: this.getLessonCount(),
166
+ };
167
+ }
168
+ /**
169
+ * Update course metadata after sync.
170
+ */
171
+ updateCourseMetadata(name, url) {
172
+ this.setMetadata("course_name", name);
173
+ this.setMetadata("course_url", url);
174
+ this.setMetadata("last_sync_at", new Date().toISOString());
175
+ }
176
+ // ============================================
177
+ // Module Operations
178
+ // ============================================
179
+ /**
180
+ * Upsert a module (insert or update).
181
+ */
182
+ upsertModule(slug, name, position, isLocked = false) {
183
+ const stmt = this.db.prepare(`
184
+ INSERT INTO modules (slug, name, position, is_locked, updated_at)
185
+ VALUES (?, ?, ?, ?, datetime('now'))
186
+ ON CONFLICT(slug) DO UPDATE SET
187
+ name = excluded.name,
188
+ position = excluded.position,
189
+ is_locked = excluded.is_locked,
190
+ updated_at = datetime('now')
191
+ RETURNING *
192
+ `);
193
+ const row = stmt.get(slug, name, position, isLocked ? 1 : 0);
194
+ return this.mapModuleRow(row);
195
+ }
196
+ /**
197
+ * Get all modules.
198
+ */
199
+ getModules() {
200
+ const stmt = this.db.prepare("SELECT * FROM modules ORDER BY position");
201
+ const rows = stmt.all();
202
+ return rows.map((row) => this.mapModuleRow(row));
203
+ }
204
+ /**
205
+ * Get module count.
206
+ */
207
+ getModuleCount() {
208
+ const stmt = this.db.prepare("SELECT COUNT(*) as count FROM modules");
209
+ const row = stmt.get();
210
+ return row.count;
211
+ }
212
+ /**
213
+ * Get module by slug.
214
+ */
215
+ getModuleBySlug(slug) {
216
+ const stmt = this.db.prepare("SELECT * FROM modules WHERE slug = ?");
217
+ const row = stmt.get(slug);
218
+ return row ? this.mapModuleRow(row) : null;
219
+ }
220
+ mapModuleRow(row) {
221
+ return {
222
+ id: row.id,
223
+ slug: row.slug,
224
+ name: row.name,
225
+ position: row.position,
226
+ isLocked: row.is_locked === 1,
227
+ createdAt: row.created_at,
228
+ updatedAt: row.updated_at,
229
+ };
230
+ }
231
+ // ============================================
232
+ // Lesson Operations
233
+ // ============================================
234
+ /**
235
+ * Upsert a lesson (insert or update).
236
+ */
237
+ upsertLesson(moduleId, slug, name, url, position, isLocked = false) {
238
+ const stmt = this.db.prepare(`
239
+ INSERT INTO lessons (module_id, slug, name, url, position, is_locked, updated_at)
240
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
241
+ ON CONFLICT(module_id, slug) DO UPDATE SET
242
+ name = excluded.name,
243
+ url = excluded.url,
244
+ position = excluded.position,
245
+ is_locked = excluded.is_locked,
246
+ updated_at = datetime('now')
247
+ RETURNING *
248
+ `);
249
+ const row = stmt.get(moduleId, slug, name, url, position, isLocked ? 1 : 0);
250
+ return this.mapLessonRow(row);
251
+ }
252
+ /**
253
+ * Update lesson scan results.
254
+ */
255
+ updateLessonScan(lessonId, videoType, videoUrl, hlsUrl, status, errorMessage, errorCode) {
256
+ const stmt = this.db.prepare(`
257
+ UPDATE lessons SET
258
+ video_type = ?,
259
+ video_url = ?,
260
+ hls_url = ?,
261
+ status = ?,
262
+ error_message = ?,
263
+ error_code = ?,
264
+ last_scanned_at = datetime('now'),
265
+ updated_at = datetime('now')
266
+ WHERE id = ?
267
+ `);
268
+ stmt.run(videoType, videoUrl, hlsUrl, status, errorMessage ?? null, errorCode ?? null, lessonId);
269
+ }
270
+ /**
271
+ * Mark lesson as downloaded.
272
+ */
273
+ markLessonDownloaded(lessonId, fileSize) {
274
+ const stmt = this.db.prepare(`
275
+ UPDATE lessons SET
276
+ status = 'downloaded',
277
+ last_downloaded_at = datetime('now'),
278
+ video_file_size = ?,
279
+ error_message = NULL,
280
+ error_code = NULL,
281
+ updated_at = datetime('now')
282
+ WHERE id = ?
283
+ `);
284
+ stmt.run(fileSize ?? null, lessonId);
285
+ }
286
+ /**
287
+ * Mark lesson as error.
288
+ */
289
+ markLessonError(lessonId, errorMessage, errorCode) {
290
+ const stmt = this.db.prepare(`
291
+ UPDATE lessons SET
292
+ status = 'error',
293
+ error_message = ?,
294
+ error_code = ?,
295
+ updated_at = datetime('now')
296
+ WHERE id = ?
297
+ `);
298
+ stmt.run(errorMessage, errorCode ?? null, lessonId);
299
+ }
300
+ /**
301
+ * Mark lesson as skipped (no video).
302
+ */
303
+ markLessonSkipped(lessonId, reason) {
304
+ const stmt = this.db.prepare(`
305
+ UPDATE lessons SET
306
+ status = 'skipped',
307
+ error_message = ?,
308
+ error_code = NULL,
309
+ updated_at = datetime('now')
310
+ WHERE id = ?
311
+ `);
312
+ stmt.run(reason ?? null, lessonId);
313
+ }
314
+ /**
315
+ * Update lesson video type.
316
+ */
317
+ updateLessonVideoType(lessonId, videoType) {
318
+ const stmt = this.db.prepare(`
319
+ UPDATE lessons SET
320
+ video_type = ?,
321
+ updated_at = datetime('now')
322
+ WHERE id = ?
323
+ `);
324
+ stmt.run(videoType, lessonId);
325
+ }
326
+ /**
327
+ * Increment retry count for a lesson.
328
+ */
329
+ incrementRetryCount(lessonId) {
330
+ const stmt = this.db.prepare(`
331
+ UPDATE lessons SET
332
+ retry_count = retry_count + 1,
333
+ updated_at = datetime('now')
334
+ WHERE id = ?
335
+ `);
336
+ stmt.run(lessonId);
337
+ // Return the new retry count
338
+ const getStmt = this.db.prepare("SELECT retry_count FROM lessons WHERE id = ?");
339
+ const row = getStmt.get(lessonId);
340
+ return row?.retry_count ?? 0;
341
+ }
342
+ /**
343
+ * Reset retry count for a lesson.
344
+ */
345
+ resetRetryCount(lessonId) {
346
+ const stmt = this.db.prepare(`
347
+ UPDATE lessons SET
348
+ retry_count = 0,
349
+ updated_at = datetime('now')
350
+ WHERE id = ?
351
+ `);
352
+ stmt.run(lessonId);
353
+ }
354
+ /**
355
+ * Get lessons that failed but can still be retried (retry_count < maxRetries).
356
+ * Only returns retryable errors (not UNSUPPORTED_PROVIDER).
357
+ */
358
+ getLessonsToRetry(maxRetries = 3) {
359
+ const stmt = this.db.prepare(`
360
+ SELECT
361
+ l.*,
362
+ m.name as module_name,
363
+ m.slug as module_slug,
364
+ m.position as module_position
365
+ FROM lessons l
366
+ JOIN modules m ON l.module_id = m.id
367
+ WHERE l.status = 'error'
368
+ AND l.retry_count < ?
369
+ AND (l.error_code IS NULL OR l.error_code NOT IN ('UNSUPPORTED_PROVIDER'))
370
+ ORDER BY m.position, l.position
371
+ `);
372
+ const rows = stmt.all(maxRetries);
373
+ return rows.map((row) => ({
374
+ ...this.mapLessonRow(row),
375
+ moduleName: row.module_name,
376
+ moduleSlug: row.module_slug,
377
+ modulePosition: row.module_position,
378
+ }));
379
+ }
380
+ /**
381
+ * Mark a lesson for retry by setting it back to pending/validated status.
382
+ */
383
+ queueForRetry(lessonId, targetStatus = LessonStatus.PENDING) {
384
+ const stmt = this.db.prepare(`
385
+ UPDATE lessons SET
386
+ status = ?,
387
+ error_message = NULL,
388
+ error_code = NULL,
389
+ updated_at = datetime('now')
390
+ WHERE id = ?
391
+ `);
392
+ stmt.run(targetStatus, lessonId);
393
+ }
394
+ /**
395
+ * Get all lessons.
396
+ */
397
+ getLessons() {
398
+ const stmt = this.db.prepare("SELECT * FROM lessons ORDER BY module_id, position");
399
+ const rows = stmt.all();
400
+ return rows.map((row) => this.mapLessonRow(row));
401
+ }
402
+ /**
403
+ * Get lessons with module info.
404
+ */
405
+ getLessonsWithModules() {
406
+ const stmt = this.db.prepare(`
407
+ SELECT
408
+ l.*,
409
+ m.name as module_name,
410
+ m.slug as module_slug,
411
+ m.position as module_position
412
+ FROM lessons l
413
+ JOIN modules m ON l.module_id = m.id
414
+ ORDER BY m.position, l.position
415
+ `);
416
+ const rows = stmt.all();
417
+ return rows.map((row) => ({
418
+ ...this.mapLessonRow(row),
419
+ moduleName: row.module_name,
420
+ moduleSlug: row.module_slug,
421
+ modulePosition: row.module_position,
422
+ }));
423
+ }
424
+ /**
425
+ * Get lessons by status.
426
+ */
427
+ getLessonsByStatus(status) {
428
+ const stmt = this.db.prepare(`
429
+ SELECT
430
+ l.*,
431
+ m.name as module_name,
432
+ m.slug as module_slug,
433
+ m.position as module_position
434
+ FROM lessons l
435
+ JOIN modules m ON l.module_id = m.id
436
+ WHERE l.status = ?
437
+ ORDER BY m.position, l.position
438
+ `);
439
+ const rows = stmt.all(status);
440
+ return rows.map((row) => ({
441
+ ...this.mapLessonRow(row),
442
+ moduleName: row.module_name,
443
+ moduleSlug: row.module_slug,
444
+ modulePosition: row.module_position,
445
+ }));
446
+ }
447
+ /**
448
+ * Get lessons that need scanning (pending or never scanned).
449
+ */
450
+ getLessonsToScan() {
451
+ const stmt = this.db.prepare(`
452
+ SELECT
453
+ l.*,
454
+ m.name as module_name,
455
+ m.slug as module_slug,
456
+ m.position as module_position
457
+ FROM lessons l
458
+ JOIN modules m ON l.module_id = m.id
459
+ WHERE (l.status = 'pending' OR l.last_scanned_at IS NULL)
460
+ AND l.is_locked = 0
461
+ ORDER BY m.position, l.position
462
+ `);
463
+ const rows = stmt.all();
464
+ return rows.map((row) => ({
465
+ ...this.mapLessonRow(row),
466
+ moduleName: row.module_name,
467
+ moduleSlug: row.module_slug,
468
+ modulePosition: row.module_position,
469
+ }));
470
+ }
471
+ /**
472
+ * Get lessons that need validation (scanned but not validated, with video).
473
+ */
474
+ getLessonsToValidate() {
475
+ const stmt = this.db.prepare(`
476
+ SELECT
477
+ l.*,
478
+ m.name as module_name,
479
+ m.slug as module_slug,
480
+ m.position as module_position
481
+ FROM lessons l
482
+ JOIN modules m ON l.module_id = m.id
483
+ WHERE l.status = 'scanned'
484
+ AND l.video_url IS NOT NULL
485
+ AND l.is_locked = 0
486
+ ORDER BY m.position, l.position
487
+ `);
488
+ const rows = stmt.all();
489
+ return rows.map((row) => ({
490
+ ...this.mapLessonRow(row),
491
+ moduleName: row.module_name,
492
+ moduleSlug: row.module_slug,
493
+ modulePosition: row.module_position,
494
+ }));
495
+ }
496
+ /**
497
+ * Get lessons that are ready for download (validated with HLS URL).
498
+ */
499
+ getLessonsToDownload() {
500
+ const stmt = this.db.prepare(`
501
+ SELECT
502
+ l.*,
503
+ m.name as module_name,
504
+ m.slug as module_slug,
505
+ m.position as module_position
506
+ FROM lessons l
507
+ JOIN modules m ON l.module_id = m.id
508
+ WHERE l.status = 'validated' AND l.hls_url IS NOT NULL
509
+ ORDER BY m.position, l.position
510
+ `);
511
+ const rows = stmt.all();
512
+ return rows.map((row) => ({
513
+ ...this.mapLessonRow(row),
514
+ moduleName: row.module_name,
515
+ moduleSlug: row.module_slug,
516
+ modulePosition: row.module_position,
517
+ }));
518
+ }
519
+ /**
520
+ * Get lesson count.
521
+ */
522
+ getLessonCount() {
523
+ const stmt = this.db.prepare("SELECT COUNT(*) as count FROM lessons");
524
+ const row = stmt.get();
525
+ return row.count;
526
+ }
527
+ /**
528
+ * Get lesson by URL.
529
+ */
530
+ getLessonByUrl(url) {
531
+ const stmt = this.db.prepare("SELECT * FROM lessons WHERE url = ?");
532
+ const row = stmt.get(url);
533
+ return row ? this.mapLessonRow(row) : null;
534
+ }
535
+ /**
536
+ * Get status summary.
537
+ */
538
+ getStatusSummary() {
539
+ const stmt = this.db.prepare(`
540
+ SELECT status, COUNT(*) as count FROM lessons GROUP BY status
541
+ `);
542
+ const rows = stmt.all();
543
+ const summary = {
544
+ pending: 0,
545
+ scanned: 0,
546
+ validated: 0,
547
+ downloaded: 0,
548
+ error: 0,
549
+ skipped: 0,
550
+ locked: 0,
551
+ };
552
+ for (const row of rows) {
553
+ summary[row.status] = row.count;
554
+ }
555
+ // Count locked lessons separately
556
+ const lockedStmt = this.db.prepare(`SELECT COUNT(*) as count FROM lessons WHERE is_locked = 1`);
557
+ const lockedRow = lockedStmt.get();
558
+ summary.locked = lockedRow.count;
559
+ return summary;
560
+ }
561
+ /**
562
+ * Reset all error lessons to pending for retry.
563
+ */
564
+ resetErrorLessons() {
565
+ const stmt = this.db.prepare(`
566
+ UPDATE lessons SET
567
+ status = 'pending',
568
+ error_message = NULL,
569
+ error_code = NULL,
570
+ updated_at = datetime('now')
571
+ WHERE status = 'error'
572
+ `);
573
+ const result = stmt.run();
574
+ return result.changes;
575
+ }
576
+ /**
577
+ * Reset ALL lessons to pending (for --force full rescan).
578
+ * Preserves locked status.
579
+ */
580
+ resetAllLessonsToPending() {
581
+ const stmt = this.db.prepare(`
582
+ UPDATE lessons SET
583
+ status = 'pending',
584
+ video_type = NULL,
585
+ video_url = NULL,
586
+ hls_url = NULL,
587
+ error_message = NULL,
588
+ error_code = NULL,
589
+ retry_count = 0,
590
+ updated_at = datetime('now')
591
+ WHERE is_locked = 0
592
+ `);
593
+ const result = stmt.run();
594
+ return result.changes;
595
+ }
596
+ /**
597
+ * Reset error lessons to validated (for --resume --retry-errors).
598
+ * Only resets lessons that already have an HLS URL.
599
+ */
600
+ resetErrorLessonsForResume() {
601
+ const stmt = this.db.prepare(`
602
+ UPDATE lessons SET
603
+ status = 'validated',
604
+ error_message = NULL,
605
+ error_code = NULL,
606
+ updated_at = datetime('now')
607
+ WHERE status = 'error' AND hls_url IS NOT NULL
608
+ `);
609
+ const result = stmt.run();
610
+ return result.changes;
611
+ }
612
+ /**
613
+ * Get lessons by error code.
614
+ */
615
+ getLessonsByErrorCode(errorCode) {
616
+ const stmt = this.db.prepare(`
617
+ SELECT
618
+ l.*,
619
+ m.name as module_name,
620
+ m.slug as module_slug,
621
+ m.position as module_position
622
+ FROM lessons l
623
+ JOIN modules m ON l.module_id = m.id
624
+ WHERE l.error_code = ?
625
+ ORDER BY m.position, l.position
626
+ `);
627
+ const rows = stmt.all(errorCode);
628
+ return rows.map((row) => ({
629
+ ...this.mapLessonRow(row),
630
+ moduleName: row.module_name,
631
+ moduleSlug: row.module_slug,
632
+ modulePosition: row.module_position,
633
+ }));
634
+ }
635
+ /**
636
+ * Get count of lessons grouped by video type.
637
+ */
638
+ getVideoTypeSummary() {
639
+ const stmt = this.db.prepare(`
640
+ SELECT video_type, COUNT(*) as count
641
+ FROM lessons
642
+ WHERE video_type IS NOT NULL
643
+ GROUP BY video_type
644
+ `);
645
+ const rows = stmt.all();
646
+ const summary = {};
647
+ for (const row of rows) {
648
+ summary[row.video_type] = row.count;
649
+ }
650
+ return summary;
651
+ }
652
+ mapLessonRow(row) {
653
+ return {
654
+ id: row.id,
655
+ moduleId: row.module_id,
656
+ slug: row.slug,
657
+ name: row.name,
658
+ url: row.url,
659
+ position: row.position,
660
+ isLocked: row.is_locked === 1,
661
+ status: row.status,
662
+ videoType: row.video_type,
663
+ videoUrl: row.video_url,
664
+ hlsUrl: row.hls_url,
665
+ errorMessage: row.error_message,
666
+ errorCode: row.error_code,
667
+ retryCount: row.retry_count ?? 0,
668
+ lastScannedAt: row.last_scanned_at,
669
+ lastDownloadedAt: row.last_downloaded_at,
670
+ videoFileSize: row.video_file_size,
671
+ createdAt: row.created_at,
672
+ updatedAt: row.updated_at,
673
+ };
674
+ }
675
+ }
676
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/state/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=database.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.test.d.ts","sourceRoot":"","sources":["../../src/state/database.test.ts"],"names":[],"mappings":""}