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.
- package/README.md +107 -8
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/inspect.js +1 -1
- package/dist/cli/commands/inspect.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +1 -2
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/sync.js +17 -15
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/commands/syncHighLevel.d.ts +1 -2
- package/dist/cli/commands/syncHighLevel.d.ts.map +1 -1
- package/dist/cli/commands/syncHighLevel.js +8 -9
- package/dist/cli/commands/syncHighLevel.js.map +1 -1
- package/dist/cli/commands/syncLearningSuite.d.ts +35 -0
- package/dist/cli/commands/syncLearningSuite.d.ts.map +1 -0
- package/dist/cli/commands/syncLearningSuite.js +765 -0
- package/dist/cli/commands/syncLearningSuite.js.map +1 -0
- package/dist/cli/index.js +39 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/config/configManager.d.ts.map +1 -1
- package/dist/config/configManager.js +4 -0
- package/dist/config/configManager.js.map +1 -1
- package/dist/downloader/hlsDownloader.d.ts +10 -4
- package/dist/downloader/hlsDownloader.d.ts.map +1 -1
- package/dist/downloader/hlsDownloader.js +60 -29
- package/dist/downloader/hlsDownloader.js.map +1 -1
- package/dist/downloader/hlsValidator.d.ts.map +1 -1
- package/dist/downloader/hlsValidator.js +6 -2
- package/dist/downloader/hlsValidator.js.map +1 -1
- package/dist/downloader/index.d.ts +7 -0
- package/dist/downloader/index.d.ts.map +1 -1
- package/dist/downloader/index.js +9 -6
- package/dist/downloader/index.js.map +1 -1
- package/dist/downloader/loomDownloader.d.ts +1 -1
- package/dist/downloader/loomDownloader.d.ts.map +1 -1
- package/dist/downloader/loomDownloader.js +32 -27
- package/dist/downloader/loomDownloader.js.map +1 -1
- package/dist/downloader/queue.d.ts +4 -4
- package/dist/downloader/queue.d.ts.map +1 -1
- package/dist/downloader/queue.js.map +1 -1
- package/dist/downloader/vimeoDownloader.d.ts.map +1 -1
- package/dist/downloader/vimeoDownloader.js +7 -3
- package/dist/downloader/vimeoDownloader.js.map +1 -1
- package/dist/scraper/extractor.d.ts +4 -0
- package/dist/scraper/extractor.d.ts.map +1 -1
- package/dist/scraper/extractor.js +79 -79
- package/dist/scraper/extractor.js.map +1 -1
- package/dist/scraper/highlevel/extractor.d.ts +11 -19
- package/dist/scraper/highlevel/extractor.d.ts.map +1 -1
- package/dist/scraper/highlevel/extractor.js +72 -85
- package/dist/scraper/highlevel/extractor.js.map +1 -1
- package/dist/scraper/highlevel/navigator.d.ts +3 -10
- package/dist/scraper/highlevel/navigator.d.ts.map +1 -1
- package/dist/scraper/highlevel/navigator.js +140 -127
- package/dist/scraper/highlevel/navigator.js.map +1 -1
- package/dist/scraper/highlevel/schemas.d.ts +188 -0
- package/dist/scraper/highlevel/schemas.d.ts.map +1 -0
- package/dist/scraper/highlevel/schemas.js +139 -0
- package/dist/scraper/highlevel/schemas.js.map +1 -0
- package/dist/scraper/learningsuite/extractor.d.ts +50 -0
- package/dist/scraper/learningsuite/extractor.d.ts.map +1 -0
- package/dist/scraper/learningsuite/extractor.js +429 -0
- package/dist/scraper/learningsuite/extractor.js.map +1 -0
- package/dist/scraper/learningsuite/index.d.ts +4 -0
- package/dist/scraper/learningsuite/index.d.ts.map +1 -0
- package/dist/scraper/{ghl → learningsuite}/index.js +1 -1
- package/dist/scraper/learningsuite/index.js.map +1 -0
- package/dist/scraper/learningsuite/navigator.d.ts +122 -0
- package/dist/scraper/learningsuite/navigator.d.ts.map +1 -0
- package/dist/scraper/learningsuite/navigator.js +736 -0
- package/dist/scraper/learningsuite/navigator.js.map +1 -0
- package/dist/scraper/learningsuite/schemas.d.ts +270 -0
- package/dist/scraper/learningsuite/schemas.d.ts.map +1 -0
- package/dist/scraper/learningsuite/schemas.js +147 -0
- package/dist/scraper/learningsuite/schemas.js.map +1 -0
- package/dist/scraper/navigator.d.ts +14 -11
- package/dist/scraper/navigator.d.ts.map +1 -1
- package/dist/scraper/navigator.js +61 -104
- package/dist/scraper/navigator.js.map +1 -1
- package/dist/scraper/schemas.d.ts +57 -0
- package/dist/scraper/schemas.d.ts.map +1 -0
- package/dist/scraper/schemas.js +135 -0
- package/dist/scraper/schemas.js.map +1 -0
- package/dist/scraper/videoInterceptor.d.ts +4 -0
- package/dist/scraper/videoInterceptor.d.ts.map +1 -1
- package/dist/scraper/videoInterceptor.js +66 -51
- package/dist/scraper/videoInterceptor.js.map +1 -1
- package/dist/shared/auth.d.ts +9 -9
- package/dist/shared/auth.d.ts.map +1 -1
- package/dist/shared/auth.js +24 -38
- package/dist/shared/auth.js.map +1 -1
- package/dist/shared/firebase.d.ts +60 -0
- package/dist/shared/firebase.d.ts.map +1 -0
- package/dist/shared/firebase.js +102 -0
- package/dist/shared/firebase.js.map +1 -0
- package/dist/shared/fs.d.ts.map +1 -1
- package/dist/shared/fs.js +4 -0
- package/dist/shared/fs.js.map +1 -1
- package/dist/shared/index.d.ts +3 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +3 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/slug.d.ts +11 -0
- package/dist/shared/slug.d.ts.map +1 -0
- package/{src/shared/slug.ts → dist/shared/slug.js} +10 -11
- package/dist/shared/slug.js.map +1 -0
- package/dist/shared/url.d.ts +43 -0
- package/dist/shared/url.d.ts.map +1 -0
- package/{src/shared/url.ts → dist/shared/url.js} +12 -15
- package/dist/shared/url.js.map +1 -0
- package/dist/state/database.d.ts +1 -0
- package/dist/state/database.d.ts.map +1 -1
- package/dist/state/database.js +3 -0
- package/dist/state/database.js.map +1 -1
- package/dist/storage/fileSystem.d.ts +17 -17
- package/dist/storage/fileSystem.d.ts.map +1 -1
- package/dist/storage/fileSystem.js +39 -31
- package/dist/storage/fileSystem.js.map +1 -1
- package/package.json +5 -2
- package/.github/workflows/ci.yml +0 -50
- package/.husky/commit-msg +0 -2
- package/.husky/pre-commit +0 -1
- package/.husky/pre-push +0 -3
- package/.prettierrc +0 -8
- package/.release-it.json +0 -23
- package/ARCHITECTURE.md +0 -233
- package/CHANGELOG.md +0 -78
- package/commitlint.config.js +0 -4
- package/dist/ai/openRouter.d.ts +0 -47
- package/dist/ai/openRouter.d.ts.map +0 -1
- package/dist/ai/openRouter.js +0 -116
- package/dist/ai/openRouter.js.map +0 -1
- package/dist/ai/transcriptPolisher.d.ts +0 -24
- package/dist/ai/transcriptPolisher.d.ts.map +0 -1
- package/dist/ai/transcriptPolisher.js +0 -89
- package/dist/ai/transcriptPolisher.js.map +0 -1
- package/dist/cli/commands/enrich.d.ts +0 -14
- package/dist/cli/commands/enrich.d.ts.map +0 -1
- package/dist/cli/commands/enrich.js +0 -271
- package/dist/cli/commands/enrich.js.map +0 -1
- package/dist/cli/commands/syncGhl.d.ts +0 -20
- package/dist/cli/commands/syncGhl.d.ts.map +0 -1
- package/dist/cli/commands/syncGhl.js +0 -483
- package/dist/cli/commands/syncGhl.js.map +0 -1
- package/dist/cli/commands/syncHighLevel.test.d.ts +0 -2
- package/dist/cli/commands/syncHighLevel.test.d.ts.map +0 -1
- package/dist/cli/commands/syncHighLevel.test.js +0 -102
- package/dist/cli/commands/syncHighLevel.test.js.map +0 -1
- package/dist/config/paths.test.d.ts +0 -2
- package/dist/config/paths.test.d.ts.map +0 -1
- package/dist/config/paths.test.js +0 -70
- package/dist/config/paths.test.js.map +0 -1
- package/dist/config/schema.test.d.ts +0 -2
- package/dist/config/schema.test.d.ts.map +0 -1
- package/dist/config/schema.test.js +0 -151
- package/dist/config/schema.test.js.map +0 -1
- package/dist/downloader/hlsDownloader.test.d.ts +0 -2
- package/dist/downloader/hlsDownloader.test.d.ts.map +0 -1
- package/dist/downloader/hlsDownloader.test.js +0 -116
- package/dist/downloader/hlsDownloader.test.js.map +0 -1
- package/dist/downloader/loomDownloader.test.d.ts +0 -2
- package/dist/downloader/loomDownloader.test.d.ts.map +0 -1
- package/dist/downloader/loomDownloader.test.js +0 -36
- package/dist/downloader/loomDownloader.test.js.map +0 -1
- package/dist/downloader/queue.test.d.ts +0 -2
- package/dist/downloader/queue.test.d.ts.map +0 -1
- package/dist/downloader/queue.test.js +0 -158
- package/dist/downloader/queue.test.js.map +0 -1
- package/dist/downloader/videoDownloader.d.ts +0 -32
- package/dist/downloader/videoDownloader.d.ts.map +0 -1
- package/dist/downloader/videoDownloader.js +0 -173
- package/dist/downloader/videoDownloader.js.map +0 -1
- package/dist/downloader/vimeoDownloader.test.d.ts +0 -2
- package/dist/downloader/vimeoDownloader.test.d.ts.map +0 -1
- package/dist/downloader/vimeoDownloader.test.js +0 -51
- package/dist/downloader/vimeoDownloader.test.js.map +0 -1
- package/dist/scraper/auth.d.ts +0 -29
- package/dist/scraper/auth.d.ts.map +0 -1
- package/dist/scraper/auth.js +0 -115
- package/dist/scraper/auth.js.map +0 -1
- package/dist/scraper/extractor.test.d.ts +0 -2
- package/dist/scraper/extractor.test.d.ts.map +0 -1
- package/dist/scraper/extractor.test.js +0 -65
- package/dist/scraper/extractor.test.js.map +0 -1
- package/dist/scraper/ghl/auth.d.ts +0 -25
- package/dist/scraper/ghl/auth.d.ts.map +0 -1
- package/dist/scraper/ghl/auth.js +0 -187
- package/dist/scraper/ghl/auth.js.map +0 -1
- package/dist/scraper/ghl/extractor.d.ts +0 -96
- package/dist/scraper/ghl/extractor.d.ts.map +0 -1
- package/dist/scraper/ghl/extractor.js +0 -345
- package/dist/scraper/ghl/extractor.js.map +0 -1
- package/dist/scraper/ghl/index.d.ts +0 -4
- package/dist/scraper/ghl/index.d.ts.map +0 -1
- package/dist/scraper/ghl/index.js.map +0 -1
- package/dist/scraper/ghl/navigator.d.ts +0 -93
- package/dist/scraper/ghl/navigator.d.ts.map +0 -1
- package/dist/scraper/ghl/navigator.js +0 -447
- package/dist/scraper/ghl/navigator.js.map +0 -1
- package/dist/scraper/highlevel/auth.d.ts +0 -25
- package/dist/scraper/highlevel/auth.d.ts.map +0 -1
- package/dist/scraper/highlevel/auth.js +0 -189
- package/dist/scraper/highlevel/auth.js.map +0 -1
- package/dist/scraper/highlevel/extractor.test.d.ts +0 -2
- package/dist/scraper/highlevel/extractor.test.d.ts.map +0 -1
- package/dist/scraper/highlevel/extractor.test.js +0 -101
- package/dist/scraper/highlevel/extractor.test.js.map +0 -1
- package/dist/scraper/highlevel/navigator.test.d.ts +0 -2
- package/dist/scraper/highlevel/navigator.test.d.ts.map +0 -1
- package/dist/scraper/highlevel/navigator.test.js +0 -78
- package/dist/scraper/highlevel/navigator.test.js.map +0 -1
- package/dist/scraper/navigator.test.d.ts +0 -2
- package/dist/scraper/navigator.test.d.ts.map +0 -1
- package/dist/scraper/navigator.test.js +0 -63
- package/dist/scraper/navigator.test.js.map +0 -1
- package/dist/scraper/skoolApi.d.ts +0 -17
- package/dist/scraper/skoolApi.d.ts.map +0 -1
- package/dist/scraper/skoolApi.js +0 -72
- package/dist/scraper/skoolApi.js.map +0 -1
- package/dist/state/database.test.d.ts +0 -2
- package/dist/state/database.test.d.ts.map +0 -1
- package/dist/state/database.test.js +0 -34
- package/dist/state/database.test.js.map +0 -1
- package/dist/transcription/whisperService.d.ts +0 -27
- package/dist/transcription/whisperService.d.ts.map +0 -1
- package/dist/transcription/whisperService.js +0 -102
- package/dist/transcription/whisperService.js.map +0 -1
- package/eslint.config.js +0 -55
- package/src/__fixtures__/highlevel-post-response.json +0 -68
- package/src/__fixtures__/hls-master-playlist.m3u8 +0 -24
- package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +0 -38
- package/src/cli/commands/config.ts +0 -74
- package/src/cli/commands/inspect.ts +0 -441
- package/src/cli/commands/login.ts +0 -68
- package/src/cli/commands/status.ts +0 -147
- package/src/cli/commands/sync.ts +0 -1235
- package/src/cli/commands/syncHighLevel.test.ts +0 -144
- package/src/cli/commands/syncHighLevel.ts +0 -639
- package/src/cli/index.ts +0 -121
- package/src/config/configManager.ts +0 -75
- package/src/config/paths.test.ts +0 -83
- package/src/config/paths.ts +0 -36
- package/src/config/schema.test.ts +0 -173
- package/src/config/schema.ts +0 -65
- package/src/downloader/hlsDownloader.test.ts +0 -148
- package/src/downloader/hlsDownloader.ts +0 -327
- package/src/downloader/hlsValidator.ts +0 -196
- package/src/downloader/index.ts +0 -122
- package/src/downloader/loomDownloader.test.ts +0 -43
- package/src/downloader/loomDownloader.ts +0 -742
- package/src/downloader/queue.test.ts +0 -199
- package/src/downloader/queue.ts +0 -118
- package/src/downloader/vimeoDownloader.test.ts +0 -62
- package/src/downloader/vimeoDownloader.ts +0 -722
- package/src/scraper/extractor.test.ts +0 -124
- package/src/scraper/extractor.ts +0 -757
- package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +0 -41
- package/src/scraper/highlevel/extractor.test.ts +0 -134
- package/src/scraper/highlevel/extractor.ts +0 -537
- package/src/scraper/highlevel/index.ts +0 -2
- package/src/scraper/highlevel/navigator.test.ts +0 -110
- package/src/scraper/highlevel/navigator.ts +0 -668
- package/src/scraper/highlevel/schemas.ts +0 -183
- package/src/scraper/navigator.test.ts +0 -122
- package/src/scraper/navigator.ts +0 -355
- package/src/scraper/schemas.ts +0 -177
- package/src/scraper/videoInterceptor.ts +0 -435
- package/src/shared/auth.test.ts +0 -58
- package/src/shared/auth.ts +0 -251
- package/src/shared/firebase.ts +0 -151
- package/src/shared/fs.ts +0 -80
- package/src/shared/http.ts +0 -34
- package/src/shared/index.ts +0 -6
- package/src/shared/url.test.ts +0 -122
- package/src/state/database.test.ts +0 -49
- package/src/state/database.ts +0 -919
- package/src/state/index.ts +0 -14
- package/src/storage/fileSystem.test.ts +0 -64
- package/src/storage/fileSystem.ts +0 -175
- package/tsconfig.json +0 -28
- package/vitest.config.ts +0 -29
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for HighLevel API responses.
|
|
3
|
+
* These provide runtime validation and type inference.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
// Re-export Firebase auth types (Firebase is used by HighLevel for auth)
|
|
7
|
+
export { FirebaseAuthTokenSchema, } from "../../shared/firebase.js";
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Portal Settings API
|
|
10
|
+
// ============================================================================
|
|
11
|
+
export const PortalSettingsResponseSchema = z.object({
|
|
12
|
+
locationId: z.string(),
|
|
13
|
+
portalName: z.string().optional(),
|
|
14
|
+
name: z.string().optional(),
|
|
15
|
+
});
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Video License API
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export const VideoLicenseResponseSchema = z.object({
|
|
20
|
+
url: z.string(),
|
|
21
|
+
token: z.string(),
|
|
22
|
+
});
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Post Details API
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const VideoAssetSchema = z.object({
|
|
27
|
+
id: z.string().optional(),
|
|
28
|
+
assetId: z.string().optional(),
|
|
29
|
+
assetsLicenseId: z.string().optional(),
|
|
30
|
+
url: z.string().optional(),
|
|
31
|
+
});
|
|
32
|
+
const PosterImageSchema = z.object({
|
|
33
|
+
assetId: z.string().optional(),
|
|
34
|
+
url: z.string().optional(),
|
|
35
|
+
});
|
|
36
|
+
const ContentBlockSchema = z.object({
|
|
37
|
+
type: z.string(),
|
|
38
|
+
id: z.string().optional(),
|
|
39
|
+
assetId: z.string().optional(),
|
|
40
|
+
assetsLicenseId: z.string().optional(),
|
|
41
|
+
url: z.string().optional(),
|
|
42
|
+
});
|
|
43
|
+
const MaterialSchema = z.object({
|
|
44
|
+
id: z.string().optional(),
|
|
45
|
+
name: z.string().optional(),
|
|
46
|
+
url: z.string().optional(),
|
|
47
|
+
type: z.string().optional(),
|
|
48
|
+
});
|
|
49
|
+
export const PostDetailsSchema = z.object({
|
|
50
|
+
title: z.string().optional(),
|
|
51
|
+
description: z.string().nullable().optional(),
|
|
52
|
+
video: VideoAssetSchema.nullable().optional(),
|
|
53
|
+
posterImage: PosterImageSchema.nullable().optional(),
|
|
54
|
+
contentBlock: z.array(ContentBlockSchema).optional(),
|
|
55
|
+
materials: z.array(MaterialSchema).optional(),
|
|
56
|
+
post_materials: z.array(MaterialSchema).optional(),
|
|
57
|
+
});
|
|
58
|
+
// Response can have data directly or wrapped in "post"
|
|
59
|
+
export const PostDetailsResponseSchema = z.object({
|
|
60
|
+
post: PostDetailsSchema.optional(),
|
|
61
|
+
// Also allow all post fields directly on root
|
|
62
|
+
title: z.string().optional(),
|
|
63
|
+
description: z.string().nullable().optional(),
|
|
64
|
+
video: VideoAssetSchema.nullable().optional(),
|
|
65
|
+
posterImage: PosterImageSchema.nullable().optional(),
|
|
66
|
+
contentBlock: z.array(ContentBlockSchema).optional(),
|
|
67
|
+
materials: z.array(MaterialSchema).optional(),
|
|
68
|
+
post_materials: z.array(MaterialSchema).optional(),
|
|
69
|
+
});
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Categories API
|
|
72
|
+
// ============================================================================
|
|
73
|
+
export const CategorySchema = z.object({
|
|
74
|
+
id: z.string(),
|
|
75
|
+
title: z.string(),
|
|
76
|
+
description: z.string().nullable().optional(),
|
|
77
|
+
position: z.number().optional(),
|
|
78
|
+
postCount: z.number().optional(),
|
|
79
|
+
visibility: z.string().optional(),
|
|
80
|
+
});
|
|
81
|
+
export const CategoriesResponseSchema = z.object({
|
|
82
|
+
categories: z.array(CategorySchema),
|
|
83
|
+
});
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// Posts (Lessons) API
|
|
86
|
+
// ============================================================================
|
|
87
|
+
export const PostSchema = z.object({
|
|
88
|
+
id: z.string(),
|
|
89
|
+
title: z.string(),
|
|
90
|
+
indexPosition: z.number().optional(),
|
|
91
|
+
visibility: z.string().optional(),
|
|
92
|
+
});
|
|
93
|
+
export const PostsResponseSchema = z.object({
|
|
94
|
+
category: z
|
|
95
|
+
.object({
|
|
96
|
+
posts: z.array(PostSchema),
|
|
97
|
+
})
|
|
98
|
+
.optional(),
|
|
99
|
+
});
|
|
100
|
+
// ============================================================================
|
|
101
|
+
// Product (Course) API
|
|
102
|
+
// ============================================================================
|
|
103
|
+
export const ProductSchema = z.object({
|
|
104
|
+
id: z.string().optional(),
|
|
105
|
+
title: z.string(),
|
|
106
|
+
description: z.string().optional(),
|
|
107
|
+
posterImage: z.string().nullable().optional(),
|
|
108
|
+
instructor: z.string().nullable().optional(),
|
|
109
|
+
postCount: z.number().optional(),
|
|
110
|
+
});
|
|
111
|
+
export const ProductResponseSchema = z.object({
|
|
112
|
+
product: ProductSchema.optional(),
|
|
113
|
+
// Also allow fields directly on root
|
|
114
|
+
id: z.string().optional(),
|
|
115
|
+
title: z.string().optional(),
|
|
116
|
+
description: z.string().optional(),
|
|
117
|
+
posterImage: z.string().nullable().optional(),
|
|
118
|
+
instructor: z.string().nullable().optional(),
|
|
119
|
+
postCount: z.number().optional(),
|
|
120
|
+
});
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// Helper: Safe parse with logging
|
|
123
|
+
// ============================================================================
|
|
124
|
+
/**
|
|
125
|
+
* Safely parses data with a Zod schema.
|
|
126
|
+
* Returns the parsed data or null if validation fails.
|
|
127
|
+
* Logs validation errors for debugging.
|
|
128
|
+
*/
|
|
129
|
+
export function safeParse(schema, data, context) {
|
|
130
|
+
const result = schema.safeParse(data);
|
|
131
|
+
if (result.success) {
|
|
132
|
+
return result.data;
|
|
133
|
+
}
|
|
134
|
+
if (context) {
|
|
135
|
+
console.warn(`[${context}] Validation failed:`, z.treeifyError(result.error));
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../../src/scraper/highlevel/schemas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
export interface LearningSuiteVideoInfo {
|
|
3
|
+
type: "hls" | "vimeo" | "loom" | "youtube" | "wistia" | "native" | "unknown";
|
|
4
|
+
url: string;
|
|
5
|
+
hlsUrl?: string;
|
|
6
|
+
thumbnailUrl?: string;
|
|
7
|
+
duration?: number;
|
|
8
|
+
}
|
|
9
|
+
export interface LearningSuitePostContent {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string | null;
|
|
13
|
+
htmlContent: string | null;
|
|
14
|
+
video: LearningSuiteVideoInfo | null;
|
|
15
|
+
attachments: {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
url: string;
|
|
19
|
+
type: string;
|
|
20
|
+
size?: number;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Detects the video type from a URL.
|
|
25
|
+
*/
|
|
26
|
+
export declare function detectVideoType(url: string): LearningSuiteVideoInfo["type"];
|
|
27
|
+
/**
|
|
28
|
+
* Extracts video information from a lesson page.
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractVideoFromPage(page: Page): Promise<LearningSuiteVideoInfo | null>;
|
|
31
|
+
/**
|
|
32
|
+
* Extracts HTML content from the lesson page using semantic HTML structure.
|
|
33
|
+
* Uses accessibility-friendly selectors: main element, semantic headings, paragraphs, lists.
|
|
34
|
+
* Falls back to data-* attributes which are also stable.
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractHtmlContent(page: Page): Promise<string | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Extracts attachments/materials from the lesson page.
|
|
39
|
+
*/
|
|
40
|
+
export declare function extractAttachmentsFromPage(page: Page): Promise<LearningSuitePostContent["attachments"]>;
|
|
41
|
+
/**
|
|
42
|
+
* Extracts complete lesson content using DOM-based extraction with network interception.
|
|
43
|
+
* Note: LearningSuite uses persisted GraphQL queries, so we can't make arbitrary API calls.
|
|
44
|
+
*/
|
|
45
|
+
export declare function extractLearningSuitePostContent(page: Page, lessonUrl: string, _tenantId: string, _courseId: string, lessonId: string): Promise<LearningSuitePostContent | null>;
|
|
46
|
+
/**
|
|
47
|
+
* Intercepts network requests to capture video URLs during page load.
|
|
48
|
+
*/
|
|
49
|
+
export declare function interceptVideoRequests(page: Page, lessonUrl: string): Promise<LearningSuiteVideoInfo | null>;
|
|
50
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../../src/scraper/learningsuite/extractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACrC,WAAW,EAAE;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,EAAE,CAAC;CACL;AAOD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAuB3E;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAkI7F;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkE3E;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,IAAI,GACT,OAAO,CAAC,wBAAwB,CAAC,aAAa,CAAC,CAAC,CAuElD;AAED;;;GAGG;AACH,wBAAsB,+BAA+B,CACnD,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAqH1C;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAwDxC"}
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Browser/API Automation
|
|
3
|
+
// ============================================================================
|
|
4
|
+
/* v8 ignore start */
|
|
5
|
+
/**
|
|
6
|
+
* Detects the video type from a URL.
|
|
7
|
+
*/
|
|
8
|
+
export function detectVideoType(url) {
|
|
9
|
+
const lowerUrl = url.toLowerCase();
|
|
10
|
+
if (lowerUrl.includes("vimeo.com") || lowerUrl.includes("player.vimeo")) {
|
|
11
|
+
return "vimeo";
|
|
12
|
+
}
|
|
13
|
+
if (lowerUrl.includes("loom.com")) {
|
|
14
|
+
return "loom";
|
|
15
|
+
}
|
|
16
|
+
if (lowerUrl.includes("youtube.com") || lowerUrl.includes("youtu.be")) {
|
|
17
|
+
return "youtube";
|
|
18
|
+
}
|
|
19
|
+
if (lowerUrl.includes("wistia.com") || lowerUrl.includes("wistia.net")) {
|
|
20
|
+
return "wistia";
|
|
21
|
+
}
|
|
22
|
+
if (lowerUrl.includes(".m3u8")) {
|
|
23
|
+
return "hls";
|
|
24
|
+
}
|
|
25
|
+
if (lowerUrl.includes(".mp4") || lowerUrl.includes(".webm")) {
|
|
26
|
+
return "native";
|
|
27
|
+
}
|
|
28
|
+
return "unknown";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extracts video information from a lesson page.
|
|
32
|
+
*/
|
|
33
|
+
export async function extractVideoFromPage(page) {
|
|
34
|
+
// Check for HLS video
|
|
35
|
+
const hlsUrl = await page.evaluate(() => {
|
|
36
|
+
// Look for video elements with HLS source
|
|
37
|
+
const videos = Array.from(document.querySelectorAll("video"));
|
|
38
|
+
for (const video of videos) {
|
|
39
|
+
const src = video.currentSrc ?? video.src;
|
|
40
|
+
if (src?.includes(".m3u8")) {
|
|
41
|
+
return src;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// Check for HLS source elements
|
|
45
|
+
const sources = Array.from(document.querySelectorAll('source[type*="m3u8"], source[src*=".m3u8"]'));
|
|
46
|
+
for (const source of sources) {
|
|
47
|
+
const src = source.src;
|
|
48
|
+
if (src)
|
|
49
|
+
return src;
|
|
50
|
+
}
|
|
51
|
+
// Look for HLS URLs in script tags
|
|
52
|
+
const scripts = Array.from(document.querySelectorAll("script"));
|
|
53
|
+
for (const script of scripts) {
|
|
54
|
+
const content = script.textContent ?? "";
|
|
55
|
+
const hlsMatch = /"(https?:\/\/[^"]+\.m3u8[^"]*)"/i.exec(content);
|
|
56
|
+
if (hlsMatch?.[1])
|
|
57
|
+
return hlsMatch[1];
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
});
|
|
61
|
+
if (hlsUrl) {
|
|
62
|
+
return {
|
|
63
|
+
type: "hls",
|
|
64
|
+
url: hlsUrl,
|
|
65
|
+
hlsUrl,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Check for Vimeo embed
|
|
69
|
+
const vimeoUrl = await page.evaluate(() => {
|
|
70
|
+
const iframe = document.querySelector('iframe[src*="vimeo.com"], iframe[src*="player.vimeo"]');
|
|
71
|
+
if (iframe) {
|
|
72
|
+
return iframe.src;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
});
|
|
76
|
+
if (vimeoUrl) {
|
|
77
|
+
return {
|
|
78
|
+
type: "vimeo",
|
|
79
|
+
url: vimeoUrl,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// Check for Loom embed
|
|
83
|
+
const loomUrl = await page.evaluate(() => {
|
|
84
|
+
const iframe = document.querySelector('iframe[src*="loom.com"]');
|
|
85
|
+
if (iframe) {
|
|
86
|
+
return iframe.src;
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
});
|
|
90
|
+
if (loomUrl) {
|
|
91
|
+
return {
|
|
92
|
+
type: "loom",
|
|
93
|
+
url: loomUrl,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Check for YouTube embed
|
|
97
|
+
const youtubeUrl = await page.evaluate(() => {
|
|
98
|
+
const iframe = document.querySelector('iframe[src*="youtube.com"], iframe[src*="youtube-nocookie.com"], iframe[src*="youtu.be"]');
|
|
99
|
+
if (iframe) {
|
|
100
|
+
return iframe.src;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
});
|
|
104
|
+
if (youtubeUrl) {
|
|
105
|
+
return {
|
|
106
|
+
type: "youtube",
|
|
107
|
+
url: youtubeUrl,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// Check for Wistia
|
|
111
|
+
const wistiaInfo = await page.evaluate(() => {
|
|
112
|
+
const wistiaEmbed = document.querySelector('[class*="wistia"]');
|
|
113
|
+
if (wistiaEmbed) {
|
|
114
|
+
const match = /wistia_embed wistia_async_(\w+)/.exec(wistiaEmbed.className);
|
|
115
|
+
if (match?.[1]) {
|
|
116
|
+
return { id: match[1] };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
});
|
|
121
|
+
if (wistiaInfo?.id) {
|
|
122
|
+
return {
|
|
123
|
+
type: "wistia",
|
|
124
|
+
url: `https://fast.wistia.net/embed/medias/${wistiaInfo.id}`,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
// Check for native video
|
|
128
|
+
const nativeVideoUrl = await page.evaluate(() => {
|
|
129
|
+
const video = document.querySelector("video");
|
|
130
|
+
if (video) {
|
|
131
|
+
const source = video.querySelector("source");
|
|
132
|
+
const src = source?.src ?? video.src ?? video.currentSrc;
|
|
133
|
+
if (src && !src.includes(".m3u8")) {
|
|
134
|
+
return src;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return null;
|
|
138
|
+
});
|
|
139
|
+
if (nativeVideoUrl) {
|
|
140
|
+
return {
|
|
141
|
+
type: "native",
|
|
142
|
+
url: nativeVideoUrl,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extracts HTML content from the lesson page using semantic HTML structure.
|
|
149
|
+
* Uses accessibility-friendly selectors: main element, semantic headings, paragraphs, lists.
|
|
150
|
+
* Falls back to data-* attributes which are also stable.
|
|
151
|
+
*/
|
|
152
|
+
export async function extractHtmlContent(page) {
|
|
153
|
+
return page.evaluate(() => {
|
|
154
|
+
// Find the main content area (semantic HTML)
|
|
155
|
+
const main = document.querySelector("main");
|
|
156
|
+
if (!main)
|
|
157
|
+
return null;
|
|
158
|
+
// Find content elements using semantic selectors first, then data attributes as fallback
|
|
159
|
+
// Priority: semantic HTML (p, ul, ol in main) > data-slate-node > data-cy attributes
|
|
160
|
+
const contentElements = main.querySelectorAll(
|
|
161
|
+
// Semantic HTML within main
|
|
162
|
+
"p[data-slate-node], ul[data-slate-node], ol[data-slate-node], " +
|
|
163
|
+
// Stable data attributes as fallback
|
|
164
|
+
'[data-cy="paragraph-element"], [data-cy="list-item"]');
|
|
165
|
+
if (contentElements.length > 0) {
|
|
166
|
+
const htmlParts = [];
|
|
167
|
+
const processedTexts = new Set();
|
|
168
|
+
for (const el of Array.from(contentElements)) {
|
|
169
|
+
const tag = el.tagName.toLowerCase();
|
|
170
|
+
const text = el.textContent?.trim() ?? "";
|
|
171
|
+
// Skip empty, duplicate, or very short text
|
|
172
|
+
if (!text || processedTexts.has(text) || text.length < 3)
|
|
173
|
+
continue;
|
|
174
|
+
processedTexts.add(text);
|
|
175
|
+
if (tag === "p") {
|
|
176
|
+
htmlParts.push(`<p>${text}</p>`);
|
|
177
|
+
}
|
|
178
|
+
else if (tag === "ul" || tag === "ol") {
|
|
179
|
+
const items = el.querySelectorAll("li");
|
|
180
|
+
const listItems = Array.from(items)
|
|
181
|
+
.map((li) => li.textContent?.trim() ?? "")
|
|
182
|
+
.filter((t) => t.length > 0)
|
|
183
|
+
.map((t) => `<li>${t}</li>`)
|
|
184
|
+
.join("");
|
|
185
|
+
if (listItems) {
|
|
186
|
+
htmlParts.push(`<${tag}>${listItems}</${tag}>`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (htmlParts.length > 0) {
|
|
191
|
+
return htmlParts.join("\n");
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Fallback: extract from main, excluding navigation and interactive elements
|
|
195
|
+
const clone = main.cloneNode(true);
|
|
196
|
+
// Remove non-content elements using semantic/role selectors
|
|
197
|
+
const unwanted = clone.querySelectorAll("script, style, nav, video, iframe, svg, button, input, " +
|
|
198
|
+
'[role="navigation"], [role="button"], [role="menuitem"], [role="menu"]');
|
|
199
|
+
unwanted.forEach((el) => {
|
|
200
|
+
el.remove();
|
|
201
|
+
});
|
|
202
|
+
const text = clone.textContent?.trim();
|
|
203
|
+
if (text && text.length > 50) {
|
|
204
|
+
return `<p>${text}</p>`;
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Extracts attachments/materials from the lesson page.
|
|
211
|
+
*/
|
|
212
|
+
export async function extractAttachmentsFromPage(page) {
|
|
213
|
+
return page.evaluate(() => {
|
|
214
|
+
const attachments = [];
|
|
215
|
+
// Look for download links - include storage URLs (Google Cloud Storage)
|
|
216
|
+
const downloadLinks = document.querySelectorAll('a[download], a[href*=".pdf"], a[href*=".doc"], a[href*=".xls"], a[href*=".ppt"], a[href*=".zip"], a[href*="storage.googleapis.com"], a[href*="storage.cloud.google"]');
|
|
217
|
+
const seen = new Set();
|
|
218
|
+
for (const link of Array.from(downloadLinks)) {
|
|
219
|
+
const anchor = link;
|
|
220
|
+
const url = anchor.href;
|
|
221
|
+
if (!url || seen.has(url))
|
|
222
|
+
continue;
|
|
223
|
+
// Skip non-file URLs
|
|
224
|
+
if (url.startsWith("javascript:") || url.startsWith("#"))
|
|
225
|
+
continue;
|
|
226
|
+
seen.add(url);
|
|
227
|
+
// Get filename from download attribute, text content, or URL
|
|
228
|
+
let name = anchor.download || "";
|
|
229
|
+
if (!name) {
|
|
230
|
+
// Try to get name from visible text (often the file name is shown)
|
|
231
|
+
const textContent = anchor.textContent?.trim() ?? "";
|
|
232
|
+
if (textContent?.includes(".")) {
|
|
233
|
+
name = textContent;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!name) {
|
|
237
|
+
// Extract from URL, handling encoded characters
|
|
238
|
+
const urlParts = url.split("/");
|
|
239
|
+
const lastPart = urlParts[urlParts.length - 1]?.split("?")[0] ?? "";
|
|
240
|
+
try {
|
|
241
|
+
name = decodeURIComponent(lastPart);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
name = lastPart;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (!name) {
|
|
248
|
+
name = "attachment";
|
|
249
|
+
}
|
|
250
|
+
// Determine type from extension
|
|
251
|
+
const ext = name.split(".").pop()?.toLowerCase() ?? "";
|
|
252
|
+
let type = "file";
|
|
253
|
+
if (["pdf"].includes(ext))
|
|
254
|
+
type = "pdf";
|
|
255
|
+
else if (["doc", "docx"].includes(ext))
|
|
256
|
+
type = "document";
|
|
257
|
+
else if (["xls", "xlsx"].includes(ext))
|
|
258
|
+
type = "spreadsheet";
|
|
259
|
+
else if (["ppt", "pptx"].includes(ext))
|
|
260
|
+
type = "presentation";
|
|
261
|
+
else if (["zip", "rar", "7z"].includes(ext))
|
|
262
|
+
type = "archive";
|
|
263
|
+
else if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext))
|
|
264
|
+
type = "image";
|
|
265
|
+
attachments.push({
|
|
266
|
+
id: `attachment-${attachments.length}`,
|
|
267
|
+
name,
|
|
268
|
+
url,
|
|
269
|
+
type,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return attachments;
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Extracts complete lesson content using DOM-based extraction with network interception.
|
|
277
|
+
* Note: LearningSuite uses persisted GraphQL queries, so we can't make arbitrary API calls.
|
|
278
|
+
*/
|
|
279
|
+
export async function extractLearningSuitePostContent(page, lessonUrl, _tenantId, _courseId, lessonId) {
|
|
280
|
+
// Set up request interception to capture HLS video URLs
|
|
281
|
+
const hlsUrls = [];
|
|
282
|
+
const requestHandler = (request) => {
|
|
283
|
+
const url = request.url();
|
|
284
|
+
// Capture HLS playlists from Bunny API or direct m3u8
|
|
285
|
+
if (url.includes("/playlist/master") || url.includes(".m3u8")) {
|
|
286
|
+
hlsUrls.push(url);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
page.on("request", requestHandler);
|
|
290
|
+
// Navigate to lesson page
|
|
291
|
+
await page.goto(lessonUrl, { timeout: 30000 });
|
|
292
|
+
await page.waitForLoadState("domcontentloaded");
|
|
293
|
+
// Wait for video player to appear (if any)
|
|
294
|
+
const hasVideoPlayer = await page
|
|
295
|
+
.locator("video, [class*='video'], [class*='Video'], [class*='player'], [class*='Player']")
|
|
296
|
+
.first()
|
|
297
|
+
.waitFor({ state: "attached", timeout: 5000 })
|
|
298
|
+
.then(() => true)
|
|
299
|
+
.catch(() => false);
|
|
300
|
+
// If video player exists but no HLS URL captured yet, try to trigger video load
|
|
301
|
+
if (hasVideoPlayer && hlsUrls.length === 0) {
|
|
302
|
+
// Try clicking play button or video element to trigger load
|
|
303
|
+
const playButton = page.locator('[aria-label*="play" i], [aria-label*="Play" i], [class*="play" i], button[class*="Play"], video');
|
|
304
|
+
try {
|
|
305
|
+
await playButton.first().click({ timeout: 2000 });
|
|
306
|
+
// Wait for HLS URL to be captured after clicking play
|
|
307
|
+
await page.waitForTimeout(2000);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// Play button not found or not clickable, continue anyway
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Give a bit more time for lazy-loaded videos
|
|
314
|
+
if (hlsUrls.length === 0 && hasVideoPlayer) {
|
|
315
|
+
await page.waitForTimeout(2000);
|
|
316
|
+
}
|
|
317
|
+
// Remove handler
|
|
318
|
+
page.off("request", requestHandler);
|
|
319
|
+
// Try to get video from intercepted requests first
|
|
320
|
+
let video = null;
|
|
321
|
+
const masterPlaylist = hlsUrls.find((url) => url.includes("/playlist/master"));
|
|
322
|
+
if (masterPlaylist) {
|
|
323
|
+
video = {
|
|
324
|
+
type: "hls",
|
|
325
|
+
url: masterPlaylist,
|
|
326
|
+
hlsUrl: masterPlaylist,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
else if (hlsUrls.length > 0 && hlsUrls[0]) {
|
|
330
|
+
video = {
|
|
331
|
+
type: "hls",
|
|
332
|
+
url: hlsUrls[0],
|
|
333
|
+
hlsUrl: hlsUrls[0],
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
// Fallback to DOM extraction if no HLS found
|
|
337
|
+
video ??= await extractVideoFromPage(page);
|
|
338
|
+
const htmlContent = await extractHtmlContent(page);
|
|
339
|
+
const attachments = await extractAttachmentsFromPage(page);
|
|
340
|
+
// Get title from page using semantic HTML structure
|
|
341
|
+
// The lesson title is typically an h3 within the main element
|
|
342
|
+
const title = await page.evaluate(() => {
|
|
343
|
+
const main = document.querySelector("main");
|
|
344
|
+
// Find h3 heading within main (lesson title is usually h3)
|
|
345
|
+
if (main) {
|
|
346
|
+
const h3 = main.querySelector("h3");
|
|
347
|
+
if (h3?.textContent?.trim()) {
|
|
348
|
+
return h3.textContent.trim();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Try breadcrumb navigation (last item is the current page)
|
|
352
|
+
const breadcrumb = document.querySelector('nav[aria-label*="breadcrumb"], [role="navigation"] li:last-child');
|
|
353
|
+
if (breadcrumb?.textContent?.trim()) {
|
|
354
|
+
return breadcrumb.textContent.trim();
|
|
355
|
+
}
|
|
356
|
+
// Try any h3 on the page
|
|
357
|
+
const h3 = document.querySelector("h3");
|
|
358
|
+
if (h3?.textContent?.trim()) {
|
|
359
|
+
return h3.textContent.trim();
|
|
360
|
+
}
|
|
361
|
+
// Try h1 as fallback
|
|
362
|
+
const h1 = document.querySelector("h1");
|
|
363
|
+
if (h1?.textContent?.trim()) {
|
|
364
|
+
return h1.textContent.trim();
|
|
365
|
+
}
|
|
366
|
+
// Use page title as last resort
|
|
367
|
+
return document.title.split(" - ")[0] ?? "Untitled";
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
id: lessonId,
|
|
371
|
+
title,
|
|
372
|
+
description: null,
|
|
373
|
+
htmlContent,
|
|
374
|
+
video,
|
|
375
|
+
attachments,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Intercepts network requests to capture video URLs during page load.
|
|
380
|
+
*/
|
|
381
|
+
export async function interceptVideoRequests(page, lessonUrl) {
|
|
382
|
+
const hlsUrls = [];
|
|
383
|
+
const videoUrls = [];
|
|
384
|
+
// Set up request interception
|
|
385
|
+
const requestHandler = (request) => {
|
|
386
|
+
const url = request.url();
|
|
387
|
+
// Capture HLS playlists
|
|
388
|
+
if (url.includes(".m3u8") || url.includes("master.m3u8")) {
|
|
389
|
+
hlsUrls.push(url);
|
|
390
|
+
}
|
|
391
|
+
// Capture video files
|
|
392
|
+
if (url.includes(".mp4") || url.includes(".webm")) {
|
|
393
|
+
videoUrls.push(url);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
page.on("request", requestHandler);
|
|
397
|
+
// Navigate to the lesson
|
|
398
|
+
await page.goto(lessonUrl, { timeout: 30000 });
|
|
399
|
+
await page.waitForLoadState("domcontentloaded");
|
|
400
|
+
await page.waitForTimeout(3000);
|
|
401
|
+
// Remove handler
|
|
402
|
+
page.off("request", requestHandler);
|
|
403
|
+
// Return the best URL found
|
|
404
|
+
const masterPlaylist = hlsUrls.find((url) => url.includes("master.m3u8"));
|
|
405
|
+
if (masterPlaylist) {
|
|
406
|
+
return {
|
|
407
|
+
type: "hls",
|
|
408
|
+
url: masterPlaylist,
|
|
409
|
+
hlsUrl: masterPlaylist,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
if (hlsUrls.length > 0 && hlsUrls[0]) {
|
|
413
|
+
return {
|
|
414
|
+
type: "hls",
|
|
415
|
+
url: hlsUrls[0],
|
|
416
|
+
hlsUrl: hlsUrls[0],
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
if (videoUrls.length > 0 && videoUrls[0]) {
|
|
420
|
+
return {
|
|
421
|
+
type: "native",
|
|
422
|
+
url: videoUrls[0],
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
// Fallback to DOM extraction
|
|
426
|
+
return extractVideoFromPage(page);
|
|
427
|
+
}
|
|
428
|
+
/* v8 ignore stop */
|
|
429
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../../src/scraper/learningsuite/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scraper/learningsuite/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC"}
|