AyGemuy commited on
Commit
34a0297
·
0 Parent(s):

Taylor-V2

Browse files
Files changed (14) hide show
  1. .gitattributes +35 -0
  2. Dockerfile +31 -0
  3. Indie-Flower.ttf +0 -0
  4. ObelixProBIt-cyr.ttf +0 -0
  5. README.md +12 -0
  6. Zahraaa.ttf +0 -0
  7. app.js +2155 -0
  8. favicon.ico +0 -0
  9. foliokanan.jpg +0 -0
  10. foliokiri.jpg +0 -0
  11. magernulis1.jpg +0 -0
  12. package.json +37 -0
  13. sebelumkanan.jpg +0 -0
  14. sebelumkiri.jpg +0 -0
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM mcr.microsoft.com/playwright:focal
2
+
3
+ # Set environment variable untuk menghindari dialog pada Playwright
4
+ ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD 1
5
+
6
+ # Tentukan work directory
7
+ WORKDIR /app
8
+
9
+ # Copy file package.json dan package-lock.json
10
+ COPY package*.json ./
11
+
12
+ # Install dependencies
13
+ RUN npm install
14
+
15
+ # Install ImageMagick dan FFmpeg
16
+ RUN apt-get update && apt-get install -y \
17
+ imagemagick \
18
+ ffmpeg \
19
+ && rm -rf /var/lib/apt/lists/*
20
+
21
+ # Copy semua file ke container
22
+ COPY . .
23
+
24
+ # Install Playwright dependencies dan browser binaries
25
+ RUN npx playwright install --with-deps
26
+
27
+ # Expose port untuk aplikasi
28
+ EXPOSE 7860
29
+
30
+ # Start aplikasi
31
+ CMD ["npm", "start"]
Indie-Flower.ttf ADDED
Binary file (55.3 kB). View file
 
ObelixProBIt-cyr.ttf ADDED
Binary file (22.4 kB). View file
 
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Nulis
3
+ emoji: 📚
4
+ colorFrom: green
5
+ colorTo: green
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ short_description: Nulis Image
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
Zahraaa.ttf ADDED
Binary file (86.1 kB). View file
 
app.js ADDED
@@ -0,0 +1,2155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ import { chromium } from 'playwright';
3
+ import cors from 'cors';
4
+ import dotenv from 'dotenv';
5
+ import os from 'os';
6
+ import axios from 'axios';
7
+ import fetch from 'node-fetch';
8
+ import sharp from 'sharp';
9
+ import { spawn } from 'child_process';
10
+ import path from 'path';
11
+
12
+ import EventEmitter from 'events';
13
+ import WebSocket from 'ws';
14
+
15
+ import pkg from 'axios-cookiejar-support';
16
+ const { wrapper } = pkg;
17
+
18
+ import { CookieJar } from 'tough-cookie';
19
+ import * as cheerio from 'cheerio';
20
+ import TurndownService from 'turndown';
21
+ import { Readable } from 'stream';
22
+
23
+ dotenv.config();
24
+
25
+ const config = {
26
+ maxTextLength: 100,
27
+ viewport: { width: 1920, height: 1080 },
28
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
29
+ };
30
+
31
+ let browser, page;
32
+
33
+ const utils = {
34
+ async initialize() {
35
+ if (!browser) {
36
+ browser = await chromium.launch({ headless: true });
37
+ const context = await browser.newContext({
38
+ viewport: config.viewport,
39
+ userAgent: config.userAgent
40
+ });
41
+
42
+ await context.route('**/*', (route) => {
43
+ const url = route.request().url();
44
+ if (url.endsWith('.png') || url.endsWith('.jpg') || url.includes('google-analytics')) {
45
+ return route.abort();
46
+ }
47
+ route.continue();
48
+ });
49
+
50
+ page = await context.newPage();
51
+ await page.goto('https://www.bratgenerator.com/', { waitUntil: 'domcontentloaded', timeout: 10000 });
52
+
53
+ try {
54
+ await page.click('#onetrust-accept-btn-handler', { timeout: 2000 });
55
+ } catch { }
56
+
57
+ await page.evaluate(() => setupTheme('white'));
58
+ }
59
+ },
60
+
61
+ async generateBrat(text) {
62
+ await page.fill('#textInput', text);
63
+ const overlay = page.locator('#textOverlay');
64
+ return overlay.screenshot({ timeout: 3000 });
65
+ },
66
+
67
+ async close() {
68
+ if (browser) await browser.close();
69
+ }
70
+ };
71
+
72
+ const app = express();
73
+ app.use(express.json());
74
+ app.use(cors());
75
+
76
+ app.get('/', (req, res) => {
77
+ res.send('<h1>Welcome to the Web Scraping API</h1>');
78
+ });
79
+
80
+ app.get('/brat', async (req, res) => {
81
+ try {
82
+ const { text: q } = req.query;
83
+ if (!q) {
84
+ return res.json({
85
+ name: 'HD Bart Generator API',
86
+ message: 'Parameter text di perlukan',
87
+ version: '2.1.0',
88
+ runtime: {
89
+ os: os.type(),
90
+ platform: os.platform(),
91
+ architecture: os.arch(),
92
+ cpuCount: os.cpus().length,
93
+ uptime: `${os.uptime()} seconds`,
94
+ memoryUsage: `${Math.round((os.totalmem() - os.freemem()) / 1024 / 1024)} MB used of ${Math.round(os.totalmem() / 1024 / 1024)} MB`
95
+ }
96
+ });
97
+ }
98
+ const imageBuffer = await utils.generateBrat(q);
99
+ res.set('Content-Type', 'image/png');
100
+ res.send(imageBuffer);
101
+ } catch (error) {
102
+ console.error(error);
103
+ res.status(500).json({
104
+ status: false,
105
+ message: 'Error generating image',
106
+ error: process.env.NODE_ENV === 'development' ? error.message : undefined
107
+ });
108
+ }
109
+ });
110
+
111
+ app.get('/screenshot', async (req, res) => {
112
+ const { url } = req.query;
113
+
114
+ if (!url) {
115
+ return res.status(400).send('URL is required');
116
+ }
117
+
118
+ try {
119
+ const browser = await chromium.launch();
120
+ const page = await browser.newPage();
121
+ await page.goto(url);
122
+
123
+ const screenshotBuffer = await page.screenshot();
124
+ await browser.close();
125
+
126
+ res.type('image/png').send(screenshotBuffer);
127
+ } catch (error) {
128
+ res.status(500).send('Internal Server Error');
129
+ }
130
+ });
131
+
132
+
133
+ function generateRandomString(length) {
134
+ const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
135
+ let result = '';
136
+ for (let i = 0; i < length; i++) {
137
+ result += characters.charAt(Math.floor(Math.random() * characters.length));
138
+ }
139
+ return result;
140
+ }
141
+
142
+ class MicrosoftBingAutoLogin {
143
+ constructor(bing_account, bing_password) {
144
+ console.log('Initializing auto login for Microsoft Bing ...');
145
+ this.bing_account = bing_account;
146
+ this.bing_password = bing_password;
147
+ this.init();
148
+ }
149
+
150
+ async init() {
151
+ this.browser = await chromium.launch(); // Launch browser with Playwright
152
+ }
153
+
154
+ /** Login to Microsoft Bing */
155
+ async login() {
156
+ const sig = generateRandomString(32);
157
+ const CSRFToken = generateRandomString(8) + '-' + generateRandomString(4) + '-' + generateRandomString(4) + '-' + generateRandomString(4) + '-' + generateRandomString(12);
158
+ const loginUrl = `https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&id=264960&wreply=https%3a%2f%2fwww.bing.com%2fsecure%2fPassport.aspx%3fedge_suppress_profile_switch%3d1%26requrl%3dhttps%253a%252f%252fwww.bing.com%252fsearch%253ftoWww%253d1%2526redig%253d9220EACAFFCA40508E4E7BD52023921B%2526q%253dBing%252bAI%2526showconv%253d1%2526wlexpsignin%253d1%26sig=${sig}&wp=MBI_SSL&lc=1028&CSRFToken=${CSRFToken}&aadredir=1`;
159
+
160
+ // Open Microsoft Bing login page
161
+ const page = await this.browser.newPage();
162
+ await page.goto(loginUrl);
163
+
164
+ // Enter the Bing account and password
165
+ const accountInput = await page.$('input[name="loginfmt"]');
166
+ await accountInput.type(this.bing_account);
167
+ const passwordInput = await page.$('input[name="passwd"]');
168
+ await passwordInput.type(this.bing_password);
169
+
170
+ // Submit login form
171
+ const submitButton = await page.$('input[type="submit"]');
172
+ await submitButton.click();
173
+
174
+ // Wait for login to complete (you can adjust the wait time or use a more sophisticated wait)
175
+ await page.waitForNavigation();
176
+ }
177
+
178
+ async getCookies() {
179
+ const page = await this.browser.newPage();
180
+ await page.goto('https://bing.com/chat'); // Navigate to Bing Chat to get the cookies
181
+ const cookies = await page.cookies();
182
+ return cookies;
183
+ }
184
+ }
185
+
186
+ // Create the API route for login
187
+ app.get('/login', async (req, res) => {
188
+ const { user, pass } = req.query;
189
+
190
+ if (!user || !pass) {
191
+ return res.status(400).send('Missing username or password.');
192
+ }
193
+
194
+ try {
195
+ const bingLogin = new MicrosoftBingAutoLogin(user, pass);
196
+ await bingLogin.login(); // Perform login
197
+ const cookies = await bingLogin.getCookies(); // Get cookies after login
198
+ res.json(cookies); // Send cookies as response
199
+ } catch (error) {
200
+ res.status(500).send('Error during login: ' + error.message);
201
+ }
202
+ });
203
+
204
+ app.get('/cookie', async (req, res) => {
205
+ const { url } = req.query;
206
+
207
+ if (!url) {
208
+ return res.status(400).send('URL is required');
209
+ }
210
+
211
+ try {
212
+ const browser = await chromium.launch();
213
+ const page = await browser.newPage();
214
+ await page.goto(url);
215
+ const cookies = await page.context().cookies();
216
+ await browser.close();
217
+ res.json(cookies);
218
+ } catch (error) {
219
+ res.status(500).send('Internal Server Error');
220
+ }
221
+ });
222
+
223
+
224
+ // const { chromium } = require('playwright'); // Pastikan Anda sudah mengimpor Playwright
225
+
226
+ app.get('/cookie/v2', async (req, res) => {
227
+ const { url } = req.query;
228
+
229
+ if (!url) {
230
+ return res.status(400).send('URL is required');
231
+ }
232
+
233
+ try {
234
+ const browser = await chromium.launch();
235
+ const page = await browser.newPage();
236
+ await page.goto(url);
237
+
238
+ // Mengambil cookies
239
+ const cookies = await page.context().cookies();
240
+
241
+ // Mengambil headers
242
+ const response = await page.waitForResponse(url);
243
+ const headers = response.headers();
244
+
245
+ await browser.close();
246
+
247
+ // Menggabungkan cookies dan headers dalam satu objek
248
+ res.json({ cookies, headers });
249
+ } catch (error) {
250
+ console.error(error); // Menambahkan log untuk debugging
251
+ res.status(500).send('Internal Server Error');
252
+ }
253
+ });
254
+
255
+ app.get('/welcome', async (req, res) => {
256
+ const { name, info, desc } = req.query;
257
+
258
+ // Ensure all required query parameters are present
259
+ if (!name || !info) {
260
+ return res.status(400).json({ error: 'Missing required parameters' });
261
+ }
262
+
263
+ // Construct HTML content dynamically based on query parameters
264
+ const html = `
265
+ <!DOCTYPE html>
266
+ <html lang="en" >
267
+ <head>
268
+ <meta charset="UTF-8">
269
+ <title>Course Card UI Design - #094 of #100Days100Projects</title>
270
+ <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css'>
271
+ <style>
272
+ @import url('https://fonts.googleapis.com/css?family=Muli&display=swap');
273
+
274
+ * {
275
+ box-sizing: border-box;
276
+ }
277
+
278
+
279
+ body {
280
+ background-image: linear-gradient(45deg, #7175da, #9790F2);
281
+ font-family: 'Muli', sans-serif;
282
+ display: flex;
283
+ align-items: center;
284
+ justify-content: center;
285
+ flex-direction: column;
286
+ min-height: 100vh;
287
+ margin: 0;
288
+ }
289
+
290
+ .courses-container {
291
+
292
+ }
293
+
294
+ .course {
295
+ background-color: #fff;
296
+ border-radius: 10px;
297
+ box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2);
298
+ display: flex;
299
+ max-width: 100%;
300
+ margin: 20px;
301
+ overflow: hidden;
302
+ width: 700px;
303
+ }
304
+
305
+ .course h6 {
306
+ opacity: 0.6;
307
+ margin: 0;
308
+ letter-spacing: 1px;
309
+ text-transform: uppercase;
310
+ }
311
+
312
+ .course h2 {
313
+ letter-spacing: 1px;
314
+ margin: 10px 0;
315
+ }
316
+
317
+ .course-preview {
318
+ background-color: #2A265F;
319
+ color: #fff;
320
+ padding: 30px;
321
+ max-width: 250px;
322
+ }
323
+
324
+ .course-preview a {
325
+ color: #fff;
326
+ display: inline-block;
327
+ font-size: 12px;
328
+ opacity: 0.6;
329
+ margin-top: 30px;
330
+ text-decoration: none;
331
+ }
332
+
333
+ .course-info {
334
+ padding: 30px;
335
+ position: relative;
336
+ width: 100%;
337
+ }
338
+
339
+ .progress-container {
340
+ position: absolute;
341
+ top: 30px;
342
+ right: 30px;
343
+ text-align: right;
344
+ width: 150px;
345
+ }
346
+
347
+ .progress {
348
+ background-color: #ddd;
349
+ border-radius: 3px;
350
+ height: 5px;
351
+ width: 100%;
352
+ }
353
+
354
+ .progress::after {
355
+ border-radius: 3px;
356
+ background-color: #2A265F;
357
+ content: '';
358
+ position: absolute;
359
+ top: 0;
360
+ left: 0;
361
+ height: 5px;
362
+ width: 66%;
363
+ }
364
+
365
+ .progress-text {
366
+ font-size: 10px;
367
+ opacity: 0.6;
368
+ letter-spacing: 1px;
369
+ }
370
+
371
+ .btn {
372
+ background-color: #2A265F;
373
+ border: 0;
374
+ border-radius: 50px;
375
+ box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2);
376
+ color: #fff;
377
+ font-size: 16px;
378
+ padding: 12px 25px;
379
+ position: absolute;
380
+ bottom: 30px;
381
+ right: 30px;
382
+ letter-spacing: 1px;
383
+ }
384
+
385
+ /* SOCIAL PANEL CSS */
386
+ .social-panel-container {
387
+ position: fixed;
388
+ right: 0;
389
+ bottom: 80px;
390
+ transform: translateX(100%);
391
+ transition: transform 0.4s ease-in-out;
392
+ }
393
+
394
+ .social-panel-container.visible {
395
+ transform: translateX(-10px);
396
+ }
397
+
398
+ .social-panel {
399
+ background-color: #fff;
400
+ border-radius: 16px;
401
+ box-shadow: 0 16px 31px -17px rgba(0,31,97,0.6);
402
+ border: 5px solid #001F61;
403
+ display: flex;
404
+ flex-direction: column;
405
+ justify-content: center;
406
+ align-items: center;
407
+ font-family: 'Muli';
408
+ position: relative;
409
+ height: 169px;
410
+ width: 370px;
411
+ max-width: calc(100% - 10px);
412
+ }
413
+
414
+ .social-panel button.close-btn {
415
+ border: 0;
416
+ color: #97A5CE;
417
+ cursor: pointer;
418
+ font-size: 20px;
419
+ position: absolute;
420
+ top: 5px;
421
+ right: 5px;
422
+ }
423
+
424
+ .social-panel button.close-btn:focus {
425
+ outline: none;
426
+ }
427
+
428
+ .social-panel p {
429
+ background-color: #001F61;
430
+ border-radius: 0 0 10px 10px;
431
+ color: #fff;
432
+ font-size: 14px;
433
+ line-height: 18px;
434
+ padding: 2px 17px 6px;
435
+ position: absolute;
436
+ top: 0;
437
+ left: 50%;
438
+ margin: 0;
439
+ transform: translateX(-50%);
440
+ text-align: center;
441
+ width: 235px;
442
+ }
443
+
444
+ .social-panel p i {
445
+ margin: 0 5px;
446
+ }
447
+
448
+ .social-panel p a {
449
+ color: #FF7500;
450
+ text-decoration: none;
451
+ }
452
+
453
+ .social-panel h4 {
454
+ margin: 20px 0;
455
+ color: #97A5CE;
456
+ font-family: 'Muli';
457
+ font-size: 14px;
458
+ line-height: 18px;
459
+ text-transform: uppercase;
460
+ }
461
+
462
+ .social-panel ul {
463
+ display: flex;
464
+ list-style-type: none;
465
+ padding: 0;
466
+ margin: 0;
467
+ }
468
+
469
+ .social-panel ul li {
470
+ margin: 0 10px;
471
+ }
472
+
473
+ .social-panel ul li a {
474
+ border: 1px solid #DCE1F2;
475
+ border-radius: 50%;
476
+ color: #001F61;
477
+ font-size: 20px;
478
+ display: flex;
479
+ justify-content: center;
480
+ align-items: center;
481
+ height: 50px;
482
+ width: 50px;
483
+ text-decoration: none;
484
+ }
485
+
486
+ .social-panel ul li a:hover {
487
+ border-color: #FF6A00;
488
+ box-shadow: 0 9px 12px -9px #FF6A00;
489
+ }
490
+
491
+ .floating-btn {
492
+ border-radius: 26.5px;
493
+ background-color: #001F61;
494
+ border: 1px solid #001F61;
495
+ box-shadow: 0 16px 22px -17px #03153B;
496
+ color: #fff;
497
+ cursor: pointer;
498
+ font-size: 16px;
499
+ line-height: 20px;
500
+ padding: 12px 20px;
501
+ position: fixed;
502
+ bottom: 20px;
503
+ right: 20px;
504
+ z-index: 999;
505
+ }
506
+
507
+ .floating-btn:hover {
508
+ background-color: #ffffff;
509
+ color: #001F61;
510
+ }
511
+
512
+ .floating-btn:focus {
513
+ outline: none;
514
+ }
515
+
516
+ .floating-text {
517
+ background-color: #001F61;
518
+ border-radius: 10px 10px 0 0;
519
+ color: #fff;
520
+ font-family: 'Muli';
521
+ padding: 7px 15px;
522
+ position: fixed;
523
+ bottom: 0;
524
+ left: 50%;
525
+ transform: translateX(-50%);
526
+ text-align: center;
527
+ z-index: 998;
528
+ }
529
+
530
+ .floating-text a {
531
+ color: #FF7500;
532
+ text-decoration: none;
533
+ }
534
+
535
+ @media screen and (max-width: 480px) {
536
+
537
+ .social-panel-container.visible {
538
+ transform: translateX(0px);
539
+ }
540
+
541
+ .floating-btn {
542
+ right: 10px;
543
+ }
544
+ }
545
+ </style>
546
+
547
+ </head>
548
+ <body>
549
+ <!-- partial:index.partial.html -->
550
+ <div class="courses-container">
551
+ <div class="course">
552
+ <div class="course-preview">
553
+ <h6>Course</h6>
554
+ <h2>${name}</h2>
555
+ <a href="#">View all chapters <i class="fas fa-chevron-right"></i></a>
556
+ </div>
557
+ <div class="course-info">
558
+ <div class="progress-container">
559
+ <div class="progress"></div>
560
+ <span class="progress-text">
561
+ 6/9 Challenges
562
+ </span>
563
+ </div>
564
+ <h6>${info}</h6>
565
+ <h2>${desc}</h2>
566
+ <button class="btn">Continue</button>
567
+ </div>
568
+ </div>
569
+ </div>
570
+
571
+ <!-- SOCIAL PANEL HTML -->
572
+ <div class="social-panel-container">
573
+ <div class="social-panel">
574
+ <p>Created with <i class="fa fa-heart"></i> by
575
+ <a target="_blank" href="https://florin-pop.com">Florin Pop</a></p>
576
+ <button class="close-btn"><i class="fas fa-times"></i></button>
577
+ <h4>Get in touch on</h4>
578
+ <ul>
579
+ <li>
580
+ <a href="https://www.patreon.com/florinpop17" target="_blank">
581
+ <i class="fab fa-discord"></i>
582
+ </a>
583
+ </li>
584
+ <li>
585
+ <a href="https://twitter.com/florinpop1705" target="_blank">
586
+ <i class="fab fa-twitter"></i>
587
+ </a>
588
+ </li>
589
+ <li>
590
+ <a href="https://linkedin.com/in/florinpop17" target="_blank">
591
+ <i class="fab fa-linkedin"></i>
592
+ </a>
593
+ </li>
594
+ <li>
595
+ <a href="https://facebook.com/florinpop17" target="_blank">
596
+ <i class="fab fa-facebook"></i>
597
+ </a>
598
+ </li>
599
+ <li>
600
+ <a href="https://instagram.com/florinpop17" target="_blank">
601
+ <i class="fab fa-instagram"></i>
602
+ </a>
603
+ </li>
604
+ </ul>
605
+ </div>
606
+ </div>
607
+ <button class="floating-btn">
608
+ Get in Touch
609
+ </button>
610
+
611
+ <div class="floating-text">
612
+ Part of <a href="https://florin-pop.com/blog/2019/09/100-days-100-projects" target="_blank">#100Days100Projects</a>
613
+ </div>
614
+ <!-- partial -->
615
+ <script>
616
+ // INSERT JS HERE
617
+
618
+
619
+ // SOCIAL PANEL JS
620
+ const floating_btn = document.querySelector('.floating-btn');
621
+ const close_btn = document.querySelector('.close-btn');
622
+ const social_panel_container = document.querySelector('.social-panel-container');
623
+
624
+ floating_btn.addEventListener('click', () => {
625
+ social_panel_container.classList.toggle('visible')
626
+ });
627
+
628
+ close_btn.addEventListener('click', () => {
629
+ social_panel_container.classList.remove('visible')
630
+ });
631
+ </script>
632
+
633
+ </body>
634
+ </html>`;
635
+
636
+ try {
637
+ const browser = await chromium.launch(); // Launch Playwright Chromium browser
638
+ const page = await browser.newPage();
639
+ await page.setContent(html);
640
+ const buffer = await page.screenshot({ type: 'png' });
641
+ await browser.close();
642
+
643
+ res.set('Content-Type', 'image/png');
644
+ return res.send(buffer);
645
+ } catch (error) {
646
+ console.error('Error generating PNG:', error);
647
+ res.status(500).json({ error: 'Failed to convert HTML to PNG' });
648
+ }
649
+ });
650
+
651
+ app.get('/youtube-videos', async (req, res) => {
652
+ const channelName = req.query.name || 'YasoobKhalid'; // Default to 'YasoobKhalid' if no name is provided
653
+ const url = `https://www.youtube.com/@${channelName}/videos`;
654
+
655
+ const browser = await chromium.launch({ headless: true });
656
+ const page = await browser.newPage();
657
+ await page.goto(url);
658
+
659
+ const channelTitle = "Title" || await page.locator('yt-formatted-string[class*="ytd-channel-name"]').textContent();
660
+ const handle = await page.locator('yt-formatted-string#channel-handle').textContent();
661
+ const subscriberCount = await page.locator('yt-formatted-string#subscriber-count').textContent();
662
+
663
+ let lastHeight = await page.evaluate(() => {
664
+ return document.documentElement.scrollHeight;
665
+ });
666
+
667
+ const WAIT_IN_SECONDS = 5;
668
+ while (true) {
669
+ await page.evaluate('window.scrollTo(0, document.documentElement.scrollHeight)');
670
+ await page.waitForTimeout(WAIT_IN_SECONDS * 1000); // convert seconds to milliseconds
671
+
672
+ const newHeight = await page.evaluate(() => {
673
+ return document.documentElement.scrollHeight;
674
+ });
675
+
676
+ if (newHeight === lastHeight) {
677
+ break;
678
+ }
679
+
680
+ lastHeight = newHeight;
681
+ }
682
+
683
+ const videoData = await page.evaluate(() => {
684
+ const thumbnails = Array.from(document.querySelectorAll('a#thumbnail yt-image img'));
685
+ const views = Array.from(document.querySelectorAll('div#metadata-line span:nth-child(1)'));
686
+ const titles = Array.from(document.querySelectorAll('#video-title'));
687
+ const links = Array.from(document.querySelectorAll('#video-title-link'));
688
+
689
+ return titles.map((title, index) => ({
690
+ title: title.textContent.trim(),
691
+ views: views[index]?.textContent.trim(),
692
+ thumbnail: thumbnails[index]?.src,
693
+ link: links[index]?.href,
694
+ }));
695
+ });
696
+
697
+ await browser.close();
698
+
699
+ res.json({
700
+ channelTitle,
701
+ handle,
702
+ subscriberCount,
703
+ videos: videoData,
704
+ });
705
+ });
706
+
707
+ // Define regex patterns
708
+ const Patterns = {
709
+ channel: {
710
+ name: /channelMetadataRenderer\":{\"title\":\"(.*?)\"/,
711
+ id: /channelId\":\"(.*?)\"/,
712
+ verified: /"label":"Verified"/,
713
+ check_live: /{"text":"LIVE"}/,
714
+ live: /thumbnailOverlays\":\[(.*?)]/,
715
+ video_id: /videoId\":\"(.*?)\"/,
716
+ uploads: /gridVideoRenderer\":{\"videoId\":\"(.*?)\"/,
717
+ subscribers: /\"subscriberCountText\":{\"accessibility\":(.*?),/,
718
+ views: /viewCountText\":{\"simpleText\":\"(.*?)\"}/,
719
+ creation: /{\"text\":\"Joined \"},{\"text\":\"(.*?)\"}/,
720
+ country: /country\":{\"simpleText\":\"(.*?)\"}/,
721
+ custom_url: /canonicalChannelUrl\":\"(.*?)\"/,
722
+ description: /{\"description\":{\"simpleText\":\"(.*?)\"}/,
723
+ avatar: /height\":88},{\"url\":\"(.*?)\"/,
724
+ banner: /width\":1280,\"height\":351},{\"url\":\"(.*?)\"/,
725
+ playlists: /{\"url\":\"\/playlist\?list=(.*?)\"/,
726
+ video_count: /videoCountText\":{\"runs\":\[{\"text\":(.*?)}\]/,
727
+ socials: /q=https%3A%2F%2F(.*?)\"/,
728
+ upload_ids: /videoId\":\"(.*?)\"/,
729
+ stream_ids: /videoId\":\"(.*?)\"/,
730
+ upload_chunk: /gridVideoRenderer\":{(.*?)\"navigationEndpoint/,
731
+ upload_chunk_fl_1: /simpleText\":\"Streamed/,
732
+ upload_chunk_fl_2: /default_live./,
733
+ upcoming_check: /\"title\":\"Upcoming live streams\"/,
734
+ upcoming: /gridVideoRenderer\":{\"videoId\":\"(.*?)\"/,
735
+ },
736
+ video: {
737
+ video_id: /videoId\":\"(.*?)\"/,
738
+ title: /title\":\"(.*?)\"/,
739
+ duration: /approxDurationMs\":\"(.*?)\"/,
740
+ upload_date: /uploadDate\":\"(.*?)\"/,
741
+ author_id: /channelIds\":\[\"(.*?)\"/,
742
+ description: /shortDescription\":\"(.*)\",\"isCrawlable/,
743
+ tags: /<meta name=\"keywords\" content=\"(.*?)\">/,
744
+ is_streamed: /simpleText\":\"Streamed live/,
745
+ is_premiered: /dateText\":{\"simpleText\":\"Premiered/,
746
+ views: /videoViewCountRenderer\":{\"viewCount\":{\"simpleText\":\"(.*?)\"/,
747
+ likes: /toggledText\":{\"accessibility\":{\"accessibilityData\":{\"label\":\"(.*?) /,
748
+ thumbnail: /playerMicroformatRenderer\":{\"thumbnail\":{\"thumbnails\":\[{\"url\":\"(.*?)\"/,
749
+ },
750
+ playlist: {
751
+ name: /{\"title\":\"(.*?)\"/,
752
+ video_count: /stats\":\[{\"runs\":\[{\"text\":\"(.*?)\"/,
753
+ video_id: /videoId\":\"(.*?)\"/,
754
+ thumbnail: /og:image\" content=\"(.*?)\?"/,
755
+ },
756
+ extra: {
757
+ video_id: /videoId\":\"(.*?)\"/,
758
+ },
759
+ query: {
760
+ channel_id: /channelId\":\"(.*?)\"/,
761
+ video_id: /videoId\":\"(.*?)\"/,
762
+ playlist_id: /playlistId\":\"(.*?)\"/,
763
+ },
764
+ };
765
+
766
+ // Utility function to match patterns
767
+ const matchPattern = (pattern, data) => {
768
+ const matches = [];
769
+ let match;
770
+ while ((match = pattern.exec(data)) !== null) {
771
+ matches.push(match[1] || match[0]);
772
+ }
773
+ return matches;
774
+ };
775
+
776
+ // Fetch YouTube channel data by name
777
+ const fetchChannelData = async (channelName) => {
778
+ try {
779
+ const url = `https://www.youtube.com/@${channelName}/videos`;
780
+ const response = await axios.get(url);
781
+ return response.data; // return raw HTML content for pattern matching
782
+ } catch (error) {
783
+ throw new Error('Error fetching YouTube channel data: ' + error.message);
784
+ }
785
+ };
786
+
787
+ // API Endpoint
788
+ app.get('/youtube-info', async (req, res) => {
789
+ const { name } = req.query; // Get channel name from query parameter
790
+
791
+ if (!name) {
792
+ return res.status(400).json({ error: 'Channel name is required' });
793
+ }
794
+
795
+ try {
796
+ const data = await fetchChannelData(name); // Fetch the page content from YouTube
797
+ const results = {};
798
+
799
+ // Apply patterns for channel data extraction
800
+ Object.keys(Patterns.channel).forEach((key) => {
801
+ const pattern = Patterns.channel[key];
802
+ results[key] = matchPattern(pattern, data);
803
+ });
804
+
805
+ res.json({ channelName: name, data: results });
806
+ } catch (error) {
807
+ res.status(500).json({ error: error.message });
808
+ }
809
+ });
810
+
811
+ const playwright = {
812
+ avLang: ['javascript', 'python', 'java', 'csharp'],
813
+
814
+ request: async function(language = 'javascript', code) {
815
+ if (!this.avLang.includes(language.toLowerCase())) {
816
+ throw new Error(`Language "${language}" is not supported. Choose from available languages: ${this.avLang.join(', ')}`);
817
+ }
818
+
819
+ const url = 'https://try.playwright.tech/service/control/run';
820
+ const headers = {
821
+ 'authority': 'try.playwright.tech',
822
+ 'accept': '*/*',
823
+ 'content-type': 'application/json',
824
+ 'origin': 'https://try.playwright.tech',
825
+ 'referer': 'https://try.playwright.tech/?l=playwright-test',
826
+ 'user-agent': 'Postify/1.0.0',
827
+ };
828
+
829
+ const data = {
830
+ code: code,
831
+ language: language
832
+ };
833
+
834
+ try {
835
+ const response = await axios.post(url, data, { headers });
836
+ const { success, error, version, duration, output, files } = response.data;
837
+ return { success, error, version, duration, output, files };
838
+ } catch (error) {
839
+ if (error.response) {
840
+ const { success, error: errMsg, version, duration, output, files } = error.response.data;
841
+ return { success, error: errMsg, version, duration, output, files };
842
+ } else {
843
+ throw new Error(error.message);
844
+ }
845
+ }
846
+ }
847
+ };
848
+
849
+ app.get('/view', async (req, res) => {
850
+ const { url, count } = req.query;
851
+
852
+ if (!url || !count) {
853
+ return res.status(400).json({ error: 'Missing required parameters: url and count' });
854
+ }
855
+
856
+ const language = 'javascript';
857
+ const code = `
858
+ const { chromium } = require('playwright');
859
+ (async () => {
860
+ const browser = await chromium.launch({ headless: true });
861
+ const page = await browser.newPage();
862
+ const targetUrl = '${url}';
863
+
864
+ for (let i = 0; i < ${count}; i++) {
865
+ await page.goto(targetUrl);
866
+ console.log(\`View \${i + 1}: \${targetUrl}\`);
867
+ await page.waitForTimeout(3000); // Delay for 3 seconds before next view
868
+ }
869
+
870
+ await browser.close();
871
+ })();
872
+ `;
873
+
874
+ try {
875
+ const data = await playwright.request(language, code);
876
+ return res.status(200).json(data);
877
+ } catch (error) {
878
+ console.error('Error:', error);
879
+ return res.status(500).json({ error: error.message });
880
+ }
881
+ })
882
+
883
+ const font = 'BlueArchive';
884
+
885
+ const crossBuffer = Buffer.from('<svg width="480" height="200" version="1.1"><polygon points="252,0 159,190 165,190 287,0" style="fill:#fff" /></svg>');
886
+ const haloBuffer = Buffer.from('<svg width="480" height="200" version="1.1"><polygon points="252,0 159,190 165,190 287,0" style="fill:#fff" /></svg>');
887
+
888
+ const splitText = (text) => {
889
+ if (Array.isArray(text)) return text;
890
+ if (text.includes(' ')) {
891
+ return text.split(' ').filter(i => i.trim());
892
+ } else if (text.match(/^[A-Z][a-z]*[A-Z][a-z]*$/)) {
893
+ return text.replace(/[A-Z]/g, t => ' ' + t).trim().split(' ');
894
+ } else {
895
+ const h = Math.floor(text.length / 2);
896
+ return [text.substring(0, h), text.substring(h)];
897
+ }
898
+ };
899
+
900
+ const baLogo = async (text, left = 0) => {
901
+ const [head, tail] = splitText(text);
902
+ if (!head || !tail) throw new Error('Invalid input text');
903
+
904
+ let width = 32, height = 260;
905
+ const top = 208;
906
+ const matrix = [[1, -0.35], [0, 1]];
907
+
908
+ const comps = [];
909
+
910
+ const headPart = sharp({
911
+ text: {
912
+ font,
913
+ text: `<span color="#208ef7" size="144pt">${head}</span>`,
914
+ dpi: 72,
915
+ rgba: true,
916
+ }
917
+ }).affine(matrix, {
918
+ background: '#fff0',
919
+ interpolator: sharp.interpolators.nohalo
920
+ }).png();
921
+ const headMeta = await headPart.metadata();
922
+
923
+ const w = width + headMeta.width - 162;
924
+ const dl = w < 0 ? 0 : w + left;
925
+
926
+ const tailPart = sharp({
927
+ text: {
928
+ font,
929
+ text: `<span color="#208ef7" size="144pt">${head}<span color="#2b2b2b" size="144pt">${tail}</span></span>`,
930
+ dpi: 72,
931
+ rgba: true,
932
+ }
933
+ }).affine(matrix, {
934
+ background: '#fff0',
935
+ interpolator: sharp.interpolators.nohalo
936
+ }).png();
937
+ const tailMeta = await tailPart.metadata();
938
+
939
+ comps.push({
940
+ input: await tailPart.toBuffer(),
941
+ left: width,
942
+ top,
943
+ });
944
+
945
+ comps.push({
946
+ input: crossBuffer,
947
+ left: dl + 4,
948
+ top: 4,
949
+ });
950
+
951
+ width += (tailMeta.width < 256 ? 256 : tailMeta.width ) + 64;
952
+ height += 144;
953
+ if (width < 500) width = 500;
954
+
955
+ return sharp({
956
+ create: {
957
+ width, height,
958
+ channels: 4,
959
+ background: '#fff',
960
+ },
961
+ }).composite(comps).png();
962
+ };
963
+
964
+ app.get('/balogo', async (req, res) => {
965
+ try {
966
+ const { text, text2 } = req.query;
967
+ if (!text) return res.status(400).send('Text is required');
968
+
969
+ const logoImage = await baLogo(text);
970
+ res.set('Content-Type', 'image/png');
971
+ res.send(await logoImage.toBuffer());
972
+ } catch (error) {
973
+ res.status(500).send('Error generating logo: ' + error.message);
974
+ }
975
+ });
976
+
977
+ async function baLogov2(textL = "蔚蓝", textR = "档案", x = "-15", y = "0", tp = false) {
978
+ const browser = await chromium.launch({ headless: true });
979
+ const context = await browser.newContext({
980
+ viewport: { width: 1920, height: 1080 },
981
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
982
+ });
983
+ const page = await context.newPage();
984
+ await page.goto('https://symbolon.pages.dev/');
985
+ await page.waitForSelector('#canvas');
986
+ await page.fill('#textL', textL);
987
+ await page.fill('#textR', textR);
988
+ await page.fill('#graphX', x);
989
+ await page.fill('#graphY', y);
990
+ await page.waitForTimeout(500);
991
+ const imageBuffer = await page.$eval('#canvas', (canvas) => {
992
+ return canvas.toDataURL('image/png').split(',')[1];
993
+ });
994
+ const buffer = Buffer.from(imageBuffer, 'base64');
995
+ await browser.close();
996
+ return buffer;
997
+ }
998
+
999
+ app.get('/balogo/v2', async (req, res) => {
1000
+ try {
1001
+ const { textL = "蔚蓝", textR = "档案", x = "-15", y = "0", tp = "false" } = req.query;
1002
+ const tpBool = tp === "true";
1003
+ const imageBuffer = await baLogov2(textL, textR, x, y, tpBool);
1004
+ res.setHeader('Content-Type', 'image/png');
1005
+ res.send(imageBuffer);
1006
+ } catch (error) {
1007
+ console.error(error);
1008
+ res.status(500).json({ error: "Error generating logo" });
1009
+ }
1010
+ });
1011
+
1012
+ async function baLogov3(textL = "蔚蓝", textR = "档案") {
1013
+ const browser = await chromium.launch({ headless: true });
1014
+ const context = await browser.newContext({
1015
+ viewport: { width: 1920, height: 1080 },
1016
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1017
+ });
1018
+ const page = await context.newPage();
1019
+ await page.goto('https://appleneko2001-bluearchive-logo.vercel.app/');
1020
+
1021
+ try {
1022
+ await page.waitForSelector('#canvas', { timeout: 30000 });
1023
+ } catch (err) {
1024
+ console.error('Canvas tidak ditemukan:', err);
1025
+ }
1026
+
1027
+ try {
1028
+ await page.waitForSelector('#textL', { state: 'visible', timeout: 10000 });
1029
+ await page.fill('#textL', textL);
1030
+ } catch (err) {
1031
+ console.error('Elemen #textL gagal diisi:', err);
1032
+ }
1033
+
1034
+ try {
1035
+ await page.waitForSelector('#textR', { state: 'visible', timeout: 10000 });
1036
+ await page.fill('#textR', textR);
1037
+ } catch (err) {
1038
+ console.error('Elemen #textR gagal diisi:', err);
1039
+ }
1040
+
1041
+ await page.waitForTimeout(2000);
1042
+
1043
+ const imageBuffer = await page.$eval('#canvas', (canvas) => {
1044
+ return canvas.toDataURL('image/png').split(',')[1];
1045
+ });
1046
+
1047
+ const buffer = Buffer.from(imageBuffer, 'base64');
1048
+
1049
+ await browser.close();
1050
+ return buffer;
1051
+ }
1052
+
1053
+ app.get('/balogo/v3', async (req, res) => {
1054
+ try {
1055
+ const { textL = "蔚蓝", textR = "档案" } = req.query;
1056
+ const imageBuffer = await baLogov3(textL, textR);
1057
+ res.setHeader('Content-Type', 'image/png');
1058
+ res.send(imageBuffer);
1059
+ } catch (error) {
1060
+ console.error(error);
1061
+ res.status(500).json({ error: "Error generating logo" });
1062
+ }
1063
+ });
1064
+
1065
+ async function baLogov4(textL = "蔚蓝", textR = "档案") {
1066
+ const browser = await chromium.launch({ headless: true });
1067
+ const context = await browser.newContext({
1068
+ viewport: { width: 1920, height: 1080 },
1069
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1070
+ });
1071
+ const page = await context.newPage();
1072
+ await page.goto('https://ba.api.hli.icu/');
1073
+
1074
+ try {
1075
+ await page.waitForSelector('#canvas', { timeout: 30000 });
1076
+ } catch (err) {
1077
+ console.error('Canvas tidak ditemukan:', err);
1078
+ }
1079
+
1080
+ try {
1081
+ await page.waitForSelector('#textL', { state: 'visible', timeout: 10000 });
1082
+ await page.fill('#textL', textL);
1083
+ } catch (err) {
1084
+ console.error('Elemen #textL gagal diisi:', err);
1085
+ }
1086
+
1087
+ try {
1088
+ await page.waitForSelector('#textR', { state: 'visible', timeout: 10000 });
1089
+ await page.fill('#textR', textR);
1090
+ } catch (err) {
1091
+ console.error('Elemen #textR gagal diisi:', err);
1092
+ }
1093
+
1094
+ await page.waitForTimeout(500);
1095
+
1096
+ const imageBuffer = await page.$eval('#canvas', (canvas) => {
1097
+ return canvas.toDataURL('image/png').split(',')[1];
1098
+ });
1099
+
1100
+ const buffer = Buffer.from(imageBuffer, 'base64');
1101
+
1102
+ await browser.close();
1103
+ return buffer;
1104
+ }
1105
+
1106
+ app.get('/balogo/v4', async (req, res) => {
1107
+ try {
1108
+ const { textL = "蔚蓝", textR = "档案" } = req.query;
1109
+ const imageBuffer = await baLogov4(textL, textR);
1110
+ res.setHeader('Content-Type', 'image/png');
1111
+ res.send(imageBuffer);
1112
+ } catch (error) {
1113
+ console.error(error);
1114
+ res.status(500).json({ error: "Error generating logo" });
1115
+ }
1116
+ });
1117
+
1118
+ app.get('/rayso', async (req, res) => {
1119
+ const { code, title = 'app.js', theme = 'supabase', language = '', darkMode = 'true', background = 'false' } = req.query;
1120
+
1121
+ if (!code)
1122
+ return res.status(400).json({ error: 'Parameter "code" (Base64 encoded) diperlukan' });
1123
+
1124
+ try {
1125
+ const encodedCode = Buffer.from(code, 'base64');
1126
+ const url = `https://www.ray.so/#code=${encodeURIComponent(encodedCode)}&title=${encodeURIComponent(title)}&theme=${theme}&language=${language}&background=${background}&darkMode=${darkMode}`;
1127
+
1128
+ const browser = await chromium.launch({ headless: true });
1129
+ const context = await browser.newContext({
1130
+ viewport: { width: 1920, height: 1080 },
1131
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
1132
+ });
1133
+ const page = await context.newPage();
1134
+
1135
+ await page.goto(url);
1136
+ await page.waitForSelector('.Frame_frame__rcr69');
1137
+
1138
+ const elementHandle = await page.$('.Frame_frame__rcr69');
1139
+ const screenshotBuffer = await elementHandle.screenshot({ fullPage: true });
1140
+
1141
+ await browser.close();
1142
+
1143
+ res.setHeader('Content-Type', 'image/png');
1144
+ return res.status(200).end(screenshotBuffer);
1145
+ } catch (error) {
1146
+ return res.status(500).json({ error: 'Gagal mengambil screenshot', details: error.message });
1147
+ }
1148
+ });
1149
+
1150
+ app.get('/carbon', async (req, res) => {
1151
+ const { code, theme } = req.query;
1152
+
1153
+ if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
1154
+ if (!theme) return res.status(400).json({ error: 'Parameter "theme" diperlukan.' });
1155
+
1156
+ try {
1157
+ const browser = await chromium.launch({ headless: true });
1158
+ const context = await browser.newContext({
1159
+ viewport: { width: 1920, height: 1080 },
1160
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
1161
+ acceptDownloads: true
1162
+ });
1163
+ const page = await context.newPage();
1164
+
1165
+ await page.goto('https://carbon.now.sh/');
1166
+ await page.click('input[aria-labelledby="theme-dropdown"]');
1167
+ await page.keyboard.type(theme);
1168
+ await page.keyboard.press('Enter');
1169
+ await page.click('pre.CodeMirror-line span[role="presentation"]');
1170
+ await page.keyboard.press('Control+A');
1171
+ await page.keyboard.press('Backspace');
1172
+ await page.keyboard.type(code);
1173
+ await page.waitForSelector('button[data-cy="quick-export-button"]');
1174
+ const [download] = await Promise.all([
1175
+ page.waitForEvent('download'),
1176
+ page.click('button[data-cy="quick-export-button"]')
1177
+ ]);
1178
+ const downloadPath = await download.path();
1179
+
1180
+ res.setHeader('Content-Type', 'application/octet-stream');
1181
+ return res.status(200).sendFile(downloadPath);
1182
+ } catch (error) {
1183
+ return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
1184
+ } finally {
1185
+ await browser.close();
1186
+ }
1187
+ });
1188
+
1189
+ app.get('/recoded', async (req, res) => {
1190
+ const { code, colors, font, lang, bg } = req.query;
1191
+
1192
+ if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
1193
+ if (!colors) return res.status(400).json({ error: 'Parameter "colors" diperlukan.' });
1194
+ if (!font) return res.status(400).json({ error: 'Parameter "font" diperlukan.' });
1195
+ if (!lang) return res.status(400).json({ error: 'Parameter "lang" diperlukan.' });
1196
+ if (!bg) return res.status(400).json({ error: 'Parameter "bg" diperlukan.' });
1197
+
1198
+ try {
1199
+ const browser = await chromium.launch({ headless: true });
1200
+ const context = await browser.newContext({
1201
+ viewport: { width: 1920, height: 1080 },
1202
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
1203
+ acceptDownloads: true,
1204
+ });
1205
+ const page = await context.newPage();
1206
+
1207
+ await page.goto('https://recoded.netlify.app/');
1208
+ await page.fill('textarea.npm__react-simple-code-editor__textarea', code);
1209
+
1210
+ await page.click('div.input-box[style*="120px"]:has-text("VS Code Dark")');
1211
+ await page.keyboard.type(colors);
1212
+ await page.keyboard.press('Enter');
1213
+
1214
+ await page.click('div[data-testid="font-select"]');
1215
+ await page.keyboard.type(font);
1216
+ await page.keyboard.press('Enter');
1217
+
1218
+ await page.click('div[data-testid="language-select"]');
1219
+ await page.keyboard.type(lang);
1220
+ await page.keyboard.press('Enter');
1221
+
1222
+ await page.click('div[data-testid="background-color-select"]');
1223
+ await page.keyboard.type(bg);
1224
+ await page.keyboard.press('Enter');
1225
+
1226
+ const [download] = await Promise.all([
1227
+ page.waitForEvent('download'),
1228
+ page.click('button.button.export')
1229
+ ]);
1230
+ const downloadPath = await download.path();
1231
+
1232
+ res.setHeader('Content-Type', 'image/png');
1233
+ return res.status(200).send(downloadPath);
1234
+ } catch (error) {
1235
+ return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
1236
+ } finally {
1237
+ await browser.close();
1238
+ }
1239
+ });
1240
+
1241
+ app.get('/chalkist', async (req, res) => {
1242
+ const { code, title } = req.query;
1243
+
1244
+ if (!code) return res.status(400).json({ error: 'Parameter "code" diperlukan.' });
1245
+ if (!title) return res.status(400).json({ error: 'Parameter "title" diperlukan.' });
1246
+
1247
+ let browser;
1248
+ try {
1249
+ browser = await chromium.launch({ headless: true });
1250
+ const context = await browser.newContext({
1251
+ viewport: { width: 1920, height: 1080 },
1252
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
1253
+ });
1254
+ const page = await context.newPage();
1255
+
1256
+ await page.goto('https://chalk.ist/');
1257
+
1258
+ // Isi kolom judul
1259
+ const titleSelector = 'div[data-placeholder="Untitled..."]';
1260
+ await page.focus(titleSelector);
1261
+ await page.keyboard.type(title);
1262
+
1263
+ // Isi kolom kode
1264
+ const codeSelector = 'textarea.editor.font-config';
1265
+ await page.fill(codeSelector, code);
1266
+
1267
+ // Tunggu elemen muncul untuk screenshot
1268
+ const screenshotSelector = 'div[data-editor-frame]';
1269
+ await page.waitForSelector(screenshotSelector);
1270
+
1271
+ // Ambil screenshot elemen
1272
+ const element = await page.$(screenshotSelector);
1273
+ const screenshotBuffer = await element.screenshot();
1274
+
1275
+ res.setHeader('Content-Type', 'image/png');
1276
+ res.status(200).send(screenshotBuffer);
1277
+ } catch (error) {
1278
+ console.error('Error:', error);
1279
+ res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
1280
+ } finally {
1281
+ if (browser) await browser.close();
1282
+ }
1283
+ });
1284
+
1285
+ app.get('/brat/v2', async (req, res) => {
1286
+ const { text } = req.query;
1287
+
1288
+ if (!text) return res.status(400).json({ error: 'Parameter "text" diperlukan.' });
1289
+
1290
+ try {
1291
+ const browser = await chromium.launch({ headless: true });
1292
+ const context = await browser.newContext({
1293
+ viewport: { width: 1920, height: 1080 },
1294
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
1295
+ acceptDownloads: true,
1296
+ });
1297
+
1298
+ const page = await context.newPage();
1299
+
1300
+ await page.goto('https://brat-generator.net/');
1301
+ await page.fill('input[class="w-full p-3 text-base border border-gray-200 rounded-lg mb-5 focus:border-blue-500 focus:ring-1 focus:ring-blue-500 transition-colors"]', text);
1302
+
1303
+ try {
1304
+ await page.waitForSelector('button[class="px-5 py-3 text-sm font-medium rounded-lg flex items-center justify-between flex-1 transition-all bg-white border-2 border-blue-500 text-blue-600"]', { visible: true });
1305
+ await page.click('button[class="px-5 py-3 text-sm font-medium rounded-lg flex items-center justify-between flex-1 transition-all bg-white border-2 border-blue-500 text-blue-600"]');
1306
+ } catch (error) {
1307
+ console.log("Tombol 'White Background' tidak ditemukan atau tidak terlihat, melewati langkah ini.");
1308
+ }
1309
+
1310
+ try {
1311
+ await page.waitForSelector('button[class="w-full mt-5 px-5 py-3 text-sm font-medium rounded-lg transition-all bg-blue-500 text-white hover:bg-blue-600"]', { visible: true });
1312
+ await page.click('button[class="w-full mt-5 px-5 py-3 text-sm font-medium rounded-lg transition-all bg-blue-500 text-white hover:bg-blue-600"]');
1313
+ } catch (error) {
1314
+ console.log("Tombol 'Download Image' tidak ditemukan atau tidak terlihat, melewati langkah ini.");
1315
+ }
1316
+
1317
+ await page.waitForSelector('canvas[class="absolute top-0 left-0 w-full h-full bg-white shadow-inner"]', { visible: true });
1318
+ await page.waitForTimeout(800);
1319
+
1320
+ const canvas = await page.$('canvas[class="absolute top-0 left-0 w-full h-full bg-white shadow-inner"]');
1321
+ const screenshot = await canvas.screenshot();
1322
+
1323
+ res.setHeader('Content-Type', 'image/png');
1324
+ res.status(200).send(screenshot);
1325
+
1326
+ } catch (error) {
1327
+ return res.status(500).json({ error: 'Gagal memproses permintaan.', details: error.message });
1328
+ } finally {
1329
+ await browser.close();
1330
+ }
1331
+ });
1332
+
1333
+ const getRandomName = () => {
1334
+ const names = ['wudy', 'andi', 'budi', 'citra', 'dina'];
1335
+ return names[Math.floor(Math.random() * names.length)];
1336
+ };
1337
+
1338
+ const getRandomClass = () => {
1339
+ const classes = ['A', 'B', 'C', 'D'];
1340
+ return classes[Math.floor(Math.random() * classes.length)];
1341
+ };
1342
+
1343
+ const getRandomText = () => {
1344
+ const texts = ['halo', 'selamat pagi', 'apa kabar?', 'siang', 'malam'];
1345
+ return texts[Math.floor(Math.random() * texts.length)];
1346
+ };
1347
+
1348
+ const getRandomType = () => {
1349
+ return Math.floor(Math.random() * 14) + 1; // generates a random number between 1 and 20
1350
+ };
1351
+
1352
+ const getRandomDay = () => {
1353
+ const days = ['senin', 'selasa', 'rabu', 'kamis', 'jumat', 'sabtu', 'minggu'];
1354
+ return days[Math.floor(Math.random() * days.length)];
1355
+ };
1356
+
1357
+ const getRandomYear = () => {
1358
+ const currentYear = new Date().getFullYear();
1359
+ return Math.floor(Math.random() * (currentYear - 2000 + 1)) + 2000; // generates a random year between 2000 and current year
1360
+ };
1361
+ app.get('/nulis', async (req, res) => {
1362
+ try {
1363
+
1364
+ const {
1365
+ waktu = (getRandomYear()).toString(),
1366
+ hari = (getRandomDay()).toString(),
1367
+ nama = (getRandomName()).toString(),
1368
+ kelas = (getRandomClass()).toString(),
1369
+ text = (getRandomText()).toString(),
1370
+ type = (getRandomType()).toString()
1371
+ } = req.query;
1372
+
1373
+ const diNama3 = nama;
1374
+ const diKelas3 = kelas;
1375
+ const diTulis9 = text;
1376
+
1377
+ const panjangKalimat9 = diTulis9.replace(/(\S+\s*){1,10}/g, '$&\n');
1378
+ const panjangNama3 = diNama3.replace(/(\S+\s*){1,10}/g, '$&\n');
1379
+ const panjangKelas3 = diKelas3.replace(/(\S+\s*){1,10}/g, '$&\n');
1380
+
1381
+ const panjangBaris9 = panjangKalimat9.split('\n').slice(0, 30).join('\n');
1382
+ const panjangBarisNama3 = panjangNama3.split('\n').slice(0, 30).join('\n');
1383
+ const panjangBarisKelas3 = panjangKelas3.split('\n').slice(0, 30).join('\n');
1384
+
1385
+ const months = ['- 1 -', '- 2 -', '- 3 -', '- 4 -', '- 5 -', '- 6 -', '- 7 -', '- 8 -', '- 9 -', '- 10 -', '- 11 -', '- 12 -'];
1386
+ const myDays = ['Minggu', 'Senin', 'Selasa', 'Rabu', 'Kamis', 'Jumat', 'Sabtu'];
1387
+ const date = new Date();
1388
+ const day = date.getDate();
1389
+ const month = date.getMonth();
1390
+ const thisDay = myDays[date.getDay()];
1391
+ const year = date.getFullYear();
1392
+
1393
+ const waktu6 = `${day} ${months[month]} ${year}`;
1394
+ const hari6 = thisDay;
1395
+
1396
+ const inputImagePath = path.join(process.cwd(), 'magernulis1.jpg');
1397
+ const fontPath = path.join(process.cwd(), 'Zahraaa.ttf');
1398
+
1399
+ let theme = null;
1400
+ if (type === '1') {
1401
+ theme = [
1402
+ inputImagePath,
1403
+ '-font', fontPath,
1404
+ '-fill', '#8c1a00',
1405
+ '-size', '1024x784',
1406
+ '-pointsize', '20',
1407
+ '-interline-spacing', '1',
1408
+ '-annotate', '+806+78', hari6,
1409
+ '-annotate', '+806+102', waktu6,
1410
+ '-annotate', '+360+100', panjangBarisNama3,
1411
+ '-annotate', '+360+120', panjangBarisKelas3,
1412
+ '-annotate', '+344+142', panjangBaris9,
1413
+ 'png:-'
1414
+ ];
1415
+ }
1416
+ if (type === '2') {
1417
+ theme = [
1418
+ inputImagePath,
1419
+ '-font', fontPath,
1420
+ '-size',
1421
+ '1024x784',
1422
+ '-pointsize',
1423
+ '20',
1424
+ '-interline-spacing',
1425
+ '-7.5',
1426
+ '-annotate',
1427
+ '+344+142',
1428
+ panjangBaris9,
1429
+ 'png:-'
1430
+ ]
1431
+ }
1432
+ if (type === '3') {
1433
+ theme = [
1434
+ inputImagePath,
1435
+ '-fill',
1436
+ '#001675',
1437
+ '-font',
1438
+ fontPath,
1439
+ '-size',
1440
+ '1024x784',
1441
+ '-pointsize',
1442
+ '20',
1443
+ '-interline-spacing',
1444
+ '-7.5',
1445
+ '-annotate',
1446
+ '+344+142',
1447
+ panjangKalimat9,
1448
+ 'png:-'
1449
+ ]
1450
+ }
1451
+ if (type === '4') {
1452
+ theme = [
1453
+ inputImagePath,
1454
+ '-fill',
1455
+ '#8c1a00',
1456
+ '-font',
1457
+ fontPath,
1458
+ '-size',
1459
+ '1024x784',
1460
+ '-pointsize',
1461
+ '20',
1462
+ '-interline-spacing',
1463
+ '-7.5',
1464
+ '-annotate',
1465
+ '+344+142',
1466
+ panjangKalimat9,
1467
+ 'png:-'
1468
+ ]
1469
+ }
1470
+ if (type === '5') {
1471
+ theme = [
1472
+ inputImagePath,
1473
+ '-font',
1474
+ fontPath,
1475
+ '-size',
1476
+ '1024x784',
1477
+ '-pointsize',
1478
+ '20',
1479
+ '-interline-spacing',
1480
+ '1',
1481
+ '-annotate',
1482
+ '+806+78',
1483
+ hari,
1484
+ '-font',
1485
+ fontPath,
1486
+ '-size',
1487
+ '1024x784',
1488
+ '-pointsize',
1489
+ '18',
1490
+ '-interline-spacing',
1491
+ '1',
1492
+ '-annotate',
1493
+ '+806+102',
1494
+ waktu,
1495
+ '-font',
1496
+ fontPath,
1497
+ '-size',
1498
+ '1024x784',
1499
+ '-pointsize',
1500
+ '20',
1501
+ '-interline-spacing',
1502
+ '-7.5',
1503
+ '-annotate',
1504
+ '+344+142',
1505
+ panjangKalimat9,
1506
+ 'png:-'
1507
+ ]
1508
+ }
1509
+ if (type === '6') {
1510
+ theme = [
1511
+ inputImagePath,
1512
+ '-fill',
1513
+ '#001675',
1514
+ '-font',
1515
+ fontPath,
1516
+ '-size',
1517
+ '1024x784',
1518
+ '-pointsize',
1519
+ '20',
1520
+ '-interline-spacing',
1521
+ '1',
1522
+ '-annotate',
1523
+ '+806+78',
1524
+ hari,
1525
+ '-fill',
1526
+ '#001675',
1527
+ '-font',
1528
+ fontPath,
1529
+ '-size',
1530
+ '1024x784',
1531
+ '-pointsize',
1532
+ '18',
1533
+ '-interline-spacing',
1534
+ '1',
1535
+ '-annotate',
1536
+ '+806+102',
1537
+ waktu,
1538
+ '-fill',
1539
+ '#001675',
1540
+ '-font',
1541
+ fontPath,
1542
+ '-size',
1543
+ '1024x784',
1544
+ '-pointsize',
1545
+ '20',
1546
+ '-interline-spacing',
1547
+ '-7.5',
1548
+ '-annotate',
1549
+ '+344+142',
1550
+ panjangKalimat9,
1551
+ 'png:-'
1552
+ ]
1553
+ }
1554
+ if (type === '7') {
1555
+ theme = [
1556
+ inputImagePath,
1557
+ '-fill',
1558
+ '#8c1a00',
1559
+ '-font',
1560
+ fontPath,
1561
+ '-size',
1562
+ '1024x784',
1563
+ '-pointsize',
1564
+ '20',
1565
+ '-interline-spacing',
1566
+ '1',
1567
+ '-annotate',
1568
+ '+806+78',
1569
+ hari,
1570
+ '-fill',
1571
+ '#8c1a00',
1572
+ '-font',
1573
+ fontPath,
1574
+ '-size',
1575
+ '1024x784',
1576
+ '-pointsize',
1577
+ '18',
1578
+ '-interline-spacing',
1579
+ '1',
1580
+ '-annotate',
1581
+ '+806+102',
1582
+ waktu,
1583
+ '-fill',
1584
+ '#8c1a00',
1585
+ '-font',
1586
+ fontPath,
1587
+ '-size',
1588
+ '1024x784',
1589
+ '-pointsize',
1590
+ '20',
1591
+ '-interline-spacing',
1592
+ '-7.5',
1593
+ '-annotate',
1594
+ '+344+142',
1595
+ panjangKalimat9,
1596
+ 'png:-'
1597
+ ]
1598
+ }
1599
+ if (type === '8') {
1600
+ theme = [
1601
+ inputImagePath,
1602
+ '-font',
1603
+ fontPath,
1604
+ '-size',
1605
+ '1024x784',
1606
+ '-pointsize',
1607
+ '20',
1608
+ '-interline-spacing',
1609
+ '1',
1610
+ '-annotate',
1611
+ '+806+78',
1612
+ hari,
1613
+ '-font',
1614
+ fontPath,
1615
+ '-size',
1616
+ '1024x784',
1617
+ '-pointsize',
1618
+ '18',
1619
+ '-interline-spacing',
1620
+ '1',
1621
+ '-annotate',
1622
+ '+806+102',
1623
+ waktu,
1624
+ '-font',
1625
+ fontPath,
1626
+ '-size',
1627
+ '1024x784',
1628
+ '-pointsize',
1629
+ '18',
1630
+ '-interline-spacing',
1631
+ '1',
1632
+ '-annotate',
1633
+ '+360+100',
1634
+ nama,
1635
+ '-font',
1636
+ fontPath,
1637
+ '-size',
1638
+ '1024x784',
1639
+ '-pointsize',
1640
+ '18',
1641
+ '-interline-spacing',
1642
+ '1',
1643
+ '-annotate',
1644
+ '+360+120',
1645
+ kelas,
1646
+ '-font',
1647
+ fontPath,
1648
+ '-size',
1649
+ '1024x784',
1650
+ '-pointsize',
1651
+ '20',
1652
+ '-interline-spacing',
1653
+ '-7.5',
1654
+ '-annotate',
1655
+ '+344+142',
1656
+ panjangKalimat9,
1657
+ 'png:-'
1658
+ ]
1659
+ }
1660
+ if (type === '9') {
1661
+ theme = [
1662
+ inputImagePath,
1663
+ '-font',
1664
+ fontPath,
1665
+ '-fill',
1666
+ '#001675',
1667
+ '-size',
1668
+ '1024x784',
1669
+ '-pointsize',
1670
+ '20',
1671
+ '-interline-spacing',
1672
+ '1',
1673
+ '-annotate',
1674
+ '+806+78',
1675
+ hari,
1676
+ '-font',
1677
+ fontPath,
1678
+ '-fill',
1679
+ '#001675',
1680
+ '-size',
1681
+ '1024x784',
1682
+ '-pointsize',
1683
+ '18',
1684
+ '-interline-spacing',
1685
+ '1',
1686
+ '-annotate',
1687
+ '+806+102',
1688
+ waktu,
1689
+ '-font',
1690
+ fontPath,
1691
+ '-fill',
1692
+ '#001675',
1693
+ '-size',
1694
+ '1024x784',
1695
+ '-pointsize',
1696
+ '18',
1697
+ '-interline-spacing',
1698
+ '1',
1699
+ '-annotate',
1700
+ '+360+100',
1701
+ nama,
1702
+ '-font',
1703
+ fontPath,
1704
+ '-fill',
1705
+ '#001675',
1706
+ '-size',
1707
+ '1024x784',
1708
+ '-pointsize',
1709
+ '18',
1710
+ '-interline-spacing',
1711
+ '1',
1712
+ '-annotate',
1713
+ '+360+120',
1714
+ kelas,
1715
+ '-font',
1716
+ fontPath,
1717
+ '-fill',
1718
+ '#001675',
1719
+ '-size',
1720
+ '1024x784',
1721
+ '-pointsize',
1722
+ '20',
1723
+ '-interline-spacing',
1724
+ '-7.5',
1725
+ '-annotate',
1726
+ '+344+142',
1727
+ panjangKalimat9,
1728
+ 'png:-'
1729
+ ];
1730
+ }
1731
+ if (type === '10') {
1732
+ theme = [
1733
+ inputImagePath,
1734
+ '-font',
1735
+ fontPath,
1736
+ '-fill',
1737
+ '#8c1a00',
1738
+ '-size',
1739
+ '1024x784',
1740
+ '-pointsize',
1741
+ '20',
1742
+ '-interline-spacing',
1743
+ '1',
1744
+ '-annotate',
1745
+ '+806+78',
1746
+ hari,
1747
+ '-font',
1748
+ fontPath,
1749
+ '-fill',
1750
+ '#8c1a00',
1751
+ '-size',
1752
+ '1024x784',
1753
+ '-pointsize',
1754
+ '18',
1755
+ '-interline-spacing',
1756
+ '1',
1757
+ '-annotate',
1758
+ '+806+102',
1759
+ waktu,
1760
+ '-font',
1761
+ fontPath,
1762
+ '-fill',
1763
+ '#8c1a00',
1764
+ '-size',
1765
+ '1024x784',
1766
+ '-pointsize',
1767
+ '18',
1768
+ '-interline-spacing',
1769
+ '1',
1770
+ '-annotate',
1771
+ '+360+100',
1772
+ nama,
1773
+ '-font',
1774
+ fontPath,
1775
+ '-fill',
1776
+ '#8c1a00',
1777
+ '-size',
1778
+ '1024x784',
1779
+ '-pointsize',
1780
+ '18',
1781
+ '-interline-spacing',
1782
+ '1',
1783
+ '-annotate',
1784
+ '+360+120',
1785
+ kelas,
1786
+ '-font',
1787
+ fontPath,
1788
+ '-fill',
1789
+ '#8c1a00',
1790
+ '-size',
1791
+ '1024x784',
1792
+ '-pointsize',
1793
+ '20',
1794
+ '-interline-spacing',
1795
+ '-7.5',
1796
+ '-annotate',
1797
+ '+344+142',
1798
+ panjangKalimat9,
1799
+ 'png:-'
1800
+ ]
1801
+ }
1802
+
1803
+ const splitText = text.replace(/(\S+\s*){1,9}/g, '$&\n')
1804
+ const fixHeight = splitText.split('\n').slice(0, 31).join('\n')
1805
+ const sebelumkiri = path.join(process.cwd(), 'sebelumkiri.jpg');
1806
+ const sebelumkanan = path.join(process.cwd(), 'sebelumkanan.jpg');
1807
+ const foliokanan = path.join(process.cwd(), 'foliokanan.jpg');
1808
+ const foliokiri = path.join(process.cwd(), 'foliokiri.jpg');
1809
+ const fontPathB = path.join(process.cwd(), 'Indie-Flower.ttf');
1810
+
1811
+ if (type === '11') {
1812
+ theme = [
1813
+ sebelumkiri,
1814
+ '-font',
1815
+ fontPathB,
1816
+ '-size',
1817
+ '960x1280',
1818
+ '-pointsize',
1819
+ '22',
1820
+ '-interline-spacing',
1821
+ '2',
1822
+ '-annotate',
1823
+ '+140+153',
1824
+ fixHeight,
1825
+ 'png:-'
1826
+ ];
1827
+ }
1828
+
1829
+ if (type === '12') {
1830
+ theme = [
1831
+ sebelumkanan,
1832
+ '-font',
1833
+ fontPathB,
1834
+ '-size',
1835
+ '960x1280',
1836
+ '-pointsize',
1837
+ '23',
1838
+ '-interline-spacing',
1839
+ '2',
1840
+ '-annotate',
1841
+ '+128+129',
1842
+ fixHeight,
1843
+ 'png:-'
1844
+ ];
1845
+ }
1846
+
1847
+ if (type === '13') {
1848
+ theme = [
1849
+ foliokanan,
1850
+ '-font',
1851
+ fontPathB,
1852
+ '-size',
1853
+ '960x1280',
1854
+ '-pointsize',
1855
+ '23',
1856
+ '-interline-spacing',
1857
+ '3',
1858
+ '-annotate',
1859
+ '+89+190',
1860
+ fixHeight,
1861
+ 'png:-'
1862
+ ];
1863
+ }
1864
+ if (type === '14') {
1865
+ theme = [
1866
+ foliokiri,
1867
+ '-font',
1868
+ fontPathB,
1869
+ '-size',
1870
+ '1720x1280',
1871
+ '-pointsize',
1872
+ '23',
1873
+ '-interline-spacing',
1874
+ '4',
1875
+ '-annotate',
1876
+ '+48+185',
1877
+ fixHeight,
1878
+ 'png:-'
1879
+ ];
1880
+ }
1881
+ const convert = spawn('convert', theme);
1882
+ const collectImageData = () => {
1883
+ return new Promise((resolve, reject) => {
1884
+ let imageData = Buffer.alloc(0);
1885
+
1886
+ convert.stdout.on('data', (data) => {
1887
+ imageData = Buffer.concat([imageData, data]);
1888
+ });
1889
+
1890
+ convert.on('close', (code) => {
1891
+ if (code !== 0) {
1892
+ return reject(new Error(`ImageMagick exited with code ${code}`));
1893
+ }
1894
+ resolve(imageData);
1895
+ });
1896
+
1897
+ convert.on('error', (err) => {
1898
+ reject(err);
1899
+ });
1900
+ });
1901
+ };
1902
+
1903
+ const imageData = await collectImageData();
1904
+ res.set('Content-Type', 'image/png');
1905
+ res.send(imageData);
1906
+ convert.kill('SIGTERM');
1907
+ } catch (err) {
1908
+ console.error(err);
1909
+ res.status(500).json({ error: 'Terjadi kesalahan server.' });
1910
+ }
1911
+ });
1912
+
1913
+ Readable.fromEventEmitter = function (emitter, events) {
1914
+ const readable = new Readable({
1915
+ read() {}
1916
+ });
1917
+
1918
+ const onData = (data) => {
1919
+ readable.push(data);
1920
+ };
1921
+ const onEnd = () => {
1922
+ readable.push(null);
1923
+ };
1924
+ const onError = (err) => {
1925
+ readable.emit('error', err);
1926
+ };
1927
+
1928
+ emitter.on(events[0], onData);
1929
+ emitter.on(events[1], onEnd);
1930
+ emitter.on(events[2], onError);
1931
+
1932
+ return readable;
1933
+ };
1934
+
1935
+ const iask = {
1936
+ turndownService: new TurndownService(),
1937
+
1938
+ request(query, mode, options) {
1939
+ if (typeof query === 'object') {
1940
+ return query;
1941
+ }
1942
+ return { q: query, mode, ...options };
1943
+ },
1944
+
1945
+ eventx(query) {
1946
+ const pipe = new EventEmitter();
1947
+ const getQueryString = () => {
1948
+ const params = new URLSearchParams(query);
1949
+ return params.toString();
1950
+ };
1951
+ return { query, pipe, getQueryString };
1952
+ },
1953
+
1954
+ parseChunk(message) {
1955
+ try {
1956
+ const data = JSON.parse(message);
1957
+ const diff = data.pop();
1958
+ let content = '';
1959
+ let stop = false;
1960
+
1961
+ if (diff?.e?.[0]?.[1]?.data) {
1962
+ content = diff.e[0][1].data.replace(/<br\/>/g, '\n');
1963
+ console.log(content);
1964
+ }
1965
+
1966
+ if (diff?.response?.rendered?.[2]?.[1]?.[4]?.[4]) {
1967
+ content = this.turndownService.turndown(diff.response.rendered[2][1][4][4]);
1968
+ stop = true;
1969
+ console.log(content);
1970
+ }
1971
+
1972
+ return { content, stop };
1973
+ } catch (error) {
1974
+ console.error(error);
1975
+ return { content: '', stop: true };
1976
+ }
1977
+ },
1978
+
1979
+ inspect(response) {
1980
+ const $ = cheerio.load(response.data);
1981
+ const phxElement = $('[id^="phx-"]').first();
1982
+ const joinMessage = JSON.stringify([
1983
+ null,
1984
+ null,
1985
+ `lv:${phxElement.attr('id')}`,
1986
+ 'phx_join',
1987
+ {
1988
+ url: response.request.res.responseUrl,
1989
+ session: phxElement.attr('data-phx-session'),
1990
+ },
1991
+ ]);
1992
+ const csrfToken = $('meta[name="csrf-token"]').attr('content');
1993
+ return { joinMessage, csrfToken };
1994
+ },
1995
+
1996
+ async cws(queryString, jar) {
1997
+ const client = wrapper(axios.create({ jar }));
1998
+ try {
1999
+ const response = await client.get(`https://iask.ai?${queryString}`);
2000
+ const { joinMessage, csrfToken } = this.inspect(response);
2001
+ const cookies = await jar.getCookieString('https://iask.ai');
2002
+ console.log(cookies);
2003
+
2004
+ const ws = new WebSocket(`wss://iask.ai/live/websocket?_csrf_token=${csrfToken}&vsn=2.0.0`, {
2005
+ headers: {
2006
+ 'Cookie': cookies
2007
+ }
2008
+ });
2009
+
2010
+ await new Promise((resolve, reject) => {
2011
+ ws.on('open', () => {
2012
+ console.log('Websocket berhasil terhubung...');
2013
+ ws.send(joinMessage);
2014
+ resolve();
2015
+ });
2016
+ ws.on('error', (err) => {
2017
+ console.error('Tidak dapat terhubung ke WebSocket:', err);
2018
+ reject(err);
2019
+ });
2020
+ });
2021
+
2022
+ return ws;
2023
+ } catch (error) {
2024
+ console.error(error);
2025
+ throw error;
2026
+ }
2027
+ },
2028
+
2029
+ async handleJoin(event) {
2030
+ try {
2031
+ const jar = new CookieJar();
2032
+ const ws = await this.cws(event.getQueryString(), jar);
2033
+ const pipe = event.pipe;
2034
+
2035
+ ws.on('message', (message) => {
2036
+ console.log(message.toString());
2037
+ const { content, stop } = this.parseChunk(message.toString());
2038
+ if (content !== '') {
2039
+ pipe.emit('data', content);
2040
+ }
2041
+ if (stop) {
2042
+ pipe.emit('end');
2043
+ ws.close();
2044
+ }
2045
+ });
2046
+
2047
+ ws.on('close', () => {
2048
+ console.log('Websocket terputus...');
2049
+ pipe.emit('end');
2050
+ });
2051
+
2052
+ ws.on('error', (err) => {
2053
+ console.error(err);
2054
+ pipe.emit('error', err);
2055
+ });
2056
+ } catch (error) {
2057
+ console.error(error);
2058
+ event.pipe.emit('error', error);
2059
+ }
2060
+ },
2061
+
2062
+ dispatcher: new EventEmitter(),
2063
+
2064
+ setupDispatcher() {
2065
+ this.dispatcher.on('JoinEvent', (event) => this.handleJoin(event));
2066
+ },
2067
+
2068
+ ask: async (query, mode = 'question', options = {}) => {
2069
+ const summon = iask.request(query, mode, options);
2070
+ const event = iask.eventx(summon);
2071
+ iask.dispatcher.emit('JoinEvent', event);
2072
+ return Readable.fromEventEmitter(event.pipe, ['data', 'end', 'error']);
2073
+ },
2074
+
2075
+ init() {
2076
+ this.setupDispatcher();
2077
+ }
2078
+ };
2079
+
2080
+ async function Ask(query, mode = 'question', options = { detail_level: 'detailed' }) {
2081
+ try {
2082
+ iask.init();
2083
+ const stream = await iask.ask(query, mode, options);
2084
+
2085
+ // Return a Promise to properly handle stream events
2086
+ return new Promise((resolve, reject) => {
2087
+ let result = '';
2088
+
2089
+ stream.on('data', (chunk) => {
2090
+ result += chunk;
2091
+ });
2092
+
2093
+ stream.on('end', () => {
2094
+ console.log('Permintaan ke Websocket iASK berhasil..');
2095
+ console.log('Result:', result);
2096
+ resolve({ result }); // Resolve with the accumulated result
2097
+ });
2098
+
2099
+ stream.on('error', (err) => {
2100
+ console.error(err);
2101
+ reject({ err }); // Reject on error
2102
+ });
2103
+ });
2104
+
2105
+ } catch (error) {
2106
+ console.error(error);
2107
+ throw error; // Re-throw error to ensure it's caught in the calling context
2108
+ }
2109
+ }
2110
+
2111
+ app.post('/ask', async (req, res) => {
2112
+ const { query, mode = 'question', ...options } = req.body;
2113
+
2114
+ if (!query) {
2115
+ return res.status(400).json({ error: 'Query parameter is required' });
2116
+ }
2117
+
2118
+ try {
2119
+ const result = await Ask(query, mode, options);
2120
+ // Send response as JSON
2121
+ return res.status(200).json(result);
2122
+ } catch (error) {
2123
+ console.error(error);
2124
+ return res.status(500).json({ error: 'Failed to handle the query' });
2125
+ }
2126
+ });
2127
+
2128
+ app.get('/ask', async (req, res) => {
2129
+ const { query, mode = 'question', ...options } = req.query;
2130
+
2131
+ if (!query) {
2132
+ return res.status(400).json({ error: 'Query parameter is required' });
2133
+ }
2134
+
2135
+ try {
2136
+ const result = await Ask(query, mode, options);
2137
+ // Send response as JSON
2138
+ return res.status(200).json(result);
2139
+ } catch (error) {
2140
+ console.error(error);
2141
+ return res.status(500).json({ error: 'Failed to handle the query' });
2142
+ }
2143
+ });
2144
+
2145
+ const PORT = process.env.PORT || 7860;
2146
+
2147
+ app.listen(PORT, async () => {
2148
+ console.log(`Server running on port ${PORT}`);
2149
+ await utils.initialize();
2150
+ });
2151
+
2152
+ process.on('SIGINT', async () => {
2153
+ await utils.close();
2154
+ process.exit(0);
2155
+ });
favicon.ico ADDED
foliokanan.jpg ADDED
foliokiri.jpg ADDED
magernulis1.jpg ADDED
package.json ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "hd-bart-generator-api",
3
+ "version": "2.1.0",
4
+ "description": "API for generating HD Bart images using Playwright",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node app.js",
9
+ "dev": "nodemon app.js"
10
+ },
11
+ "keywords": ["playwright", "express", "bart-generator", "API", "HD"],
12
+ "author": "Putu",
13
+ "license": "MIT",
14
+ "dependencies": {
15
+ "express": "latest",
16
+ "playwright": "latest",
17
+ "cors": "latest",
18
+ "dotenv": "latest",
19
+ "axios": "latest",
20
+ "os": "latest",
21
+ "sharp": "latest",
22
+ "node-fetch": "latest",
23
+ "child_process": "latest",
24
+ "path": "latest",
25
+ "axios-cookiejar-support": "latest",
26
+ "cheerio": "latest",
27
+ "tough-cookie": "latest",
28
+ "turndown": "latest",
29
+ "ws": "latest",
30
+ "stream": "latest",
31
+ "events": "latest"
32
+
33
+ },
34
+ "devDependencies": {
35
+ "nodemon": "latest"
36
+ }
37
+ }
sebelumkanan.jpg ADDED
sebelumkiri.jpg ADDED