tronclass-auto 1.2.3 → 1.2.5

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tronclass-auto",
3
- "version": "1.2.3",
3
+ "version": "1.2.5",
4
4
  "description": "自動觀看 eclass/TronClass 影片、填寫表單的 CLI 工具",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/auth.js CHANGED
@@ -85,7 +85,7 @@ async function autoLogin(baseUrl) {
85
85
  const exePath = await ensureBrowser();
86
86
 
87
87
  const { chromium } = require('playwright');
88
- const launchOpts = { headless: false, slowMo: 50 };
88
+ const launchOpts = { headless: false, slowMo: 50, args: ['--disable-background-timer-throttling'] };
89
89
  if (exePath) launchOpts.executablePath = exePath;
90
90
 
91
91
  const browser = await chromium.launch(launchOpts);
package/src/index.js CHANGED
@@ -103,7 +103,7 @@ async function processCourse(page, courseId, stats) {
103
103
  if (success) {
104
104
  markDone(courseId, act.id);
105
105
  done++;
106
- console.log(chalk.green(' [OK] Saved'));
106
+ console.log(chalk.green(' ✓ Saved'));
107
107
  } else {
108
108
  fail++;
109
109
  }
@@ -130,7 +130,7 @@ async function showStatus() {
130
130
  const { chromium } = re('playwright');
131
131
  const { ensureBrowser } = re('./browser');
132
132
  const exePath = await ensureBrowser();
133
- const launchOpts = { headless: true, slowMo: 50 };
133
+ const launchOpts = { headless: true, slowMo: 50, args: ['--disable-gpu', '--disable-software-rasterizer'] };
134
134
  if (exePath) launchOpts.executablePath = exePath;
135
135
  const browser = await chromium.launch(launchOpts);
136
136
  const context = await browser.newContext();
@@ -195,7 +195,16 @@ async function launchBrowser(headless) {
195
195
  const { chromium } = re('playwright');
196
196
  const { ensureBrowser } = re('./browser');
197
197
  const exePath = await ensureBrowser();
198
- const launchOpts = { headless, slowMo: 50 };
198
+ const launchOpts = {
199
+ headless,
200
+ slowMo: 50,
201
+ args: [
202
+ '--disable-background-timer-throttling',
203
+ '--disable-backgrounding-occluded-windows',
204
+ '--disable-renderer-backgrounding',
205
+ '--disable-features=MediaFoundationVideoCapture,HardwareMediaKeyHandling',
206
+ ]
207
+ };
199
208
  if (exePath) launchOpts.executablePath = exePath;
200
209
  const browser = await chromium.launch(launchOpts);
201
210
  const context = await browser.newContext({
package/src/video.js CHANGED
@@ -12,14 +12,23 @@ function formatTime(seconds) {
12
12
  return `${s}s`;
13
13
  }
14
14
 
15
+ function progress(msg) {
16
+ process.stdout.write('\r\x1b[K' + msg);
17
+ }
18
+
19
+ function log(msg) {
20
+ process.stdout.write('\n');
21
+ progress(msg);
22
+ }
23
+
15
24
  async function watchVideo(page, stats) {
16
25
  const hasVideo = await page.evaluate(() => document.querySelector('video') !== null);
17
26
  if (!hasVideo) {
18
- log(chalk.yellow(' [VIDEO] No video element'));
27
+ log(chalk.yellow(' No video element'));
19
28
  return false;
20
29
  }
21
30
 
22
- log(chalk.blue(' [VIDEO] Muted + 2x speed'));
31
+ log(chalk.blue(' Muted + 2x'));
23
32
 
24
33
  await page.evaluate(() => {
25
34
  document.querySelectorAll('video').forEach(v => {
@@ -38,7 +47,7 @@ async function watchVideo(page, stats) {
38
47
  });
39
48
 
40
49
  if (!isPlaying) {
41
- log(chalk.yellow(' [VIDEO] Clicking play...'));
50
+ log(chalk.yellow(' Clicking play...'));
42
51
  await page.evaluate(() => {
43
52
  document.querySelectorAll('[class*="play"], .vjs-big-play-button, button').forEach(btn => {
44
53
  if (btn.offsetParent && (btn.className.includes('play') || btn.className.includes('Play'))) {
@@ -56,14 +65,14 @@ async function watchVideo(page, stats) {
56
65
  });
57
66
 
58
67
  if (!duration || duration <= 0) {
59
- log(chalk.yellow(' [VIDEO] Cannot get duration, waiting 30s...'));
68
+ log(chalk.yellow(' Cannot get duration, waiting 30s...'));
60
69
  await page.waitForTimeout(30000);
61
70
  if (stats) stats.videosWatched++;
62
71
  return true;
63
72
  }
64
73
 
65
74
  const waitTime = (duration / 2) + 15;
66
- log(chalk.blue(` [VIDEO] ${formatTime(duration)} video, waiting ~${formatTime(waitTime)} (2x)`));
75
+ log(chalk.blue(` ${formatTime(duration)} video → ~${formatTime(waitTime)} (2x)`));
67
76
 
68
77
  if (stats) {
69
78
  stats.currentVideoDuration = duration / 2;
@@ -93,27 +102,28 @@ async function watchVideo(page, stats) {
93
102
 
94
103
  if (state.p > lastPct) {
95
104
  const pct = state.p;
105
+ const barWidth = 20;
106
+ const filled = Math.floor(barWidth * pct / 100);
107
+ const empty = barWidth - filled;
108
+ const bar = chalk.green('█'.repeat(filled)) + chalk.gray('░'.repeat(empty));
96
109
  const remaining = Math.max(0, waitTime - elapsed);
97
110
  let etaStr = '';
98
111
  if (stats && stats.remainingVideos > 0) {
99
112
  const totalRemaining = remaining + stats.estimatedTimeForRemaining;
100
- etaStr = chalk.gray(` | ETA: ${formatTime(totalRemaining)}`);
113
+ etaStr = chalk.gray(` | ETA ${formatTime(totalRemaining)}`);
101
114
  } else {
102
- etaStr = chalk.gray(` | ~${formatTime(remaining)} left`);
115
+ etaStr = chalk.gray(` | ${formatTime(remaining)} left`);
103
116
  }
104
- log(chalk.blue(` [VIDEO] ${pct}% (${formatTime(elapsed)})${etaStr}`));
117
+ progress(`${bar} ${String(pct).padStart(3)}% (${formatTime(elapsed)})${etaStr}`);
105
118
  lastPct = pct;
106
119
  }
107
120
 
108
121
  if (state.e) {
109
- log(chalk.green(' [VIDEO] 100% Finished'));
122
+ log(chalk.green(' Done ✓'));
110
123
  break;
111
124
  }
112
125
 
113
126
  if (state.stalled) {
114
- if (elapsed % 15 === 0) {
115
- log(chalk.gray(` [VIDEO] Buffering... (${formatTime(elapsed)})`));
116
- }
117
127
  continue;
118
128
  }
119
129
 
@@ -127,10 +137,10 @@ async function watchVideo(page, stats) {
127
137
 
128
138
  restartCount++;
129
139
  if (restartCount > 10) {
130
- log(chalk.red(' [VIDEO] Too many restarts, giving up'));
140
+ log(chalk.red(' Too many restarts, giving up'));
131
141
  return false;
132
142
  }
133
- log(chalk.yellow(` [VIDEO] Paused, restarting (#${restartCount})...`));
143
+ log(chalk.yellow(` Paused, restarting (#${restartCount})...`));
134
144
  await page.evaluate(() => document.querySelector('video').play());
135
145
  await page.waitForTimeout(1000);
136
146
  }
@@ -141,10 +151,6 @@ async function watchVideo(page, stats) {
141
151
  return true;
142
152
  }
143
153
 
144
- function log(msg) {
145
- console.log(msg);
146
- }
147
-
148
154
  function printReport(stats) {
149
155
  console.log('');
150
156
  console.log(chalk.cyan('┌' + '─'.repeat(48) + '┐'));