tronclass-auto 1.5.1 → 1.5.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/video.js +33 -109
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tronclass-auto",
3
- "version": "1.5.1",
3
+ "version": "1.5.3",
4
4
  "description": "自動觀看 eclass/TronClass 影片、填寫表單的 CLI 工具",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/video.js CHANGED
@@ -21,23 +21,22 @@ function log(msg) {
21
21
  }
22
22
 
23
23
  async function detectPlayerType(page) {
24
- return page.evaluate(() => {
24
+ const type = await page.evaluate(() => {
25
25
  const v = document.querySelector('video');
26
26
  if (v) return 'html5';
27
-
27
+ const yt = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"], iframe[src*="vimeo"]');
28
+ if (yt) return 'youtube';
28
29
  for (const f of document.querySelectorAll('iframe')) {
29
- const src = (f.src || f.getAttribute('data-src') || '').toLowerCase();
30
- if (src.includes('youtube') || src.includes('youtu.be')) return 'youtube';
31
- if (src.includes('vimeo')) return 'vimeo';
32
- try {
33
- if (f.contentDocument) {
34
- const fv = f.contentDocument.querySelector('video');
35
- if (fv) return 'html5';
36
- }
37
- } catch (e) {}
30
+ try { if (f.contentDocument && f.contentDocument.querySelector('video')) return 'html5'; } catch (e) {}
38
31
  }
39
32
  return 'none';
40
33
  });
34
+ if (type !== 'none') return type;
35
+ try {
36
+ const ytFrame = page.frame({ url: /youtube|youtu\.be/ });
37
+ if (ytFrame) return 'youtube';
38
+ } catch (e) {}
39
+ return 'none';
41
40
  }
42
41
 
43
42
  async function watchVideo(page, stats) {
@@ -60,114 +59,39 @@ async function watchYouTube(page, stats) {
60
59
  let rate = 1;
61
60
 
62
61
  try {
63
- await page.evaluate(() => {
64
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
65
- if (f) f.scrollIntoView({ block: 'center' });
66
- });
67
- await page.waitForTimeout(2000);
62
+ const ytFrame = page.frame({ url: /youtube|youtu\.be/ });
68
63
 
69
- const ytFrame = page.locator('iframe[src*="youtube"], iframe[src*="youtu.be"]');
70
- await ytFrame.click({ timeout: 5000 }).catch(() => {});
71
- await page.waitForTimeout(5000);
64
+ if (!ytFrame) {
65
+ log(chalk.yellow(' YouTube frame not found'));
66
+ return false;
67
+ }
72
68
 
73
- const postMsg = async (msg) => {
74
- await page.evaluate((m) => {
75
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
76
- if (f) f.contentWindow.postMessage(m, '*');
77
- }, typeof msg === 'string' ? msg : JSON.stringify(msg));
69
+ const evalYT = async (code) => {
70
+ return await ytFrame.evaluate(code).catch(() => null);
78
71
  };
79
72
 
80
- await postMsg('{"event":"listening"}');
81
- await page.waitForTimeout(2000);
82
- await postMsg({ event: 'command', func: 'mute', args: [] });
83
- await page.waitForTimeout(1000);
84
- await postMsg({ event: 'command', func: 'setPlaybackRate', args: [2] });
73
+ log(chalk.blue(' Starting video...'));
74
+ await evalYT("() => { const p = document.querySelector('#movie_player'); if (p) p.playVideo(); }");
75
+ await page.waitForTimeout(3000);
76
+
77
+ const state1 = await evalYT("() => { const p = document.querySelector('#movie_player'); return p ? p.getPlayerState() : -1; }");
78
+ if (state1 !== 1) {
79
+ log(chalk.yellow(' Retrying play...'));
80
+ await evalYT("() => { const p = document.querySelector('#movie_player'); if (p) p.playVideo(); }");
81
+ await page.waitForTimeout(3000);
82
+ }
83
+
84
+ await evalYT("() => { const p = document.querySelector('#movie_player'); if (p) { p.mute(); p.setPlaybackRate(2); } }");
85
85
  await page.waitForTimeout(2000);
86
- await postMsg({ event: 'command', func: 'playVideo', args: [] });
87
- await page.waitForTimeout(5000);
88
86
 
89
- rate = await page.evaluate(() => {
90
- return new Promise((resolve) => {
91
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
92
- if (!f) { resolve(1); return; }
93
- let resolved = false;
94
- const handler = (e) => {
95
- try {
96
- const d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
97
- if (d.event === 'infoDelivery' && d.info && d.info.playbackRate !== undefined && !resolved) {
98
- resolved = true;
99
- window.removeEventListener('message', handler);
100
- resolve(d.info.playbackRate);
101
- }
102
- } catch(e) {}
103
- };
104
- window.addEventListener('message', handler);
105
- f.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'getPlaybackRate', args: [] }), '*');
106
- setTimeout(() => { if (!resolved) { resolved = true; window.removeEventListener('message', handler); resolve(1); } }, 5000);
107
- });
108
- });
87
+ rate = await evalYT("() => { const p = document.querySelector('#movie_player'); return p ? p.getPlaybackRate() : 1; }") || 1;
109
88
  log(chalk.blue(` Speed: ${rate}x`));
110
89
 
111
- const isPlaying = await page.evaluate(() => {
112
- return new Promise((resolve) => {
113
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
114
- if (!f) { resolve(false); return; }
115
- let resolved = false;
116
- const handler = (e) => {
117
- try {
118
- const d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
119
- if (d.event === 'infoDelivery' && d.info && !resolved) {
120
- resolved = true;
121
- window.removeEventListener('message', handler);
122
- resolve(d.info.currentTime > 0);
123
- }
124
- } catch(e) {}
125
- };
126
- window.addEventListener('message', handler);
127
- f.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'getCurrentTime', args: [] }), '*');
128
- setTimeout(() => { if (!resolved) { resolved = true; window.removeEventListener('message', handler); resolve(false); } }, 5000);
129
- });
130
- });
131
-
132
- if (isPlaying) {
90
+ const state2 = await evalYT("() => { const p = document.querySelector('#movie_player'); return p ? p.getPlayerState() : -1; }");
91
+ if (state2 === 1) {
133
92
  log(chalk.green(' Playing ✓'));
134
93
  } else {
135
- log(chalk.yellow(' Not playing, retrying...'));
136
- await page.evaluate(() => {
137
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
138
- if (!f) return;
139
- f.contentWindow.postMessage('{"event":"listening"}', '*');
140
- });
141
- await page.waitForTimeout(3000);
142
- await page.evaluate(() => {
143
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
144
- if (!f) return;
145
- f.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'playVideo', args: [] }), '*');
146
- });
147
- await page.waitForTimeout(5000);
148
-
149
- const retry = await page.evaluate(() => {
150
- return new Promise((resolve) => {
151
- const f = document.querySelector('iframe[src*="youtube"], iframe[src*="youtu.be"]');
152
- if (!f) { resolve(false); return; }
153
- let resolved = false;
154
- const handler = (e) => {
155
- try {
156
- const d = typeof e.data === 'string' ? JSON.parse(e.data) : e.data;
157
- if (d.event === 'infoDelivery' && d.info && !resolved) {
158
- resolved = true;
159
- window.removeEventListener('message', handler);
160
- resolve(d.info.currentTime > 0);
161
- }
162
- } catch(e) {}
163
- };
164
- window.addEventListener('message', handler);
165
- f.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'getCurrentTime', args: [] }), '*');
166
- setTimeout(() => { if (!resolved) { resolved = true; window.removeEventListener('message', handler); resolve(false); } }, 5000);
167
- });
168
- });
169
- if (retry) log(chalk.green(' Playing ✓'));
170
- else log(chalk.yellow(' Could not verify playback'));
94
+ log(chalk.yellow(` State: ${state2}`));
171
95
  }
172
96
  } catch (e) {
173
97
  log(chalk.yellow(` YouTube error: ${e.message}`));