Upload 8 files
Browse files- Dockerfile +2 -1
- LICENSE +44 -18
- README.md +130 -61
- package.json +4 -4
- server.js +32 -9
Dockerfile
CHANGED
@@ -44,7 +44,8 @@ COPY package*.json ./
|
|
44 |
|
45 |
# 清理 npm cache 并安装依赖
|
46 |
RUN npm cache clean --force \
|
47 |
-
&& npm ci --omit=dev --no-audit --no-fund \
|
|
|
48 |
&& npm cache clean --force
|
49 |
|
50 |
# 复制应用代码
|
|
|
44 |
|
45 |
# 清理 npm cache 并安装依赖
|
46 |
RUN npm cache clean --force \
|
47 |
+
# && npm ci --omit=dev --no-audit --no-fund \
|
48 |
+
&& npm install --only=production --no-audit --no-fund \
|
49 |
&& npm cache clean --force
|
50 |
|
51 |
# 复制应用代码
|
LICENSE
CHANGED
@@ -1,27 +1,53 @@
|
|
1 |
-
PROPRIETARY
|
2 |
|
3 |
Copyright (c) 2024. All rights reserved.
|
4 |
|
5 |
-
NOTICE: This software and its documentation are proprietary and confidential
|
6 |
-
|
7 |
|
8 |
-
RESTRICTIONS:
|
9 |
-
-
|
10 |
-
- You may NOT
|
11 |
-
- You may NOT use this software
|
12 |
-
- You may NOT
|
|
|
|
|
|
|
13 |
|
14 |
-
PERMITTED USES:
|
15 |
-
- Personal, non-commercial use
|
16 |
-
- Educational
|
17 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
COMMERCIAL LICENSING:
|
20 |
-
|
21 |
-
for commercial licensing terms and pricing.
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
shall not be liable for any damages arising from the use of this software.
|
26 |
|
27 |
-
For licensing inquiries
|
|
|
1 |
+
PROPRIETARY NON-COMMERCIAL LICENSE
|
2 |
|
3 |
Copyright (c) 2024. All rights reserved.
|
4 |
|
5 |
+
NOTICE: This software and its documentation are proprietary and confidential.
|
6 |
+
This is NOT open source software and is subject to strict usage restrictions.
|
7 |
|
8 |
+
STRICT RESTRICTIONS:
|
9 |
+
- COMMERCIAL USE IS STRICTLY PROHIBITED
|
10 |
+
- You may NOT sell, rent, lease, or monetize this software in any way
|
11 |
+
- You may NOT use this software in any business or commercial environment
|
12 |
+
- You may NOT copy, modify, distribute, or redistribute this software
|
13 |
+
- You may NOT reverse engineer, decompile, or disassemble this software
|
14 |
+
- You may NOT sublicense or transfer rights to this software
|
15 |
+
- You may NOT remove or modify copyright notices
|
16 |
|
17 |
+
PERMITTED USES ONLY:
|
18 |
+
- Personal, non-commercial use for individual learning purposes
|
19 |
+
- Educational use in academic institutions for teaching purposes only
|
20 |
+
- Research and evaluation for non-commercial academic purposes
|
21 |
+
- Internal testing and development (non-commercial)
|
22 |
+
|
23 |
+
EDUCATIONAL USE REQUIREMENTS:
|
24 |
+
- Must include proper attribution to original author
|
25 |
+
- Cannot be used for any profit-generating activities
|
26 |
+
- Students/teachers cannot commercialize any derivatives
|
27 |
+
- Institution must be accredited educational organization
|
28 |
+
|
29 |
+
TERMINATION:
|
30 |
+
This license terminates automatically if you violate any terms.
|
31 |
+
Upon termination, you must destroy all copies of the software.
|
32 |
+
|
33 |
+
DISCLAIMER OF WARRANTY:
|
34 |
+
This software is provided "AS IS" without warranty of any kind, express or
|
35 |
+
implied. The author disclaims all warranties including merchantability and
|
36 |
+
fitness for a particular purpose.
|
37 |
+
|
38 |
+
LIMITATION OF LIABILITY:
|
39 |
+
The author shall not be liable for any damages whatsoever arising from the
|
40 |
+
use of this software, including but not limited to direct, indirect,
|
41 |
+
incidental, or consequential damages.
|
42 |
|
43 |
COMMERCIAL LICENSING:
|
44 |
+
For any commercial use, you must obtain a separate commercial license.
|
45 |
+
Contact the developer for commercial licensing terms and pricing.
|
46 |
+
|
47 |
+
VIOLATION CONSEQUENCES:
|
48 |
+
Violation of this license may result in legal action and monetary damages.
|
49 |
|
50 |
+
By using this software, you acknowledge that you have read, understood,
|
51 |
+
and agree to be bound by the terms of this license.
|
|
|
52 |
|
53 |
+
For licensing inquiries or permission requests, contact the developer.
|
README.md
CHANGED
@@ -5,12 +5,12 @@ colorFrom: blue
|
|
5 |
colorTo: green
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
-
license:
|
9 |
---
|
10 |
|
11 |
# 📸 Page Screenshot API
|
12 |
|
13 |
-
Professional web page screenshot service built with Node.js and Puppeteer, optimized for Hugging Face Spaces
|
14 |
|
15 |
## 🚀 Live Demo
|
16 |
|
@@ -18,84 +18,111 @@ Professional web page screenshot service built with Node.js and Puppeteer, optim
|
|
18 |
- **Demo Interface**: `https://your-username-page-shot.hf.space/demo`
|
19 |
- **Health Check**: `https://your-username-page-shot.hf.space/`
|
20 |
|
21 |
-
## 🔐
|
22 |
|
23 |
-
|
|
|
24 |
|
25 |
-
|
26 |
-
|
27 |
-
-
|
28 |
-
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
- Higher security for production use
|
34 |
|
35 |
-
|
|
|
36 |
|
37 |
-
### Public Space Access
|
38 |
```bash
|
|
|
39 |
curl -X POST https://your-space.hf.space/screenshot \
|
40 |
-H "Content-Type: application/json" \
|
41 |
-d '{"url": "https://example.com", "width": 1280, "height": 720}' \
|
42 |
--output screenshot.jpg
|
43 |
```
|
44 |
|
45 |
-
### Private Space
|
|
|
|
|
46 |
```bash
|
|
|
47 |
curl -X POST https://your-space.hf.space/screenshot \
|
48 |
-H "Content-Type: application/json" \
|
49 |
-H "Authorization: Bearer hf_your_token_here" \
|
50 |
-
-d '{"url": "https://example.com"
|
51 |
--output screenshot.jpg
|
52 |
```
|
53 |
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
```javascript
|
56 |
-
|
|
|
57 |
method: 'POST',
|
58 |
headers: {
|
59 |
'Content-Type': 'application/json',
|
60 |
-
|
61 |
-
// 'Authorization': 'Bearer hf_your_token_here'
|
62 |
},
|
63 |
body: JSON.stringify({
|
64 |
url: 'https://example.com',
|
65 |
-
|
66 |
-
|
67 |
-
quality: 80
|
68 |
})
|
69 |
});
|
70 |
-
|
71 |
-
const imageBlob = await response.blob();
|
72 |
```
|
73 |
|
74 |
-
|
|
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
|
83 |
## 🔄 Response Examples
|
84 |
|
85 |
### Success Response
|
86 |
```
|
87 |
HTTP/1.1 200 OK
|
88 |
-
Content-Type: image/jpeg
|
89 |
Content-Length: 245760
|
90 |
|
91 |
-
[Binary
|
92 |
```
|
93 |
|
94 |
-
### Error
|
95 |
```json
|
96 |
{
|
97 |
-
"error": "
|
98 |
-
"message": "
|
|
|
99 |
}
|
100 |
```
|
101 |
|
@@ -111,53 +138,95 @@ Content-Length: 245760
|
|
111 |
|
112 |
## 🛠️ Features
|
113 |
|
|
|
|
|
|
|
|
|
114 |
- ✅ **Queue Management** - Handles concurrent requests efficiently
|
115 |
- ✅ **CPU Monitoring** - Automatic load balancing
|
116 |
-
- ✅ **Rate Limiting** - Prevents abuse
|
117 |
-
- ✅ **HF Authentication** - Integrated with HuggingFace platform
|
118 |
- ✅ **Error Handling** - Comprehensive error responses
|
119 |
-
- ✅ **Demo Interface** - Built-in testing UI
|
120 |
- ✅ **Health Monitoring** - Status endpoint for monitoring
|
121 |
|
122 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
### Health Check
|
125 |
```bash
|
126 |
curl https://your-space.hf.space/
|
|
|
127 |
```
|
128 |
|
129 |
### Server Status
|
130 |
```bash
|
131 |
curl https://your-space.hf.space/status
|
|
|
132 |
```
|
133 |
|
134 |
-
## 🚨 Rate Limits
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
|
|
140 |
|
141 |
-
##
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
- HuggingFace platform integration
|
149 |
|
150 |
-
##
|
151 |
|
152 |
-
-
|
153 |
-
-
|
154 |
-
-
|
155 |
-
-
|
156 |
|
157 |
## 📄 License
|
158 |
|
159 |
-
Proprietary -
|
|
|
|
|
|
|
160 |
|
161 |
## 🤝 Support
|
162 |
|
163 |
-
For technical support or
|
|
|
5 |
colorTo: green
|
6 |
sdk: docker
|
7 |
pinned: false
|
8 |
+
license: other
|
9 |
---
|
10 |
|
11 |
# 📸 Page Screenshot API
|
12 |
|
13 |
+
Professional web page screenshot service built with Node.js and Puppeteer, optimized for Hugging Face Spaces with **full-page support** and **flexible authentication**.
|
14 |
|
15 |
## 🚀 Live Demo
|
16 |
|
|
|
18 |
- **Demo Interface**: `https://your-username-page-shot.hf.space/demo`
|
19 |
- **Health Check**: `https://your-username-page-shot.hf.space/`
|
20 |
|
21 |
+
## 🔐 Authentication Options
|
22 |
|
23 |
+
### Option 1: Custom API Key (Recommended)
|
24 |
+
Set `API_KEY` environment variable in Space settings for secure access:
|
25 |
|
26 |
+
```bash
|
27 |
+
# With API key authentication
|
28 |
+
curl -X POST https://your-space.hf.space/screenshot \
|
29 |
+
-H "Content-Type: application/json" \
|
30 |
+
-H "Authorization: Bearer your-api-key-here" \
|
31 |
+
-d '{"url": "https://example.com", "fullPage": true}' \
|
32 |
+
--output screenshot.jpg
|
33 |
+
```
|
|
|
34 |
|
35 |
+
### Option 2: Open Access Mode
|
36 |
+
If no `API_KEY` is set, the API runs in open access mode:
|
37 |
|
|
|
38 |
```bash
|
39 |
+
# Open access (no authentication)
|
40 |
curl -X POST https://your-space.hf.space/screenshot \
|
41 |
-H "Content-Type: application/json" \
|
42 |
-d '{"url": "https://example.com", "width": 1280, "height": 720}' \
|
43 |
--output screenshot.jpg
|
44 |
```
|
45 |
|
46 |
+
### Option 3: Private Space with HF Token
|
47 |
+
For private spaces, use HuggingFace access token:
|
48 |
+
|
49 |
```bash
|
50 |
+
# Private space access
|
51 |
curl -X POST https://your-space.hf.space/screenshot \
|
52 |
-H "Content-Type: application/json" \
|
53 |
-H "Authorization: Bearer hf_your_token_here" \
|
54 |
+
-d '{"url": "https://example.com"}' \
|
55 |
--output screenshot.jpg
|
56 |
```
|
57 |
|
58 |
+
## 📊 API Parameters
|
59 |
+
|
60 |
+
| Parameter | Type | Default | Range | Description |
|
61 |
+
|-----------|------|---------|-------|-------------|
|
62 |
+
| `url` | string | **required** | - | Target webpage URL (must start with http/https) |
|
63 |
+
| `width` | number | 1280 | 100-1600 | Screenshot width in pixels |
|
64 |
+
| `height` | number | 720 | 100-1200 | Screenshot height in pixels |
|
65 |
+
| `quality` | number | 75 | 10-100 | JPEG quality percentage (JPEG only) |
|
66 |
+
| `fullPage` | boolean | false | - | **NEW**: Capture full page length (long screenshots) |
|
67 |
+
| `format` | string | "jpeg" | jpeg/png | **NEW**: Output format (jpeg or png) |
|
68 |
+
|
69 |
+
## 🆕 New Features in v1.5.0
|
70 |
+
|
71 |
+
### 📜 Full Page Screenshots
|
72 |
+
Capture entire webpage including content below the fold:
|
73 |
+
|
74 |
```javascript
|
75 |
+
// Capture full page length
|
76 |
+
const response = await fetch('/screenshot', {
|
77 |
method: 'POST',
|
78 |
headers: {
|
79 |
'Content-Type': 'application/json',
|
80 |
+
'Authorization': 'Bearer your-api-key'
|
|
|
81 |
},
|
82 |
body: JSON.stringify({
|
83 |
url: 'https://example.com',
|
84 |
+
fullPage: true, // 🆕 Captures entire page height
|
85 |
+
format: 'png' // 🆕 PNG format for better quality
|
|
|
86 |
})
|
87 |
});
|
|
|
|
|
88 |
```
|
89 |
|
90 |
+
### 🖼️ Multiple Image Formats
|
91 |
+
Choose between JPEG (smaller size) and PNG (better quality):
|
92 |
|
93 |
+
```bash
|
94 |
+
# PNG format (lossless, larger file)
|
95 |
+
curl -X POST https://your-space.hf.space/screenshot \
|
96 |
+
-H "Content-Type: application/json" \
|
97 |
+
-H "Authorization: Bearer your-api-key" \
|
98 |
+
-d '{"url": "https://example.com", "format": "png"}' \
|
99 |
+
--output screenshot.png
|
100 |
+
|
101 |
+
# JPEG format (compressed, smaller file)
|
102 |
+
curl -X POST https://your-space.hf.space/screenshot \
|
103 |
+
-H "Content-Type: application/json" \
|
104 |
+
-H "Authorization: Bearer your-api-key" \
|
105 |
+
-d '{"url": "https://example.com", "format": "jpeg", "quality": 85}' \
|
106 |
+
--output screenshot.jpg
|
107 |
+
```
|
108 |
|
109 |
## 🔄 Response Examples
|
110 |
|
111 |
### Success Response
|
112 |
```
|
113 |
HTTP/1.1 200 OK
|
114 |
+
Content-Type: image/jpeg # or image/png
|
115 |
Content-Length: 245760
|
116 |
|
117 |
+
[Binary image data]
|
118 |
```
|
119 |
|
120 |
+
### Authentication Error
|
121 |
```json
|
122 |
{
|
123 |
+
"error": "Unauthorized",
|
124 |
+
"message": "Valid API key required. Please provide API key in Authorization header or x-api-key header.",
|
125 |
+
"hint": "Use \"Authorization: Bearer YOUR_API_KEY\" or \"x-api-key: YOUR_API_KEY\""
|
126 |
}
|
127 |
```
|
128 |
|
|
|
138 |
|
139 |
## 🛠️ Features
|
140 |
|
141 |
+
- ✅ **Full Page Screenshots** - Capture entire webpage length
|
142 |
+
- ✅ **Multiple Formats** - JPEG (compressed) and PNG (lossless) support
|
143 |
+
- ✅ **Flexible Authentication** - API key, open access, or HF token
|
144 |
+
- ✅ **Global Font Support** - Renders CJK, Arabic, Emoji fonts correctly
|
145 |
- ✅ **Queue Management** - Handles concurrent requests efficiently
|
146 |
- ✅ **CPU Monitoring** - Automatic load balancing
|
147 |
+
- ✅ **Rate Limiting** - Prevents abuse (100 req/15min)
|
|
|
148 |
- ✅ **Error Handling** - Comprehensive error responses
|
149 |
+
- ✅ **Demo Interface** - Built-in testing UI with auth detection
|
150 |
- ✅ **Health Monitoring** - Status endpoint for monitoring
|
151 |
|
152 |
+
## 🔧 Setup Instructions
|
153 |
+
|
154 |
+
### Step 1: Configure Authentication (Optional)
|
155 |
+
```bash
|
156 |
+
# In HuggingFace Space Settings → Variables
|
157 |
+
API_KEY=sk-your-secure-random-key-here
|
158 |
+
```
|
159 |
+
|
160 |
+
### Step 2: Deploy to HuggingFace Spaces
|
161 |
+
1. Create new Space with Docker SDK
|
162 |
+
2. Upload all files to Space repository
|
163 |
+
3. Set environment variables if needed
|
164 |
+
4. Space will auto-deploy
|
165 |
+
|
166 |
+
### Step 3: Test the API
|
167 |
+
Visit the demo page: `https://your-space.hf.space/demo`
|
168 |
+
|
169 |
+
## 📈 Monitoring Endpoints
|
170 |
|
171 |
### Health Check
|
172 |
```bash
|
173 |
curl https://your-space.hf.space/
|
174 |
+
# Returns API info and authentication status
|
175 |
```
|
176 |
|
177 |
### Server Status
|
178 |
```bash
|
179 |
curl https://your-space.hf.space/status
|
180 |
+
# Returns CPU usage, active requests, queue status
|
181 |
```
|
182 |
|
183 |
+
## 🚨 Rate Limits & Performance
|
184 |
+
|
185 |
+
| Metric | Limit | Notes |
|
186 |
+
|--------|-------|-------|
|
187 |
+
| Requests | 100/15min | Per IP address |
|
188 |
+
| Concurrent | 3 requests | Server queue management |
|
189 |
+
| CPU Threshold | 95% | Auto-rejects when overloaded |
|
190 |
+
| Timeout | 15 seconds | Per screenshot request |
|
191 |
+
| Max Dimensions | 1600x1200 | Viewport size limits |
|
192 |
+
|
193 |
+
## 🔒 Security & License
|
194 |
+
|
195 |
+
- **Proprietary License**: Commercial use requires separate license
|
196 |
+
- **Non-Commercial Use**: Educational and personal use permitted
|
197 |
+
- **API Security**: Optional API key authentication
|
198 |
+
- **Resource Protection**: Built-in rate limiting and queue management
|
199 |
+
|
200 |
+
## 🌍 Global Font Support
|
201 |
|
202 |
+
Optimized for international websites with support for:
|
203 |
+
- **CJK Languages**: Chinese, Japanese, Korean
|
204 |
+
- **RTL Languages**: Arabic, Hebrew
|
205 |
+
- **Emoji & Symbols**: Full Unicode emoji support
|
206 |
+
- **Latin Scripts**: European languages with proper rendering
|
207 |
|
208 |
+
## 🛡️ Production Recommendations
|
209 |
|
210 |
+
1. **Enable API Key**: Set `API_KEY` environment variable for production
|
211 |
+
2. **Use Private Space**: For sensitive or commercial use
|
212 |
+
3. **Implement Retry Logic**: Handle busy server responses
|
213 |
+
4. **Monitor Usage**: Use `/status` endpoint for health checks
|
214 |
+
5. **Choose Format Wisely**: JPEG for photos, PNG for graphics/text
|
|
|
215 |
|
216 |
+
## 📚 Documentation
|
217 |
|
218 |
+
- [API Authentication Guide](API_GUIDE.md)
|
219 |
+
- [Private Space Setup](PRIVATE_SPACE_GUIDE.md)
|
220 |
+
- [Environment Variables](HF_SPACES_ENV_GUIDE.md)
|
221 |
+
- [Deployment Guide](DEPLOYMENT_GUIDE.md)
|
222 |
|
223 |
## 📄 License
|
224 |
|
225 |
+
**Proprietary Non-Commercial License** - See [LICENSE](LICENSE) for full terms.
|
226 |
+
- ✅ Educational and personal use
|
227 |
+
- ❌ Commercial use without license
|
228 |
+
- ❌ Redistribution or modification
|
229 |
|
230 |
## 🤝 Support
|
231 |
|
232 |
+
For commercial licensing, technical support, or feature requests, please contact the administrator.
|
package.json
CHANGED
@@ -1,16 +1,16 @@
|
|
1 |
{
|
2 |
"name": "page-screenshot-api",
|
3 |
-
"version": "1.
|
4 |
-
"description": "Professional web page screenshot API service for Hugging Face Spaces",
|
5 |
"main": "server.js",
|
6 |
"scripts": {
|
7 |
"start": "node server.js",
|
8 |
"dev": "nodemon server.js",
|
9 |
"build": "echo 'No build step required'"
|
10 |
},
|
11 |
-
"keywords": ["screenshot", "api", "puppeteer", "huggingface", "spaces"],
|
12 |
"author": "",
|
13 |
-
"license": "
|
14 |
"private": true,
|
15 |
"dependencies": {
|
16 |
"express": "^4.18.2",
|
|
|
1 |
{
|
2 |
"name": "page-screenshot-api",
|
3 |
+
"version": "1.5.0",
|
4 |
+
"description": "Professional web page screenshot API service for Hugging Face Spaces with full-page support",
|
5 |
"main": "server.js",
|
6 |
"scripts": {
|
7 |
"start": "node server.js",
|
8 |
"dev": "nodemon server.js",
|
9 |
"build": "echo 'No build step required'"
|
10 |
},
|
11 |
+
"keywords": ["screenshot", "api", "puppeteer", "huggingface", "spaces", "fullpage"],
|
12 |
"author": "",
|
13 |
+
"license": "SEE LICENSE IN LICENSE",
|
14 |
"private": true,
|
15 |
"dependencies": {
|
16 |
"express": "^4.18.2",
|
server.js
CHANGED
@@ -171,6 +171,13 @@ app.get('/demo', (req, res) => {
|
|
171 |
<input type="number" id="height" value="720" min="100" max="1200">
|
172 |
<label>Quality:</label>
|
173 |
<input type="number" id="quality" value="75" min="10" max="100">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
</div>
|
175 |
|
176 |
<button onclick="takeScreenshot()">📸 Take Screenshot</button>
|
@@ -195,6 +202,8 @@ app.get('/demo', (req, res) => {
|
|
195 |
const width = parseInt(document.getElementById('width').value);
|
196 |
const height = parseInt(document.getElementById('height').value);
|
197 |
const quality = parseInt(document.getElementById('quality').value);
|
|
|
|
|
198 |
const apiKey = document.getElementById('apiKey') ? document.getElementById('apiKey').value : '';
|
199 |
|
200 |
if (!url) {
|
@@ -225,7 +234,7 @@ app.get('/demo', (req, res) => {
|
|
225 |
const response = await fetch('/screenshot', {
|
226 |
method: 'POST',
|
227 |
headers: headers,
|
228 |
-
body: JSON.stringify({ url, width, height, quality })
|
229 |
});
|
230 |
|
231 |
if (response.ok) {
|
@@ -237,7 +246,7 @@ app.get('/demo', (req, res) => {
|
|
237 |
'<h3 class="success">✅ Screenshot Success!</h3>' +
|
238 |
'<p>Size: ' + size + ' KB | Dimensions: ' + width + 'x' + height + '</p>' +
|
239 |
'<img src="' + imageUrl + '" alt="Screenshot"><br><br>' +
|
240 |
-
'<a href="' + imageUrl + '" download="screenshot.
|
241 |
} else {
|
242 |
const error = await response.json();
|
243 |
document.getElementById('result').innerHTML =
|
@@ -256,7 +265,7 @@ app.get('/demo', (req, res) => {
|
|
256 |
|
257 |
// 截图端点
|
258 |
app.post('/screenshot', authenticate, async (req, res) => {
|
259 |
-
const { url, width = 1280, height = 720, quality = 75 } = req.body;
|
260 |
|
261 |
// 验证参数
|
262 |
if (!url) {
|
@@ -267,6 +276,11 @@ app.post('/screenshot', authenticate, async (req, res) => {
|
|
267 |
return res.status(400).json({ error: 'URL must start with http:// or https://' });
|
268 |
}
|
269 |
|
|
|
|
|
|
|
|
|
|
|
270 |
const cpuUsage = getCpuUsage();
|
271 |
if (cpuUsage > 95) {
|
272 |
return res.status(503).json({
|
@@ -339,13 +353,22 @@ app.post('/screenshot', authenticate, async (req, res) => {
|
|
339 |
timeout: 15000
|
340 |
});
|
341 |
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
fullPage:
|
346 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
|
348 |
-
|
|
|
|
|
349 |
res.send(screenshot);
|
350 |
|
351 |
} catch (error) {
|
|
|
171 |
<input type="number" id="height" value="720" min="100" max="1200">
|
172 |
<label>Quality:</label>
|
173 |
<input type="number" id="quality" value="75" min="10" max="100">
|
174 |
+
<label>Full Page:</label>
|
175 |
+
<input type="checkbox" id="fullPage">
|
176 |
+
<label>Format:</label>
|
177 |
+
<select id="format">
|
178 |
+
<option value="jpeg" selected>JPEG</option>
|
179 |
+
<option value="png">PNG</option>
|
180 |
+
</select>
|
181 |
</div>
|
182 |
|
183 |
<button onclick="takeScreenshot()">📸 Take Screenshot</button>
|
|
|
202 |
const width = parseInt(document.getElementById('width').value);
|
203 |
const height = parseInt(document.getElementById('height').value);
|
204 |
const quality = parseInt(document.getElementById('quality').value);
|
205 |
+
const fullPage = document.getElementById('fullPage').checked;
|
206 |
+
const format = document.getElementById('format').value;
|
207 |
const apiKey = document.getElementById('apiKey') ? document.getElementById('apiKey').value : '';
|
208 |
|
209 |
if (!url) {
|
|
|
234 |
const response = await fetch('/screenshot', {
|
235 |
method: 'POST',
|
236 |
headers: headers,
|
237 |
+
body: JSON.stringify({ url, width, height, quality, fullPage, format })
|
238 |
});
|
239 |
|
240 |
if (response.ok) {
|
|
|
246 |
'<h3 class="success">✅ Screenshot Success!</h3>' +
|
247 |
'<p>Size: ' + size + ' KB | Dimensions: ' + width + 'x' + height + '</p>' +
|
248 |
'<img src="' + imageUrl + '" alt="Screenshot"><br><br>' +
|
249 |
+
'<a href="' + imageUrl + '" download="screenshot.' + format + '">💾 Download Image</a>';
|
250 |
} else {
|
251 |
const error = await response.json();
|
252 |
document.getElementById('result').innerHTML =
|
|
|
265 |
|
266 |
// 截图端点
|
267 |
app.post('/screenshot', authenticate, async (req, res) => {
|
268 |
+
const { url, width = 1280, height = 720, quality = 75, fullPage = false, format = 'jpeg' } = req.body;
|
269 |
|
270 |
// 验证参数
|
271 |
if (!url) {
|
|
|
276 |
return res.status(400).json({ error: 'URL must start with http:// or https://' });
|
277 |
}
|
278 |
|
279 |
+
// 验证图片格式
|
280 |
+
if (!['jpeg', 'png'].includes(format.toLowerCase())) {
|
281 |
+
return res.status(400).json({ error: 'Format must be either "jpeg" or "png"' });
|
282 |
+
}
|
283 |
+
|
284 |
const cpuUsage = getCpuUsage();
|
285 |
if (cpuUsage > 95) {
|
286 |
return res.status(503).json({
|
|
|
353 |
timeout: 15000
|
354 |
});
|
355 |
|
356 |
+
// 配置截图选项
|
357 |
+
const screenshotOptions = {
|
358 |
+
type: format.toLowerCase(),
|
359 |
+
fullPage: Boolean(fullPage)
|
360 |
+
};
|
361 |
+
|
362 |
+
// 只有 JPEG 格式才支持 quality 参数
|
363 |
+
if (format.toLowerCase() === 'jpeg') {
|
364 |
+
screenshotOptions.quality = parseInt(quality);
|
365 |
+
}
|
366 |
+
|
367 |
+
const screenshot = await page.screenshot(screenshotOptions);
|
368 |
|
369 |
+
// 设置正确的 Content-Type
|
370 |
+
const mimeType = format.toLowerCase() === 'png' ? 'image/png' : 'image/jpeg';
|
371 |
+
res.set('Content-Type', mimeType);
|
372 |
res.send(screenshot);
|
373 |
|
374 |
} catch (error) {
|