tronclass-auto 1.3.1 → 1.3.3
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/package.json +1 -1
- package/src/index.js +35 -20
- package/src/video.js +1 -2
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -32,14 +32,21 @@ async function getUncompleted(page, courseId) {
|
|
|
32
32
|
let isExpired = false;
|
|
33
33
|
try { isUpcoming = scope.activityUpcoming(a); } catch (e) {}
|
|
34
34
|
try { isExpired = scope.activityExpired(a); } catch (e) {}
|
|
35
|
-
if (isUpcoming) return;
|
|
36
35
|
|
|
37
36
|
let timeRange = '';
|
|
37
|
+
let startTime = '';
|
|
38
38
|
try {
|
|
39
39
|
const txt = actEl.textContent || '';
|
|
40
40
|
const tm = txt.match(/時間:\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})\s*~\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})/);
|
|
41
|
-
if (tm)
|
|
41
|
+
if (tm) {
|
|
42
|
+
timeRange = tm[0];
|
|
43
|
+
startTime = tm[1];
|
|
44
|
+
}
|
|
42
45
|
} catch (e) {}
|
|
46
|
+
|
|
47
|
+
const now = new Date();
|
|
48
|
+
const startDate = startTime ? new Date(startTime.replace(' ', 'T')) : null;
|
|
49
|
+
if (isUpcoming && startDate && startDate > now) return;
|
|
43
50
|
let durationSec = 0;
|
|
44
51
|
try {
|
|
45
52
|
const durText = actEl.querySelector('.activity-attribute');
|
|
@@ -73,25 +80,30 @@ async function processCourse(page, courseId, stats) {
|
|
|
73
80
|
let done = 0;
|
|
74
81
|
let skip = 0;
|
|
75
82
|
let fail = 0;
|
|
83
|
+
let totalProcessed = 0;
|
|
76
84
|
|
|
77
|
-
|
|
78
|
-
const videos = uncompleted.filter(u => u.type === 'online_video');
|
|
79
|
-
const remaining = videos.filter(v => !isDone(courseId, v.id));
|
|
85
|
+
console.log(chalk.cyan(` [fetching course activities...]`));
|
|
80
86
|
|
|
81
|
-
|
|
87
|
+
while (true) {
|
|
88
|
+
const uncompleted = await getUncompleted(page, courseId);
|
|
89
|
+
const videos = uncompleted.filter(u => u.type === 'online_video');
|
|
90
|
+
const remaining = videos.filter(v => !isDone(courseId, v.id));
|
|
82
91
|
|
|
83
|
-
|
|
84
|
-
const estWatchTime = Math.ceil(totalDuration / 2) + remaining.length * 15;
|
|
85
|
-
console.log(chalk.cyan(` 預估時間: ${formatTime(estWatchTime)}`));
|
|
92
|
+
if (remaining.length === 0) break;
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
if (totalProcessed === 0) {
|
|
95
|
+
console.log(chalk.cyan(` Available: ${videos.length} videos, remaining: ${remaining.length}`));
|
|
96
|
+
const totalDuration = remaining.reduce((sum, v) => sum + (v.durationSec || 120), 0);
|
|
97
|
+
const estWatchTime = Math.ceil(totalDuration / 2) + remaining.length * 15;
|
|
98
|
+
console.log(chalk.cyan(` 預估時間: ${formatTime(estWatchTime)}`));
|
|
99
|
+
if (stats) {
|
|
100
|
+
stats.remainingVideos = remaining.length;
|
|
101
|
+
stats.estimatedTimeForRemaining = estWatchTime;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
91
104
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
console.log(chalk.white(`\n [${i + 1}/${remaining.length}] ${act.title}`));
|
|
105
|
+
const act = remaining[0];
|
|
106
|
+
console.log(chalk.white(`\n [${totalProcessed + 1}] ${act.title}`));
|
|
95
107
|
|
|
96
108
|
const url = `${BASE_URL}/course/${courseId}/learning-activity/full-screen#/${act.id}`;
|
|
97
109
|
try {
|
|
@@ -100,15 +112,17 @@ async function processCourse(page, courseId, stats) {
|
|
|
100
112
|
await page.waitForTimeout(5000);
|
|
101
113
|
|
|
102
114
|
if (!page.url().includes('learning-activity')) {
|
|
103
|
-
console.log(chalk.yellow('
|
|
115
|
+
console.log(chalk.yellow(' [WARN] Failed to load, locked or skipped'));
|
|
104
116
|
skip++;
|
|
117
|
+
markDone(courseId, act.id);
|
|
118
|
+
totalProcessed++;
|
|
105
119
|
continue;
|
|
106
120
|
}
|
|
107
121
|
|
|
108
122
|
try {
|
|
109
123
|
const thisDuration = Math.ceil((act.durationSec || 120) / 2) + 15;
|
|
110
124
|
if (stats) {
|
|
111
|
-
stats.remainingVideos
|
|
125
|
+
stats.remainingVideos--;
|
|
112
126
|
stats.estimatedTimeForRemaining -= thisDuration;
|
|
113
127
|
if (stats.estimatedTimeForRemaining < 0) stats.estimatedTimeForRemaining = 0;
|
|
114
128
|
}
|
|
@@ -116,15 +130,16 @@ async function processCourse(page, courseId, stats) {
|
|
|
116
130
|
if (success) {
|
|
117
131
|
markDone(courseId, act.id);
|
|
118
132
|
done++;
|
|
119
|
-
console.log(chalk.green('
|
|
133
|
+
console.log(chalk.green(' ✓ Saved'));
|
|
120
134
|
} else {
|
|
121
135
|
fail++;
|
|
122
136
|
}
|
|
123
137
|
} catch (e) {
|
|
124
|
-
console.log(chalk.red(`
|
|
138
|
+
console.log(chalk.red(` [ERROR] ${e.message}`));
|
|
125
139
|
fail++;
|
|
126
140
|
}
|
|
127
141
|
|
|
142
|
+
totalProcessed++;
|
|
128
143
|
await page.waitForTimeout(2000);
|
|
129
144
|
}
|
|
130
145
|
|