offcourse 0.0.1 → 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.
- package/.github/workflows/ci.yml +50 -0
- package/.husky/commit-msg +2 -0
- package/.husky/pre-commit +1 -0
- package/.husky/pre-push +3 -0
- package/.prettierrc +8 -0
- package/.release-it.json +23 -0
- package/ARCHITECTURE.md +233 -0
- package/CHANGELOG.md +78 -0
- package/README.md +256 -16
- package/commitlint.config.js +4 -0
- package/dist/ai/openRouter.d.ts +47 -0
- package/dist/ai/openRouter.d.ts.map +1 -0
- package/dist/ai/openRouter.js +116 -0
- package/dist/ai/openRouter.js.map +1 -0
- package/dist/ai/transcriptPolisher.d.ts +24 -0
- package/dist/ai/transcriptPolisher.d.ts.map +1 -0
- package/dist/ai/transcriptPolisher.js +89 -0
- package/dist/ai/transcriptPolisher.js.map +1 -0
- package/dist/cli/commands/config.d.ts +13 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +66 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/enrich.d.ts +14 -0
- package/dist/cli/commands/enrich.d.ts.map +1 -0
- package/dist/cli/commands/enrich.js +271 -0
- package/dist/cli/commands/enrich.js.map +1 -0
- package/dist/cli/commands/inspect.d.ts +11 -0
- package/dist/cli/commands/inspect.d.ts.map +1 -0
- package/dist/cli/commands/inspect.js +365 -0
- package/dist/cli/commands/inspect.js.map +1 -0
- package/dist/cli/commands/login.d.ts +12 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +55 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/commands/status.d.ts +15 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +118 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +16 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +922 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/commands/syncGhl.d.ts +20 -0
- package/dist/cli/commands/syncGhl.d.ts.map +1 -0
- package/dist/cli/commands/syncGhl.js +483 -0
- package/dist/cli/commands/syncGhl.js.map +1 -0
- package/dist/cli/commands/syncHighLevel.d.ts +24 -0
- package/dist/cli/commands/syncHighLevel.d.ts.map +1 -0
- package/dist/cli/commands/syncHighLevel.js +483 -0
- package/dist/cli/commands/syncHighLevel.js.map +1 -0
- package/dist/cli/commands/syncHighLevel.test.d.ts +2 -0
- package/dist/cli/commands/syncHighLevel.test.d.ts.map +1 -0
- package/dist/cli/commands/syncHighLevel.test.js +102 -0
- package/dist/cli/commands/syncHighLevel.test.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +106 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/config/configManager.d.ts +31 -0
- package/dist/config/configManager.d.ts.map +1 -0
- package/dist/config/configManager.js +64 -0
- package/dist/config/configManager.js.map +1 -0
- package/dist/config/paths.d.ts +21 -0
- package/dist/config/paths.d.ts.map +1 -0
- package/dist/config/paths.js +33 -0
- package/dist/config/paths.js.map +1 -0
- package/dist/config/paths.test.d.ts +2 -0
- package/dist/config/paths.test.d.ts.map +1 -0
- package/dist/config/paths.test.js +70 -0
- package/dist/config/paths.test.js.map +1 -0
- package/dist/config/schema.d.ts +60 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +50 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/schema.test.d.ts +2 -0
- package/dist/config/schema.test.d.ts.map +1 -0
- package/dist/config/schema.test.js +151 -0
- package/dist/config/schema.test.js.map +1 -0
- package/dist/downloader/hlsDownloader.d.ts +58 -0
- package/dist/downloader/hlsDownloader.d.ts.map +1 -0
- package/dist/downloader/hlsDownloader.js +254 -0
- package/dist/downloader/hlsDownloader.js.map +1 -0
- package/dist/downloader/hlsDownloader.test.d.ts +2 -0
- package/dist/downloader/hlsDownloader.test.d.ts.map +1 -0
- package/dist/downloader/hlsDownloader.test.js +116 -0
- package/dist/downloader/hlsDownloader.test.js.map +1 -0
- package/dist/downloader/hlsValidator.d.ts +35 -0
- package/dist/downloader/hlsValidator.d.ts.map +1 -0
- package/dist/downloader/hlsValidator.js +148 -0
- package/dist/downloader/hlsValidator.js.map +1 -0
- package/dist/downloader/index.d.ts +26 -0
- package/dist/downloader/index.d.ts.map +1 -0
- package/dist/downloader/index.js +52 -0
- package/dist/downloader/index.js.map +1 -0
- package/dist/downloader/loomDownloader.d.ts +56 -0
- package/dist/downloader/loomDownloader.d.ts.map +1 -0
- package/dist/downloader/loomDownloader.js +559 -0
- package/dist/downloader/loomDownloader.js.map +1 -0
- package/dist/downloader/loomDownloader.test.d.ts +2 -0
- package/dist/downloader/loomDownloader.test.d.ts.map +1 -0
- package/dist/downloader/loomDownloader.test.js +36 -0
- package/dist/downloader/loomDownloader.test.js.map +1 -0
- package/dist/downloader/queue.d.ts +56 -0
- package/dist/downloader/queue.d.ts.map +1 -0
- package/dist/downloader/queue.js +88 -0
- package/dist/downloader/queue.js.map +1 -0
- package/dist/downloader/queue.test.d.ts +2 -0
- package/dist/downloader/queue.test.d.ts.map +1 -0
- package/dist/downloader/queue.test.js +158 -0
- package/dist/downloader/queue.test.js.map +1 -0
- package/dist/downloader/videoDownloader.d.ts +32 -0
- package/dist/downloader/videoDownloader.d.ts.map +1 -0
- package/dist/downloader/videoDownloader.js +173 -0
- package/dist/downloader/videoDownloader.js.map +1 -0
- package/dist/downloader/vimeoDownloader.d.ts +52 -0
- package/dist/downloader/vimeoDownloader.d.ts.map +1 -0
- package/dist/downloader/vimeoDownloader.js +565 -0
- package/dist/downloader/vimeoDownloader.js.map +1 -0
- package/dist/downloader/vimeoDownloader.test.d.ts +2 -0
- package/dist/downloader/vimeoDownloader.test.d.ts.map +1 -0
- package/dist/downloader/vimeoDownloader.test.js +51 -0
- package/dist/downloader/vimeoDownloader.test.js.map +1 -0
- package/dist/scraper/auth.d.ts +29 -0
- package/dist/scraper/auth.d.ts.map +1 -0
- package/dist/scraper/auth.js +115 -0
- package/dist/scraper/auth.js.map +1 -0
- package/dist/scraper/extractor.d.ts +49 -0
- package/dist/scraper/extractor.d.ts.map +1 -0
- package/dist/scraper/extractor.js +627 -0
- package/dist/scraper/extractor.js.map +1 -0
- package/dist/scraper/extractor.test.d.ts +2 -0
- package/dist/scraper/extractor.test.d.ts.map +1 -0
- package/dist/scraper/extractor.test.js +65 -0
- package/dist/scraper/extractor.test.js.map +1 -0
- package/dist/scraper/ghl/auth.d.ts +25 -0
- package/dist/scraper/ghl/auth.d.ts.map +1 -0
- package/dist/scraper/ghl/auth.js +187 -0
- package/dist/scraper/ghl/auth.js.map +1 -0
- package/dist/scraper/ghl/extractor.d.ts +96 -0
- package/dist/scraper/ghl/extractor.d.ts.map +1 -0
- package/dist/scraper/ghl/extractor.js +345 -0
- package/dist/scraper/ghl/extractor.js.map +1 -0
- package/dist/scraper/ghl/index.d.ts +4 -0
- package/dist/scraper/ghl/index.d.ts.map +1 -0
- package/dist/scraper/ghl/index.js +4 -0
- package/dist/scraper/ghl/index.js.map +1 -0
- package/dist/scraper/ghl/navigator.d.ts +93 -0
- package/dist/scraper/ghl/navigator.d.ts.map +1 -0
- package/dist/scraper/ghl/navigator.js +447 -0
- package/dist/scraper/ghl/navigator.js.map +1 -0
- package/dist/scraper/highlevel/auth.d.ts +25 -0
- package/dist/scraper/highlevel/auth.d.ts.map +1 -0
- package/dist/scraper/highlevel/auth.js +189 -0
- package/dist/scraper/highlevel/auth.js.map +1 -0
- package/dist/scraper/highlevel/extractor.d.ts +97 -0
- package/dist/scraper/highlevel/extractor.d.ts.map +1 -0
- package/dist/scraper/highlevel/extractor.js +386 -0
- package/dist/scraper/highlevel/extractor.js.map +1 -0
- package/dist/scraper/highlevel/extractor.test.d.ts +2 -0
- package/dist/scraper/highlevel/extractor.test.d.ts.map +1 -0
- package/dist/scraper/highlevel/extractor.test.js +101 -0
- package/dist/scraper/highlevel/extractor.test.js.map +1 -0
- package/dist/scraper/highlevel/index.d.ts +3 -0
- package/dist/scraper/highlevel/index.d.ts.map +1 -0
- package/dist/scraper/highlevel/index.js +3 -0
- package/dist/scraper/highlevel/index.js.map +1 -0
- package/dist/scraper/highlevel/navigator.d.ts +93 -0
- package/dist/scraper/highlevel/navigator.d.ts.map +1 -0
- package/dist/scraper/highlevel/navigator.js +492 -0
- package/dist/scraper/highlevel/navigator.js.map +1 -0
- package/dist/scraper/highlevel/navigator.test.d.ts +2 -0
- package/dist/scraper/highlevel/navigator.test.d.ts.map +1 -0
- package/dist/scraper/highlevel/navigator.test.js +78 -0
- package/dist/scraper/highlevel/navigator.test.js.map +1 -0
- package/dist/scraper/navigator.d.ts +65 -0
- package/dist/scraper/navigator.d.ts.map +1 -0
- package/dist/scraper/navigator.js +300 -0
- package/dist/scraper/navigator.js.map +1 -0
- package/dist/scraper/navigator.test.d.ts +2 -0
- package/dist/scraper/navigator.test.d.ts.map +1 -0
- package/dist/scraper/navigator.test.js +63 -0
- package/dist/scraper/navigator.test.js.map +1 -0
- package/dist/scraper/skoolApi.d.ts +17 -0
- package/dist/scraper/skoolApi.d.ts.map +1 -0
- package/dist/scraper/skoolApi.js +72 -0
- package/dist/scraper/skoolApi.js.map +1 -0
- package/dist/scraper/videoInterceptor.d.ts +19 -0
- package/dist/scraper/videoInterceptor.d.ts.map +1 -0
- package/dist/scraper/videoInterceptor.js +315 -0
- package/dist/scraper/videoInterceptor.js.map +1 -0
- package/dist/shared/auth.d.ts +58 -0
- package/dist/shared/auth.d.ts.map +1 -0
- package/dist/shared/auth.js +211 -0
- package/dist/shared/auth.js.map +1 -0
- package/dist/shared/fs.d.ts +31 -0
- package/dist/shared/fs.d.ts.map +1 -0
- package/dist/shared/fs.js +73 -0
- package/dist/shared/fs.js.map +1 -0
- package/dist/shared/http.d.ts +15 -0
- package/dist/shared/http.d.ts.map +1 -0
- package/dist/shared/http.js +31 -0
- package/dist/shared/http.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/state/database.d.ts +245 -0
- package/dist/state/database.d.ts.map +1 -0
- package/dist/state/database.js +676 -0
- package/dist/state/database.js.map +1 -0
- package/dist/state/database.test.d.ts +2 -0
- package/dist/state/database.test.d.ts.map +1 -0
- package/dist/state/database.test.js +34 -0
- package/dist/state/database.test.js.map +1 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +2 -0
- package/dist/state/index.js.map +1 -0
- package/dist/storage/fileSystem.d.ts +56 -0
- package/dist/storage/fileSystem.d.ts.map +1 -0
- package/dist/storage/fileSystem.js +121 -0
- package/dist/storage/fileSystem.js.map +1 -0
- package/dist/transcription/whisperService.d.ts +27 -0
- package/dist/transcription/whisperService.d.ts.map +1 -0
- package/dist/transcription/whisperService.js +102 -0
- package/dist/transcription/whisperService.js.map +1 -0
- package/eslint.config.js +55 -0
- package/package.json +68 -11
- package/src/__fixtures__/highlevel-post-response.json +68 -0
- package/src/__fixtures__/hls-master-playlist.m3u8 +24 -0
- package/src/cli/commands/__snapshots__/syncHighLevel.test.ts.snap +38 -0
- package/src/cli/commands/config.ts +74 -0
- package/src/cli/commands/inspect.ts +441 -0
- package/src/cli/commands/login.ts +68 -0
- package/src/cli/commands/status.ts +147 -0
- package/src/cli/commands/sync.ts +1235 -0
- package/src/cli/commands/syncHighLevel.test.ts +144 -0
- package/src/cli/commands/syncHighLevel.ts +639 -0
- package/src/cli/index.ts +121 -0
- package/src/config/configManager.ts +75 -0
- package/src/config/paths.test.ts +83 -0
- package/src/config/paths.ts +36 -0
- package/src/config/schema.test.ts +173 -0
- package/src/config/schema.ts +65 -0
- package/src/downloader/hlsDownloader.test.ts +148 -0
- package/src/downloader/hlsDownloader.ts +327 -0
- package/src/downloader/hlsValidator.ts +196 -0
- package/src/downloader/index.ts +122 -0
- package/src/downloader/loomDownloader.test.ts +43 -0
- package/src/downloader/loomDownloader.ts +742 -0
- package/src/downloader/queue.test.ts +199 -0
- package/src/downloader/queue.ts +118 -0
- package/src/downloader/vimeoDownloader.test.ts +62 -0
- package/src/downloader/vimeoDownloader.ts +722 -0
- package/src/scraper/extractor.test.ts +124 -0
- package/src/scraper/extractor.ts +757 -0
- package/src/scraper/highlevel/__snapshots__/extractor.test.ts.snap +41 -0
- package/src/scraper/highlevel/extractor.test.ts +134 -0
- package/src/scraper/highlevel/extractor.ts +537 -0
- package/src/scraper/highlevel/index.ts +2 -0
- package/src/scraper/highlevel/navigator.test.ts +110 -0
- package/src/scraper/highlevel/navigator.ts +668 -0
- package/src/scraper/highlevel/schemas.ts +183 -0
- package/src/scraper/navigator.test.ts +122 -0
- package/src/scraper/navigator.ts +355 -0
- package/src/scraper/schemas.ts +177 -0
- package/src/scraper/videoInterceptor.ts +435 -0
- package/src/shared/auth.test.ts +58 -0
- package/src/shared/auth.ts +251 -0
- package/src/shared/firebase.ts +151 -0
- package/src/shared/fs.ts +80 -0
- package/src/shared/http.ts +34 -0
- package/src/shared/index.ts +6 -0
- package/src/shared/slug.ts +26 -0
- package/src/shared/url.test.ts +122 -0
- package/src/shared/url.ts +57 -0
- package/src/state/database.test.ts +49 -0
- package/src/state/database.ts +919 -0
- package/src/state/index.ts +14 -0
- package/src/storage/fileSystem.test.ts +64 -0
- package/src/storage/fileSystem.ts +175 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +29 -0
- package/cli.js +0 -45
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the Firebase auth token from the page.
|
|
3
|
+
*/
|
|
4
|
+
export async function getAuthToken(page) {
|
|
5
|
+
return page.evaluate(() => {
|
|
6
|
+
const tokenKey = Object.keys(localStorage).find((k) => k.includes("firebase:authUser"));
|
|
7
|
+
if (!tokenKey)
|
|
8
|
+
return null;
|
|
9
|
+
const tokenData = JSON.parse(localStorage.getItem(tokenKey) ?? "{}");
|
|
10
|
+
return tokenData?.stsTokenManager?.accessToken ?? null;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extracts video info from a GHL post page by intercepting network requests.
|
|
15
|
+
*/
|
|
16
|
+
export async function extractVideoFromPage(page) {
|
|
17
|
+
// First, check if there's an HLS video on the page
|
|
18
|
+
const hlsUrl = await page.evaluate(() => {
|
|
19
|
+
// Look for HLS master playlist URLs in the DOM
|
|
20
|
+
const videoElements = Array.from(document.querySelectorAll("video"));
|
|
21
|
+
for (const video of videoElements) {
|
|
22
|
+
const src = video.currentSrc || video.src;
|
|
23
|
+
if (src && src.includes(".m3u8")) {
|
|
24
|
+
return src;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Check for plyr or other players
|
|
28
|
+
const sources = Array.from(document.querySelectorAll('source[type*="m3u8"], source[src*=".m3u8"]'));
|
|
29
|
+
for (const source of sources) {
|
|
30
|
+
const src = source.src;
|
|
31
|
+
if (src)
|
|
32
|
+
return src;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
});
|
|
36
|
+
if (hlsUrl) {
|
|
37
|
+
return {
|
|
38
|
+
type: "hls",
|
|
39
|
+
url: hlsUrl,
|
|
40
|
+
masterPlaylistUrl: hlsUrl,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Check for Vimeo embed
|
|
44
|
+
const vimeoUrl = await page.evaluate(() => {
|
|
45
|
+
const iframe = document.querySelector('iframe[src*="vimeo.com"], iframe[src*="player.vimeo"]');
|
|
46
|
+
if (iframe) {
|
|
47
|
+
return iframe.src;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
});
|
|
51
|
+
if (vimeoUrl) {
|
|
52
|
+
return {
|
|
53
|
+
type: "vimeo",
|
|
54
|
+
url: vimeoUrl,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// Check for Loom embed
|
|
58
|
+
const loomUrl = await page.evaluate(() => {
|
|
59
|
+
const iframe = document.querySelector('iframe[src*="loom.com"]');
|
|
60
|
+
if (iframe) {
|
|
61
|
+
return iframe.src;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
});
|
|
65
|
+
if (loomUrl) {
|
|
66
|
+
return {
|
|
67
|
+
type: "loom",
|
|
68
|
+
url: loomUrl,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
// Check for YouTube embed
|
|
72
|
+
const youtubeUrl = await page.evaluate(() => {
|
|
73
|
+
const iframe = document.querySelector('iframe[src*="youtube.com"], iframe[src*="youtube-nocookie.com"], iframe[src*="youtu.be"]');
|
|
74
|
+
if (iframe) {
|
|
75
|
+
return iframe.src;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
});
|
|
79
|
+
if (youtubeUrl) {
|
|
80
|
+
return {
|
|
81
|
+
type: "youtube",
|
|
82
|
+
url: youtubeUrl,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Extracts video info by intercepting network requests during page load.
|
|
89
|
+
*/
|
|
90
|
+
export async function interceptVideoRequests(page, postUrl) {
|
|
91
|
+
const hlsUrls = [];
|
|
92
|
+
const drmUrls = [];
|
|
93
|
+
// Set up request interception
|
|
94
|
+
const requestHandler = (request) => {
|
|
95
|
+
const url = request.url();
|
|
96
|
+
// Capture HLS master playlist requests
|
|
97
|
+
if (url.includes(".m3u8") || url.includes("master.m3u8")) {
|
|
98
|
+
hlsUrls.push(url);
|
|
99
|
+
}
|
|
100
|
+
// Capture DRM license requests
|
|
101
|
+
if (url.includes("assets-drm/assets-license")) {
|
|
102
|
+
drmUrls.push(url);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
page.on("request", requestHandler);
|
|
106
|
+
// Navigate to the post page
|
|
107
|
+
await page.goto(postUrl, { timeout: 30000 });
|
|
108
|
+
await page.waitForLoadState("domcontentloaded");
|
|
109
|
+
await page.waitForTimeout(3000);
|
|
110
|
+
// Remove the handler
|
|
111
|
+
page.off("request", requestHandler);
|
|
112
|
+
// Get the HLS master playlist URL
|
|
113
|
+
const masterPlaylistUrl = hlsUrls.find((url) => url.includes("master.m3u8"));
|
|
114
|
+
if (masterPlaylistUrl) {
|
|
115
|
+
return {
|
|
116
|
+
type: "hls",
|
|
117
|
+
url: masterPlaylistUrl,
|
|
118
|
+
masterPlaylistUrl,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// Fallback to DOM extraction
|
|
122
|
+
return extractVideoFromPage(page);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetches post details from the API.
|
|
126
|
+
*/
|
|
127
|
+
export async function fetchPostDetails(page, locationId, postId) {
|
|
128
|
+
return page.evaluate(async ({ locationId, postId }) => {
|
|
129
|
+
try {
|
|
130
|
+
const tokenKey = Object.keys(localStorage).find((k) => k.includes("firebase:authUser"));
|
|
131
|
+
const tokenData = tokenKey ? JSON.parse(localStorage.getItem(tokenKey) ?? "{}") : null;
|
|
132
|
+
const token = tokenData?.stsTokenManager?.accessToken;
|
|
133
|
+
if (!token) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const res = await fetch(`https://services.leadconnectorhq.com/membership/locations/${locationId}/posts/${postId}?source=courses`, {
|
|
137
|
+
headers: {
|
|
138
|
+
Authorization: `Bearer ${token}`,
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
if (!res.ok) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const data = await res.json();
|
|
145
|
+
let video = null;
|
|
146
|
+
if (data.post?.posterImage?.assetId) {
|
|
147
|
+
video = {
|
|
148
|
+
assetId: data.post.posterImage.assetId,
|
|
149
|
+
url: data.post.posterImage.url ?? "",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// Check for video in contentBlock
|
|
153
|
+
if (data.post?.contentBlock) {
|
|
154
|
+
for (const block of data.post.contentBlock) {
|
|
155
|
+
if (block.type === "video" && block.assetId) {
|
|
156
|
+
video = {
|
|
157
|
+
assetId: block.assetId,
|
|
158
|
+
url: block.url ?? "",
|
|
159
|
+
};
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const materials = [];
|
|
165
|
+
if (data.post?.materials && Array.isArray(data.post.materials)) {
|
|
166
|
+
for (const material of data.post.materials) {
|
|
167
|
+
materials.push({
|
|
168
|
+
id: material.id ?? crypto.randomUUID(),
|
|
169
|
+
name: material.name ?? "Attachment",
|
|
170
|
+
url: material.url ?? "",
|
|
171
|
+
type: material.type ?? "file",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
title: data.post?.title ?? "",
|
|
177
|
+
description: data.post?.description ?? null,
|
|
178
|
+
video,
|
|
179
|
+
materials,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
console.error("Failed to fetch post details:", error);
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}, { locationId, postId });
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Fetches the DRM license (HLS token) for a video asset.
|
|
190
|
+
*/
|
|
191
|
+
export async function fetchVideoLicense(page, assetId) {
|
|
192
|
+
return page.evaluate(async (assetId) => {
|
|
193
|
+
try {
|
|
194
|
+
const tokenKey = Object.keys(localStorage).find((k) => k.includes("firebase:authUser"));
|
|
195
|
+
const tokenData = tokenKey ? JSON.parse(localStorage.getItem(tokenKey) ?? "{}") : null;
|
|
196
|
+
const token = tokenData?.stsTokenManager?.accessToken;
|
|
197
|
+
if (!token) {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const res = await fetch(`https://backend.leadconnectorhq.com/assets-drm/assets-license/${assetId}`, {
|
|
201
|
+
headers: {
|
|
202
|
+
Authorization: `Bearer ${token}`,
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
if (!res.ok) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
const data = await res.json();
|
|
209
|
+
return {
|
|
210
|
+
url: data.url ?? "",
|
|
211
|
+
token: data.token ?? "",
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
console.error("Failed to fetch video license:", error);
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}, assetId);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Extracts complete post content including video and attachments.
|
|
222
|
+
*/
|
|
223
|
+
export async function extractGHLPostContent(page, postUrl, locationId, productId, postId, categoryId) {
|
|
224
|
+
// Navigate to post page
|
|
225
|
+
await page.goto(postUrl, { timeout: 30000 });
|
|
226
|
+
await page.waitForLoadState("domcontentloaded");
|
|
227
|
+
await page.waitForTimeout(3000);
|
|
228
|
+
// Fetch post details from API
|
|
229
|
+
const postDetails = await fetchPostDetails(page, locationId, postId);
|
|
230
|
+
if (!postDetails) {
|
|
231
|
+
console.error("Could not fetch post details");
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
let video = null;
|
|
235
|
+
// If post has a video asset, get the license URL
|
|
236
|
+
if (postDetails.video?.assetId) {
|
|
237
|
+
const license = await fetchVideoLicense(page, postDetails.video.assetId);
|
|
238
|
+
if (license?.url) {
|
|
239
|
+
video = {
|
|
240
|
+
type: "hls",
|
|
241
|
+
url: license.url,
|
|
242
|
+
masterPlaylistUrl: license.url,
|
|
243
|
+
token: license.token,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Fallback: try to extract video from page
|
|
248
|
+
if (!video) {
|
|
249
|
+
video = await extractVideoFromPage(page);
|
|
250
|
+
}
|
|
251
|
+
// Extract HTML content
|
|
252
|
+
const htmlContent = await page.evaluate(() => {
|
|
253
|
+
const contentEl = document.querySelector("[class*='post-content'], [class*='PostContent'], [class*='lesson-content'], article");
|
|
254
|
+
return contentEl?.innerHTML ?? null;
|
|
255
|
+
});
|
|
256
|
+
// Extract text description
|
|
257
|
+
const description = await page.evaluate(() => {
|
|
258
|
+
const descEl = document.querySelector("[class*='description'], [class*='Description'], p:first-of-type");
|
|
259
|
+
return descEl?.textContent?.trim() ?? null;
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
id: postId,
|
|
263
|
+
title: postDetails.title,
|
|
264
|
+
description: description ?? postDetails.description,
|
|
265
|
+
htmlContent,
|
|
266
|
+
video,
|
|
267
|
+
attachments: postDetails.materials.map((m) => ({
|
|
268
|
+
id: m.id,
|
|
269
|
+
name: m.name,
|
|
270
|
+
url: m.url,
|
|
271
|
+
type: m.type,
|
|
272
|
+
})),
|
|
273
|
+
categoryId,
|
|
274
|
+
productId,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Parses an HLS master playlist to extract quality variants.
|
|
279
|
+
*/
|
|
280
|
+
export function parseHLSMasterPlaylist(content, baseUrl) {
|
|
281
|
+
const variants = [];
|
|
282
|
+
const lines = content.split("\n");
|
|
283
|
+
for (let i = 0; i < lines.length; i++) {
|
|
284
|
+
const line = lines[i].trim();
|
|
285
|
+
if (line.startsWith("#EXT-X-STREAM-INF:")) {
|
|
286
|
+
// Parse attributes
|
|
287
|
+
const bandwidthMatch = /BANDWIDTH=(\d+)/.exec(line);
|
|
288
|
+
const resolutionMatch = /RESOLUTION=(\d+)x(\d+)/.exec(line);
|
|
289
|
+
const bandwidth = bandwidthMatch ? parseInt(bandwidthMatch[1], 10) : 0;
|
|
290
|
+
// Next line should be the URL
|
|
291
|
+
const nextLine = lines[i + 1]?.trim() ?? "";
|
|
292
|
+
if (nextLine && !nextLine.startsWith("#")) {
|
|
293
|
+
const variantUrl = nextLine.startsWith("http")
|
|
294
|
+
? nextLine
|
|
295
|
+
: new URL(nextLine, baseUrl).href;
|
|
296
|
+
const height = resolutionMatch ? parseInt(resolutionMatch[2], 10) : undefined;
|
|
297
|
+
const label = height ? `${height}p` : `${Math.round(bandwidth / 1000)}k`;
|
|
298
|
+
const variant = {
|
|
299
|
+
label,
|
|
300
|
+
url: variantUrl,
|
|
301
|
+
bandwidth,
|
|
302
|
+
};
|
|
303
|
+
if (resolutionMatch) {
|
|
304
|
+
variant.width = parseInt(resolutionMatch[1], 10);
|
|
305
|
+
variant.height = parseInt(resolutionMatch[2], 10);
|
|
306
|
+
}
|
|
307
|
+
variants.push(variant);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Sort by bandwidth (highest first)
|
|
312
|
+
variants.sort((a, b) => b.bandwidth - a.bandwidth);
|
|
313
|
+
return variants;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Fetches and parses HLS playlist to get quality options.
|
|
317
|
+
*/
|
|
318
|
+
export async function getHLSQualities(page, masterPlaylistUrl) {
|
|
319
|
+
try {
|
|
320
|
+
const content = await page.evaluate(async (url) => {
|
|
321
|
+
const res = await fetch(url);
|
|
322
|
+
if (!res.ok)
|
|
323
|
+
return null;
|
|
324
|
+
return res.text();
|
|
325
|
+
}, masterPlaylistUrl);
|
|
326
|
+
if (!content)
|
|
327
|
+
return [];
|
|
328
|
+
return parseHLSMasterPlaylist(content, masterPlaylistUrl);
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Gets the best quality URL from an HLS master playlist.
|
|
336
|
+
*/
|
|
337
|
+
export async function getBestHLSQuality(page, masterPlaylistUrl) {
|
|
338
|
+
const qualities = await getHLSQualities(page, masterPlaylistUrl);
|
|
339
|
+
if (qualities.length === 0) {
|
|
340
|
+
return masterPlaylistUrl;
|
|
341
|
+
}
|
|
342
|
+
// Return highest quality
|
|
343
|
+
return qualities[0]?.url ?? null;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../../src/scraper/ghl/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scraper/ghl/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scraper/ghl/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
export interface GHLCourse {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
slug: string;
|
|
7
|
+
thumbnailUrl: string | null;
|
|
8
|
+
instructor: string | null;
|
|
9
|
+
totalLessons: number;
|
|
10
|
+
progress: number;
|
|
11
|
+
}
|
|
12
|
+
export interface GHLCategory {
|
|
13
|
+
id: string;
|
|
14
|
+
title: string;
|
|
15
|
+
description: string | null;
|
|
16
|
+
position: number;
|
|
17
|
+
postCount: number;
|
|
18
|
+
isLocked: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface GHLPost {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
position: number;
|
|
24
|
+
categoryId: string;
|
|
25
|
+
isLocked: boolean;
|
|
26
|
+
isCompleted: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface GHLCourseStructure {
|
|
29
|
+
course: GHLCourse;
|
|
30
|
+
categories: Array<GHLCategory & {
|
|
31
|
+
posts: GHLPost[];
|
|
32
|
+
}>;
|
|
33
|
+
locationId: string;
|
|
34
|
+
domain: string;
|
|
35
|
+
}
|
|
36
|
+
export interface GHLScanProgress {
|
|
37
|
+
phase: "init" | "course" | "categories" | "posts" | "done";
|
|
38
|
+
courseName?: string;
|
|
39
|
+
totalCategories?: number;
|
|
40
|
+
currentCategory?: string;
|
|
41
|
+
currentCategoryIndex?: number;
|
|
42
|
+
postsFound?: number;
|
|
43
|
+
skippedLocked?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Extracts the location ID from the GHL portal.
|
|
47
|
+
* The location ID is used in all API calls.
|
|
48
|
+
*/
|
|
49
|
+
export declare function extractLocationId(page: Page): Promise<string | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Extracts portal settings including location ID from the API.
|
|
52
|
+
*/
|
|
53
|
+
export declare function extractPortalSettings(page: Page, domain: string): Promise<{
|
|
54
|
+
locationId: string;
|
|
55
|
+
portalName: string;
|
|
56
|
+
} | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Extracts course list from the courses library page.
|
|
59
|
+
*/
|
|
60
|
+
export declare function extractCourses(page: Page): Promise<GHLCourse[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Extracts course details from the course overview page via API.
|
|
63
|
+
*/
|
|
64
|
+
export declare function extractCourseDetails(page: Page, courseUrl: string, _locationId?: string): Promise<GHLCourse | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Extracts categories (modules) from a course page.
|
|
67
|
+
*/
|
|
68
|
+
export declare function extractCategories(page: Page, productId: string, locationId: string): Promise<GHLCategory[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Extracts posts (lessons) from a category.
|
|
71
|
+
*/
|
|
72
|
+
export declare function extractPosts(page: Page, productId: string, categoryId: string, locationId: string): Promise<GHLPost[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Builds the complete course structure.
|
|
75
|
+
*/
|
|
76
|
+
export declare function buildGHLCourseStructure(page: Page, courseUrl: string, onProgress?: (progress: GHLScanProgress) => void): Promise<GHLCourseStructure | null>;
|
|
77
|
+
/**
|
|
78
|
+
* Creates a filesystem-safe name from a string.
|
|
79
|
+
*/
|
|
80
|
+
export declare function slugify(name: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Creates a folder name with index prefix.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createFolderName(index: number, name: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Constructs the URL for a GHL course page.
|
|
87
|
+
*/
|
|
88
|
+
export declare function getGHLCourseUrl(domain: string, productId: string): string;
|
|
89
|
+
/**
|
|
90
|
+
* Constructs the URL for a GHL lesson (post) page.
|
|
91
|
+
*/
|
|
92
|
+
export declare function getGHLPostUrl(domain: string, productId: string, categoryId: string, postId: string): string;
|
|
93
|
+
//# sourceMappingURL=navigator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigator.d.ts","sourceRoot":"","sources":["../../../src/scraper/ghl/navigator.ts"],"names":[],"mappings":"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"}
|