Skip to content
This repository was archived by the owner on Aug 28, 2021. It is now read-only.

Commit ae5e464

Browse files
authored
Merge pull request #77 from CT1994/echo360-download-url-path-fix
add the ability to download direct url if not hls
2 parents 1615e98 + 03835e8 commit ae5e464

2 files changed

Lines changed: 60 additions & 24 deletions

File tree

app/src/background.js

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,62 @@
11
async function getDownloadLink({lessonID, lessonName}, echo360Domain, downloadHD) {
2-
const regex = /(?:\(\")(?:.*)(?:\"\))/;
2+
const classroomAppRegex = new RegExp('(classroomApp)');
3+
const dataRegex = /(?:\(\")(?:.*)(?:\"\))/;
34
const lessonHTMLPageRequest = new Request(`${echo360Domain}/lesson/${lessonID}/classroom`, { method: 'GET', credentials: 'include' });
45
const lessonHTMLPageResponse = await fetch(lessonHTMLPageRequest)
56
const lessonHTMLPageText = await lessonHTMLPageResponse.text();
67
const dummyEl = document.createElement('html')
78
dummyEl.innerHTML = lessonHTMLPageText;
9+
const videoDataScript = Array.from(dummyEl.getElementsByTagName('script')).filter((script) => classroomAppRegex.test(script.innerText));
810

9-
const videoDataString = dummyEl.getElementsByTagName('script')[11].innerText.match(regex)[0]
11+
if (videoDataScript.length === 0)
12+
{
13+
return null;
14+
}
15+
16+
const videoDataString = videoDataScript[0].innerText.match(dataRegex)[0];
17+
1018
const cleanString = videoDataString.substring(1, videoDataString.length - 1);
1119
const videoDataObject = JSON.parse(JSON.parse(cleanString));
1220

13-
let totalSoruces = 0;
21+
const videosData = videoDataObject.video.playableMedias.filter((videoData) => {
22+
const includesAudio = videoData.trackType.includes('Audio')
23+
const includesVideo = videoData.trackType.includes('Video')
24+
const wantedQuality = downloadHD ? videoData.quality.includes(1) : videoData.quality.includes(0)
25+
return includesAudio && includesVideo && wantedQuality;
26+
})
1427

15-
if (!videoDataObject.video) {
28+
if (videosData.length === 0) {
1629
return null;
1730
}
1831

19-
videoDataObject.video.playableMedias.forEach((media) => {
20-
if (media.sourceIndex > totalSoruces) {
21-
totalSoruces = media.sourceIndex;
32+
const downloadArray = videosData.map((videoData) => {
33+
const quality = downloadHD ? `hd` : `sd`;
34+
const videoName = `video_source_${videoData.sourceIndex}_${quality}.mp4`
35+
36+
if (videoData.isHls)
37+
{
38+
// here i am guessing what the url is since hls video are different format
39+
const templateUrl = new URL(videoData.uri);
40+
templateUrl.search = '';
41+
templateUrl.pathname = templateUrl.pathname.replace(/\/[^\/]*$/, `/${quality}${videoData.sourceIndex}.mp4`)
42+
43+
return {
44+
url: templateUrl.href,
45+
lessonName,
46+
videoName,
47+
}
2248
}
23-
})
2449

25-
const downloadArray = [];
26-
for (let i = 1; i <= totalSoruces; i++) {
27-
const quality = downloadHD ? `hd${i}.mp4` : `sd${i}.mp4`;
28-
const videoName = `video_source_${i}_${quality}`
29-
const templateUrl = new URL(videoDataObject.video.playableMedias[0].uri);
50+
const templateUrl = new URL(videoData.uri);
3051
templateUrl.search = '';
31-
templateUrl.pathname = templateUrl.pathname.replace(/\/[^\/]*$/, `/${quality}`)
3252

33-
downloadArray.push({
53+
return {
3454
url: templateUrl.href,
3555
lessonName,
3656
videoName,
37-
});
38-
}
57+
}
58+
59+
});
3960

4061
return downloadArray;
4162
}

app/src/popup.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,16 @@ const echo360BaseURIs = [
3030
* @param {*} param0
3131
* @returns {boolean}
3232
*/
33-
function canDownload({ lesson }) {
33+
function canDownload(lesson) {
3434
if (lesson.medias.length <= 0) {
3535
return false;
3636
}
3737

3838
return lesson.medias.some((media) => media.mediaType === "Video")
3939
}
4040

41-
function getVideoFileName({lesson}) {
42-
const {updatedAt} = lesson.lesson;
41+
function getVideoFileName(lesson) {
42+
const { updatedAt } = lesson.lesson;
4343
return updatedAt.slice(0, updatedAt.indexOf("T"));
4444
}
4545

@@ -55,7 +55,7 @@ async function getCourseName(courseSectionId) {
5555

5656
const courseMatch = courseDataJson.data[0].userSections.find((userSection) => userSection.sectionId === courseSectionId)
5757

58-
return courseMatch.courseName.replace(/[/\\?%*:|"<>]/g, ' ')
58+
return courseMatch ? courseMatch.courseName.replace(/[/\\?%*:|"<>]/g, ' ') : 'unknown course';
5959
}
6060

6161
/**
@@ -68,6 +68,20 @@ async function getMediaData({ url }) {
6868
return getMediaLessonsResponse.json();
6969
}
7070

71+
function getLessons(mediaLessonsJson) {
72+
const lessons = [];
73+
mediaLessonsJson.data.forEach((mediaLessonData) => {
74+
if (mediaLessonData.lessons) {
75+
mediaLessonData.lessons.forEach((lesson) => lessons.push(lesson.lesson));
76+
}
77+
else {
78+
lessons.push(mediaLessonData.lesson);
79+
}
80+
})
81+
82+
return lessons;
83+
}
84+
7185
// Job of this function is to listen init mediaLessons once per click.
7286
async function webRequestOnComplete(xhrRequest) {
7387
console.log("Media Lessons obtained!");
@@ -76,11 +90,12 @@ async function webRequestOnComplete(xhrRequest) {
7690
mediaLessons = xhrRequest;
7791

7892
const getMediaLessonsJson = await getMediaData(mediaLessons);
79-
const courseSectionId = getMediaLessonsJson.data[0].lesson.lesson.sectionId;
93+
const lessons = getLessons(getMediaLessonsJson);
94+
const courseSectionId = lessons[0].lesson.sectionId;
8095
courseName = await getCourseName(courseSectionId);
8196

8297
console.log(getMediaLessonsJson);
83-
downloadables = getMediaLessonsJson.data.filter((dataItem) => {
98+
downloadables = lessons.filter((dataItem) => {
8499
return canDownload(dataItem);
85100
});
86101

@@ -169,7 +184,7 @@ document.addEventListener('DOMContentLoaded', function () {
169184
options.forEach((option, i) => {
170185
if (option.selected) {
171186
toDownload.push({
172-
lessonID: downloadables[i].lesson.lesson.id,
187+
lessonID: downloadables[i].lesson.id,
173188
lessonName: getVideoFileName(downloadables[i]),
174189
})
175190
}

0 commit comments

Comments
 (0)