eienmojiki commited on
Commit
84e1e28
1 Parent(s): d4cebe0

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +279 -280
server.js CHANGED
@@ -1,280 +1,279 @@
1
- const express = require("express");
2
- const cors = require("cors");
3
- const { createCanvas, registerFont } = require("canvas");
4
- const path = require("path");
5
- const fs = require("fs");
6
- const app = express();
7
-
8
- app.use(cors());
9
- app.use(express.json());
10
- app.use(express.static("public"));
11
-
12
- // Create fonts directory if it doesn't exist
13
- const fontsDir = path.join(__dirname, "fonts");
14
- if (!fs.existsSync(fontsDir)) {
15
- fs.mkdirSync(fontsDir);
16
- }
17
-
18
- // Store available fonts and their variations
19
- const availableFonts = new Map();
20
-
21
- function initializeFonts() {
22
- if (!fs.existsSync(fontsDir)) {
23
- console.log(
24
- "Created fonts directory. Please add font files (.ttf or .otf) to the fonts folder."
25
- );
26
- return;
27
- }
28
-
29
- const fontFiles = fs
30
- .readdirSync(fontsDir)
31
- .filter(
32
- (file) =>
33
- file.toLowerCase().endsWith(".ttf") ||
34
- file.toLowerCase().endsWith(".otf")
35
- );
36
-
37
- fontFiles.forEach((file) => {
38
- const fontPath = path.join(fontsDir, file);
39
- const fontName = file.replace(/\.(ttf|otf)$/i, "");
40
-
41
- // Parse font variations (Regular, Bold, Italic, etc.)
42
- let weight = "normal";
43
- let style = "normal";
44
-
45
- const lowerFontName = fontName.toLowerCase();
46
- if (lowerFontName.includes("bold")) weight = "bold";
47
- if (lowerFontName.includes("light")) weight = "light";
48
- if (lowerFontName.includes("medium")) weight = "medium";
49
- if (lowerFontName.includes("italic")) style = "italic";
50
-
51
- // Register font with canvas
52
- registerFont(fontPath, {
53
- family: fontName.split("-")[0], // Get base font name
54
- weight,
55
- style,
56
- });
57
-
58
- // Store font info
59
- const familyName = fontName.split("-")[0];
60
- if (!availableFonts.has(familyName)) {
61
- availableFonts.set(familyName, []);
62
- }
63
- availableFonts.get(familyName).push({
64
- fullName: fontName,
65
- weight,
66
- style,
67
- });
68
- });
69
-
70
- console.log("Available font families:", Array.from(availableFonts.keys()));
71
- }
72
-
73
- // Initialize fonts
74
- initializeFonts();
75
-
76
- // Store requests history
77
- let requestsHistory = [];
78
-
79
- function generateQuoteImage(ctx, canvas, data) {
80
- const {
81
- text,
82
- author,
83
- bgColor,
84
- barColor,
85
- textColor,
86
- authorColor,
87
- quoteFontFamily,
88
- quoteFontWeight,
89
- quoteFontStyle,
90
- authorFontFamily,
91
- authorFontWeight,
92
- authorFontStyle,
93
- barWidth = 4,
94
- } = data;
95
-
96
- // Constants for layout
97
- const margin = 80;
98
- const quoteMarkSize = 120;
99
- const padding = 30;
100
- const lineHeight = 50;
101
-
102
- // Clear canvas
103
- ctx.fillStyle = bgColor;
104
- ctx.fillRect(0, 0, canvas.width, canvas.height);
105
-
106
- // Draw bars
107
- ctx.fillStyle = barColor;
108
- ctx.fillRect(margin, margin, barWidth, canvas.height - margin * 2);
109
- ctx.fillRect(
110
- canvas.width - margin - barWidth,
111
- margin,
112
- barWidth,
113
- canvas.height - margin * 2
114
- );
115
-
116
- // Set up quote font
117
- ctx.fillStyle = barColor;
118
- const quoteMarkFont = [];
119
- if (quoteFontStyle === "italic") quoteMarkFont.push("italic");
120
- quoteMarkFont.push(quoteFontWeight);
121
- quoteMarkFont.push(`${quoteMarkSize}px`);
122
- quoteMarkFont.push(`"${quoteFontFamily}"`);
123
- ctx.font = quoteMarkFont.join(" ");
124
- ctx.textBaseline = "top";
125
-
126
- // Calculate quote mark metrics
127
- const quoteMarkWidth = ctx.measureText('"').width;
128
- const textStartX = margin + barWidth + padding + quoteMarkWidth + padding;
129
- const textEndX = canvas.width - margin - barWidth - padding * 2;
130
- const maxWidth = textEndX - textStartX;
131
-
132
- // Set up quote text font
133
- ctx.fillStyle = textColor;
134
- const quoteFont = [];
135
- if (quoteFontStyle === "italic") quoteFont.push("italic");
136
- quoteFont.push(quoteFontWeight);
137
- quoteFont.push("36px");
138
- quoteFont.push(`"${quoteFontFamily}"`);
139
- ctx.font = quoteFont.join(" ");
140
-
141
- // Word wrap text
142
- const words = text.split(" ");
143
- const lines = [];
144
- let currentLine = "";
145
-
146
- for (let word of words) {
147
- const testLine = currentLine + (currentLine ? " " : "") + word;
148
- const metrics = ctx.measureText(testLine);
149
-
150
- if (metrics.width > maxWidth) {
151
- if (currentLine) {
152
- lines.push(currentLine);
153
- currentLine = word;
154
- } else {
155
- currentLine = word;
156
- }
157
- } else {
158
- currentLine = testLine;
159
- }
160
- }
161
- if (currentLine) {
162
- lines.push(currentLine);
163
- }
164
-
165
- // Calculate total height of text block
166
- const totalTextHeight = lines.length * lineHeight;
167
- const authorHeight = 60; // Space reserved for author
168
- const availableHeight = canvas.height - margin * 2;
169
-
170
- // Calculate starting Y position to center text block
171
- let startY =
172
- margin + (availableHeight - (totalTextHeight + authorHeight)) / 2;
173
-
174
- // Draw quote mark at the same vertical position as first line
175
- ctx.fillStyle = barColor;
176
- ctx.font = quoteMarkFont.join(" ");
177
- ctx.fillText('"', margin + barWidth + padding, startY);
178
-
179
- // Draw quote lines
180
- ctx.fillStyle = textColor;
181
- ctx.font = quoteFont.join(" ");
182
- lines.forEach((line, index) => {
183
- ctx.fillText(line.trim(), textStartX, startY + index * lineHeight);
184
- });
185
-
186
- // Draw author below the quote
187
- ctx.fillStyle = authorColor;
188
- const authorFont = [];
189
- if (authorFontStyle === "italic") authorFont.push("italic");
190
- authorFont.push(authorFontWeight);
191
- authorFont.push("28px");
192
- authorFont.push(`"${authorFontFamily}"`);
193
- ctx.font = authorFont.join(" ");
194
-
195
- // Ensure author doesn't overflow
196
- let authorText = `- ${author}`;
197
- let authorMetrics = ctx.measureText(authorText);
198
- if (authorMetrics.width > maxWidth) {
199
- const ellipsis = "...";
200
- while (authorMetrics.width > maxWidth && author.length > 0) {
201
- author = author.slice(0, -1);
202
- authorText = `- ${author}${ellipsis}`;
203
- authorMetrics = ctx.measureText(authorText);
204
- }
205
- }
206
-
207
- // Position author text below quote with spacing
208
- const authorY = startY + totalTextHeight + 40;
209
- ctx.fillText(authorText, textStartX, authorY);
210
- }
211
-
212
- // API Endpoints
213
- app.get("/api/fonts", (req, res) => {
214
- const fontDetails = Array.from(availableFonts.entries()).map(
215
- ([family, variations]) => ({
216
- family,
217
- variations: variations.map((v) => ({
218
- weight: v.weight,
219
- style: v.style,
220
- fullName: v.fullName,
221
- })),
222
- })
223
- );
224
- res.json(fontDetails);
225
- });
226
-
227
- app.post("/api/generate-quote", (req, res) => {
228
- try {
229
- const data = req.body;
230
-
231
- // Validate fonts exist
232
- if (!availableFonts.has(data.quoteFontFamily)) {
233
- throw new Error("Selected quote font is not available");
234
- }
235
- if (!availableFonts.has(data.authorFontFamily)) {
236
- throw new Error("Selected author font is not available");
237
- }
238
-
239
- // Store request
240
- requestsHistory.unshift({
241
- timestamp: new Date(),
242
- request: data,
243
- });
244
-
245
- // Keep only last 10 requests
246
- requestsHistory = requestsHistory.slice(0, 10);
247
-
248
- // Create canvas
249
- const canvas = createCanvas(1200, 675); // 16:9 ratio
250
- const ctx = canvas.getContext("2d");
251
-
252
- // Generate quote image
253
- generateQuoteImage(ctx, canvas, data);
254
-
255
- // Send response
256
- res.json({
257
- success: true,
258
- imageUrl: canvas.toDataURL(),
259
- timestamp: new Date().toISOString(),
260
- });
261
- } catch (error) {
262
- console.error("Error generating quote:", error);
263
- res.status(500).json({
264
- success: false,
265
- error: error.message,
266
- });
267
- }
268
- });
269
-
270
- app.get("/api/requests-history", (req, res) => {
271
- res.json(requestsHistory);
272
- });
273
-
274
- // Start server
275
- const PORT = process.env.PORT || 3000;
276
- app.listen(PORT, () => {
277
- console.log(`Server running on port ${PORT}`);
278
- console.log(`View the application at http://localhost:${PORT}`);
279
- console.log("Available fonts:", Array.from(availableFonts.keys()));
280
- });
 
1
+ const express = require("express");
2
+ const cors = require("cors");
3
+ const { createCanvas, registerFont } = require("canvas");
4
+ const path = require("path");
5
+ const fs = require("fs");
6
+ const app = express();
7
+
8
+ app.use(cors());
9
+ app.use(express.json());
10
+ app.use(express.static("public"));
11
+
12
+ // Create fonts directory if it doesn't exist
13
+ const fontsDir = path.join(__dirname, "fonts");
14
+ if (!fs.existsSync(fontsDir)) {
15
+ fs.mkdirSync(fontsDir);
16
+ }
17
+
18
+ // Store available fonts and their variations
19
+ const availableFonts = new Map();
20
+
21
+ function initializeFonts() {
22
+ if (!fs.existsSync(fontsDir)) {
23
+ console.log(
24
+ "Created fonts directory. Please add font files (.ttf or .otf) to the fonts folder."
25
+ );
26
+ return;
27
+ }
28
+
29
+ const fontFiles = fs
30
+ .readdirSync(fontsDir)
31
+ .filter(
32
+ (file) =>
33
+ file.toLowerCase().endsWith(".ttf") ||
34
+ file.toLowerCase().endsWith(".otf")
35
+ );
36
+
37
+ fontFiles.forEach((file) => {
38
+ const fontPath = path.join(fontsDir, file);
39
+ const fontName = file.replace(/\.(ttf|otf)$/i, "");
40
+
41
+ // Parse font variations (Regular, Bold, Italic, etc.)
42
+ let weight = "normal";
43
+ let style = "normal";
44
+
45
+ const lowerFontName = fontName.toLowerCase();
46
+ if (lowerFontName.includes("bold")) weight = "bold";
47
+ if (lowerFontName.includes("light")) weight = "light";
48
+ if (lowerFontName.includes("medium")) weight = "medium";
49
+ if (lowerFontName.includes("italic")) style = "italic";
50
+
51
+ // Register font with canvas
52
+ registerFont(fontPath, {
53
+ family: fontName.split("-")[0], // Get base font name
54
+ weight,
55
+ style,
56
+ });
57
+
58
+ // Store font info
59
+ const familyName = fontName.split("-")[0];
60
+ if (!availableFonts.has(familyName)) {
61
+ availableFonts.set(familyName, []);
62
+ }
63
+ availableFonts.get(familyName).push({
64
+ fullName: fontName,
65
+ weight,
66
+ style,
67
+ });
68
+ });
69
+
70
+ console.log("Available font families:", Array.from(availableFonts.keys()));
71
+ }
72
+
73
+ // Initialize fonts
74
+ initializeFonts();
75
+
76
+ // Store requests history
77
+ let requestsHistory = [];
78
+
79
+ function generateQuoteImage(ctx, canvas, data) {
80
+ const {
81
+ text,
82
+ author,
83
+ bgColor,
84
+ barColor,
85
+ textColor,
86
+ authorColor,
87
+ quoteFontFamily,
88
+ quoteFontWeight,
89
+ quoteFontStyle,
90
+ authorFontFamily,
91
+ authorFontWeight,
92
+ authorFontStyle,
93
+ barWidth = 4,
94
+ } = data;
95
+
96
+ // Constants for layout
97
+ const margin = 80;
98
+ const quoteMarkSize = 120;
99
+ const padding = 30;
100
+ const lineHeight = 50;
101
+
102
+ // Clear canvas
103
+ ctx.fillStyle = bgColor;
104
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
105
+
106
+ // Draw bars
107
+ ctx.fillStyle = barColor;
108
+ ctx.fillRect(margin, margin, barWidth, canvas.height - margin * 2);
109
+ ctx.fillRect(
110
+ canvas.width - margin - barWidth,
111
+ margin,
112
+ barWidth,
113
+ canvas.height - margin * 2
114
+ );
115
+
116
+ // Set up quote font
117
+ ctx.fillStyle = barColor;
118
+ const quoteMarkFont = [];
119
+ if (quoteFontStyle === "italic") quoteMarkFont.push("italic");
120
+ quoteMarkFont.push(quoteFontWeight);
121
+ quoteMarkFont.push(`${quoteMarkSize}px`);
122
+ quoteMarkFont.push(`"${quoteFontFamily}"`);
123
+ ctx.font = quoteMarkFont.join(" ");
124
+ ctx.textBaseline = "top";
125
+
126
+ // Calculate quote mark metrics
127
+ const quoteMarkWidth = ctx.measureText('"').width;
128
+ const textStartX = margin + barWidth + padding + quoteMarkWidth + padding;
129
+ const textEndX = canvas.width - margin - barWidth - padding * 2;
130
+ const maxWidth = textEndX - textStartX;
131
+
132
+ // Set up quote text font
133
+ ctx.fillStyle = textColor;
134
+ const quoteFont = [];
135
+ if (quoteFontStyle === "italic") quoteFont.push("italic");
136
+ quoteFont.push(quoteFontWeight);
137
+ quoteFont.push("36px");
138
+ quoteFont.push(`"${quoteFontFamily}"`);
139
+ ctx.font = quoteFont.join(" ");
140
+
141
+ // Word wrap text
142
+ const words = text.split(" ");
143
+ const lines = [];
144
+ let currentLine = "";
145
+
146
+ for (let word of words) {
147
+ const testLine = currentLine + (currentLine ? " " : "") + word;
148
+ const metrics = ctx.measureText(testLine);
149
+
150
+ if (metrics.width > maxWidth) {
151
+ if (currentLine) {
152
+ lines.push(currentLine);
153
+ currentLine = word;
154
+ } else {
155
+ currentLine = word;
156
+ }
157
+ } else {
158
+ currentLine = testLine;
159
+ }
160
+ }
161
+ if (currentLine) {
162
+ lines.push(currentLine);
163
+ }
164
+
165
+ // Calculate total height of text block
166
+ const totalTextHeight = lines.length * lineHeight;
167
+ const authorHeight = 60; // Space reserved for author
168
+ const availableHeight = canvas.height - margin * 2;
169
+
170
+ // Calculate starting Y position to center text block
171
+ let startY =
172
+ margin + (availableHeight - (totalTextHeight + authorHeight)) / 2;
173
+
174
+ // Draw quote mark at the same vertical position as first line
175
+ ctx.fillStyle = barColor;
176
+ ctx.font = quoteMarkFont.join(" ");
177
+ ctx.fillText('"', margin + barWidth + padding, startY);
178
+
179
+ // Draw quote lines
180
+ ctx.fillStyle = textColor;
181
+ ctx.font = quoteFont.join(" ");
182
+ lines.forEach((line, index) => {
183
+ ctx.fillText(line.trim(), textStartX, startY + index * lineHeight);
184
+ });
185
+
186
+ // Draw author below the quote
187
+ ctx.fillStyle = authorColor;
188
+ const authorFont = [];
189
+ if (authorFontStyle === "italic") authorFont.push("italic");
190
+ authorFont.push(authorFontWeight);
191
+ authorFont.push("28px");
192
+ authorFont.push(`"${authorFontFamily}"`);
193
+ ctx.font = authorFont.join(" ");
194
+
195
+ // Ensure author doesn't overflow
196
+ let authorText = `- ${author}`;
197
+ let authorMetrics = ctx.measureText(authorText);
198
+ if (authorMetrics.width > maxWidth) {
199
+ const ellipsis = "...";
200
+ while (authorMetrics.width > maxWidth && author.length > 0) {
201
+ author = author.slice(0, -1);
202
+ authorText = `- ${author}${ellipsis}`;
203
+ authorMetrics = ctx.measureText(authorText);
204
+ }
205
+ }
206
+
207
+ // Position author text below quote with spacing
208
+ const authorY = startY + totalTextHeight + 40;
209
+ ctx.fillText(authorText, textStartX, authorY);
210
+ }
211
+
212
+ // API Endpoints
213
+ app.get("/api/fonts", (req, res) => {
214
+ const fontDetails = Array.from(availableFonts.entries()).map(
215
+ ([family, variations]) => ({
216
+ family,
217
+ variations: variations.map((v) => ({
218
+ weight: v.weight,
219
+ style: v.style,
220
+ fullName: v.fullName,
221
+ })),
222
+ })
223
+ );
224
+ res.json(fontDetails);
225
+ });
226
+
227
+ app.post("/api/generate-quote", (req, res) => {
228
+ try {
229
+ const data = req.body;
230
+
231
+ // Validate fonts exist
232
+ if (!availableFonts.has(data.quoteFontFamily)) {
233
+ throw new Error("Selected quote font is not available");
234
+ }
235
+ if (!availableFonts.has(data.authorFontFamily)) {
236
+ throw new Error("Selected author font is not available");
237
+ }
238
+
239
+ // Store request
240
+ requestsHistory.unshift({
241
+ timestamp: new Date(),
242
+ request: data,
243
+ });
244
+
245
+ // Keep only last 10 requests
246
+ requestsHistory = requestsHistory.slice(0, 10);
247
+
248
+ // Create canvas
249
+ const canvas = createCanvas(1200, 675); // 16:9 ratio
250
+ const ctx = canvas.getContext("2d");
251
+
252
+ // Generate quote image
253
+ generateQuoteImage(ctx, canvas, data);
254
+
255
+ // Send response
256
+ res.json({
257
+ success: true,
258
+ imageUrl: canvas.toDataURL(),
259
+ timestamp: new Date().toISOString(),
260
+ });
261
+ } catch (error) {
262
+ console.error("Error generating quote:", error);
263
+ res.status(500).json({
264
+ success: false,
265
+ error: error.message,
266
+ });
267
+ }
268
+ });
269
+
270
+ app.get("/api/requests-history", (req, res) => {
271
+ res.json(requestsHistory);
272
+ });
273
+
274
+ // Start server
275
+ const PORT = process.env.PORT || 7860;
276
+ app.listen(PORT, () => {
277
+ console.log(`Server running on port ${PORT}`);
278
+ console.log(`View the application at http://localhost:${PORT}`);
279
+ });