vikarshana commited on
Commit
0c4e80b
·
verified ·
1 Parent(s): 58819e0

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +75 -218
server.js CHANGED
@@ -8,7 +8,7 @@ const app = express();
8
  const PORT = 7860;
9
 
10
  // 中间件
11
- app.use(express.json({ limit: '10mb' }));
12
  app.use(express.static('.'));
13
 
14
  // CORS支持
@@ -23,226 +23,83 @@ app.use((req, res, next) => {
23
  }
24
  });
25
 
26
- // 生成PDF的API端点
27
- app.post('/api/generate-pdf', async (req, res) => {
28
- let browser = null;
29
-
30
- try {
31
- console.log('开始生成PDF...');
32
- const { pages, filename = 'mathdrills.pdf' } = req.body;
33
-
34
- if (!pages || !Array.isArray(pages) || pages.length === 0) {
35
- return res.status(400).json({ error: '没有提供页面数据' });
36
- }
37
-
38
- console.log(`收到 ${pages.length} 页数据`);
39
-
40
- // 启动Puppeteer
41
- browser = await puppeteer.launch({
42
- executablePath: '/opt/google/chrome/chrome',
43
- headless: 'new',
44
- args: [
45
- '--no-sandbox',
46
- '--disable-setuid-sandbox',
47
- '--disable-dev-shm-usage',
48
- '--disable-accelerated-2d-canvas',
49
- '--no-first-run',
50
- '--no-zygote',
51
- '--disable-gpu'
52
- ]
53
- });
54
-
55
- const page = await browser.newPage();
56
-
57
- // 设置页面尺寸为A4
58
- await page.setViewport({
59
- width: 794, // A4宽度 (210mm at 96dpi)
60
- height: 1123, // A4高度 (297mm at 96dpi)
61
- deviceScaleFactor: 2
62
- });
63
-
64
- // 创建完整的HTML文档
65
- const htmlContent = generateHTMLDocument(pages);
66
-
67
- // 设置页面内容
68
- await page.setContent(htmlContent, {
69
- waitUntil: ['networkidle0', 'domcontentloaded'],
70
- timeout: 30000
71
- });
72
-
73
- // 等待字体和图片加载
74
- await page.evaluateHandle('document.fonts.ready');
75
- await new Promise(resolve => setTimeout(resolve, 2000));
76
-
77
- console.log('开始生成PDF...');
78
-
79
- // 生成PDF
80
- const pdfBuffer = await page.pdf({
81
- format: 'A4',
82
- printBackground: true,
83
- margin: {
84
- top: '10mm',
85
- right: '10mm',
86
- bottom: '10mm',
87
- left: '10mm'
88
- },
89
- preferCSSPageSize: true
90
- });
91
-
92
- console.log(`PDF生成成功,大小: ${pdfBuffer.length} bytes`);
93
-
94
- // 设置响应头
95
- res.setHeader('Content-Type', 'application/pdf');
96
-
97
- // 对文件名进行URL编码以支持中文
98
- const encodedFilename = encodeURIComponent(filename);
99
- res.setHeader('Content-Disposition', `attachment; filename*=UTF-8''${encodedFilename}`);
100
- res.setHeader('Content-Length', pdfBuffer.length);
101
-
102
- // 发送PDF
103
- res.send(pdfBuffer);
104
-
105
- } catch (error) {
106
- console.error('PDF生成失败:', error);
107
- res.status(500).json({
108
- error: 'PDF生成失败',
109
- message: error.message
110
- });
111
- } finally {
112
- if (browser) {
113
- await browser.close();
114
- }
115
- }
116
- });
117
 
118
- // 生成图片的API端点
119
- app.post('/api/generate-images', async (req, res) => {
120
- let browser = null;
121
-
122
- try {
123
- console.log('开始生成图片...');
124
- const { pages } = req.body;
125
-
126
- if (!pages || !Array.isArray(pages) || pages.length === 0) {
127
- return res.status(400).json({ error: '没有提供页面数据' });
128
- }
129
-
130
- console.log(`收到 ${pages.length} 页数据`);
131
-
132
- // 启动Puppeteer
133
- browser = await puppeteer.launch({
134
- executablePath: '/opt/google/chrome/chrome',
135
- headless: 'new',
136
- args: ['--no-sandbox', '--disable-setuid-sandbox']
137
- });
138
-
139
- const images = [];
140
-
141
- for (let i = 0; i < pages.length; i++) {
142
- console.log(`处理第 ${i + 1}/${pages.length} 页...`);
143
-
144
- const page = await browser.newPage();
145
-
146
- // 设置页面尺寸
147
- await page.setViewport({
148
- width: 794,
149
- height: 1123,
150
- deviceScaleFactor: 2
151
- });
152
-
153
- // 创建单页HTML
154
- const htmlContent = generateHTMLDocument([pages[i]]);
155
-
156
- await page.setContent(htmlContent, {
157
- waitUntil: ['networkidle0', 'domcontentloaded'],
158
- timeout: 30000
159
- });
160
-
161
- await page.evaluateHandle('document.fonts.ready');
162
- await new Promise(resolve => setTimeout(resolve, 1000));
163
-
164
- // 截图
165
- const screenshot = await page.screenshot({
166
- type: 'png',
167
- fullPage: true,
168
- omitBackground: false
169
- });
170
-
171
- images.push({
172
- index: i + 1,
173
- data: screenshot.toString('base64'),
174
- filename: `mathdrills_page_${i + 1}.png`
175
- });
176
-
177
- await page.close();
178
- }
179
-
180
- console.log(`所有图片生成完成`);
181
- res.json({ images });
182
-
183
- } catch (error) {
184
- console.error('图片生成失败:', error);
185
- res.status(500).json({
186
- error: '图片生成失败',
187
- message: error.message
188
- });
189
- } finally {
190
- if (browser) {
191
- await browser.close();
192
  }
193
- }
194
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
- // 生成完整的HTML文档
197
- function generateHTMLDocument(pages) {
198
- const cssContent = fs.readFileSync('./styles/pdf-styles.css', 'utf8');
199
- const pagesHTML = pages.map(pageData => pageData.html).join('');
200
- const baseURL = `http://localhost:${PORT}`;
201
-
202
- return `
203
- <!DOCTYPE html>
204
- <html lang="zh">
205
- <head>
206
- <meta charset="UTF-8">
207
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
208
- <title>数学练习题</title>
209
- <base href="${baseURL}">
210
- <style>
211
- ${cssContent}
212
-
213
- /* Puppeteer 优化样式 */
214
- body {
215
- margin: 0 !important;
216
- padding: 0 !important;
217
- background: white !important;
218
- font-family: 'Source Han Sans SC VF', 'Arial', 'Microsoft YaHei', sans-serif;
219
- display: block !important; /* 覆盖 a4.css 中的 flex 布局 */
220
- }
221
- ${fs.readFileSync('./assets/font.css', 'utf8')}
222
-
223
- /* 强制分页 */
224
- .print-page {
225
- page-break-after: always !important;
226
- }
227
-
228
- .print-page:last-child {
229
- page-break-after: auto !important;
230
- }
231
-
232
- /* 允许第四个内容部分根据内容扩展 */
233
- .content-section:nth-child(4) {
234
- height: auto;
235
- min-height: var(--section-height);
236
- }
237
- </style>
238
- </head>
239
- <body>
240
- ${pagesHTML}
241
- </body>
242
- </html>
243
- `;
244
  }
245
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  async function capturetokenandcookies(url) {
247
  let browser;
248
  try {
@@ -351,8 +208,8 @@ app.get('/api/cinex', async (req, res) => {
351
 
352
 
353
  // 健康检查端点
354
- app.get('/api/health', (req, res) => {
355
- res.json({ status: 'ok', timestamp: new Date().toISOString() });
356
  });
357
 
358
  // 启动服务器
 
8
  const PORT = 7860;
9
 
10
  // 中间件
11
+ app.use(express.json({ limit: '40mb' }));
12
  app.use(express.static('.'));
13
 
14
  // CORS支持
 
23
  }
24
  });
25
 
26
+ async function captureHTML(url) {
27
+ let browser;
28
+ try {
29
+ browser = await puppeteer.launch({
30
+ executablePath: "/opt/google/chrome/chrome", // adjust if needed
31
+ headless: "new",
32
+ args: [
33
+ "--no-sandbox",
34
+ "--disable-setuid-sandbox",
35
+ "--disable-web-security",
36
+ "--disable-gpu",
37
+ "--no-zygote",
38
+ ],
39
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
+ const page = await browser.newPage();
42
+
43
+ await page.setUserAgent(
44
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
45
+ "(KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
46
+ );
47
+
48
+ await page.evaluateOnNewDocument(() => {
49
+ Object.defineProperty(navigator, "webdriver", { get: () => false });
50
+ Object.defineProperty(navigator, "plugins", { get: () => [1, 2, 3] });
51
+ Object.defineProperty(navigator, "languages", { get: () => ["en-US", "en"] });
52
+ window.chrome = { runtime: {} };
53
+ });
54
+
55
+ await page.evaluateOnNewDocument(() => {
56
+ const metas = document.getElementsByTagName("meta");
57
+ for (let i = metas.length - 1; i >= 0; i--) {
58
+ if (metas[i].httpEquiv && metas[i].httpEquiv.toLowerCase() === "refresh") {
59
+ metas[i].remove();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  }
61
+ }
62
+ });
63
+
64
+ await page.setRequestInterception(true);
65
+ page.on("request", (request) => {
66
+ const reqUrl = request.url();
67
+ if (reqUrl.includes("disable-devtool") || reqUrl.includes("shoagloumtoamir.net")) {
68
+ request.abort();
69
+ } else {
70
+ request.continue();
71
+ }
72
+ });
73
+
74
+ await page.goto(url, { waitUntil: "load", timeout: 60000 });
75
+
76
+ await page.waitForNetworkIdle();
77
+
78
+ const html = await page.content();
79
 
80
+ await browser.close();
81
+ return { html };
82
+ } catch (e) {
83
+ if (browser) await browser.close();
84
+ console.error(e);
85
+ throw e;
86
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  }
88
 
89
+ app.get("/api/bypass", async (req, res) => {
90
+ const { url } = req.query;
91
+ if (!url) {
92
+ return res.status(400).json({ error: "URL is required" });
93
+ }
94
+
95
+ try {
96
+ const result = await captureHTML(url);
97
+ res.json(result);
98
+ } catch (err) {
99
+ res.status(500).json({ error: "Failed to capture HTML" });
100
+ }
101
+ });
102
+
103
  async function capturetokenandcookies(url) {
104
  let browser;
105
  try {
 
208
 
209
 
210
  // 健康检查端点
211
+ app.get('/', (req, res) => {
212
+ res.json({ status: 'hii', timestamp: new Date().toISOString() });
213
  });
214
 
215
  // 启动服务器