File size: 9,991 Bytes
44c9fcd
095af13
9008ed0
e868aa0
095af13
 
 
 
9008ed0
095af13
3667424
7180a58
 
095af13
 
 
 
178b776
 
 
 
095af13
9008ed0
64dcc49
 
 
 
 
 
 
 
 
 
 
 
 
9008ed0
44c9fcd
095af13
 
 
 
 
64dcc49
 
 
095af13
 
 
 
 
 
 
 
 
 
 
 
9008ed0
 
 
095af13
44c9fcd
095af13
9008ed0
095af13
 
59f11b4
095af13
 
 
 
 
 
9008ed0
095af13
 
 
44c9fcd
 
21d123c
 
44c9fcd
 
21d123c
44c9fcd
3667424
44c9fcd
21d123c
9008ed0
44c9fcd
21d123c
 
 
 
 
 
 
64dcc49
9008ed0
 
 
 
 
 
 
64dcc49
9008ed0
 
 
 
64dcc49
 
9008ed0
64dcc49
9008ed0
 
 
 
 
 
 
 
3667424
 
 
 
 
afb83df
 
3667424
 
 
 
 
 
 
 
 
f91f35a
2bfc655
f91f35a
 
 
 
 
 
 
 
e7ec152
 
6179fa0
9008ed0
 
6179fa0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8fcec76
6179fa0
 
 
 
 
 
8fcec76
6179fa0
 
 
 
 
8fcec76
6179fa0
 
 
 
 
 
 
 
 
 
 
 
 
095af13
 
 
 
4ca849c
095af13
 
44c9fcd
 
 
 
 
 
 
 
095af13
 
 
 
 
 
 
4ca849c
ceeb8a8
4ca849c
095af13
 
4ca849c
095af13
 
 
 
 
4ca849c
 
095af13
 
 
 
 
 
 
 
 
 
8c53df2
3667424
91906f9
aca9c68
 
 
 
 
 
91906f9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3667424
 
 
 
 
 
 
 
 
468a2d5
3667424
 
 
 
 
 
 
 
 
 
 
 
57f2510
0738a9b
57f2510
468a2d5
3667424
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
const fs = require('fs')
const os = require('os')
const util = require('util')
const axios = require('axios')
const bytes = require('bytes')
const sharp = require('sharp')
const morgan = require('morgan')
const express = require('express')
const cp = require('child_process')
const PDFDocument = require('pdfkit')
const playwright = require('playwright-extra')
// const stealth = require('puppeteer-extra-plugin-stealth')
// playwright.chromium.use(stealth())

const app = express()
app.set('json spaces', 4)
app.use(morgan('dev'))

const limitSize = '500mb'
app.use(express.json({ limit: limitSize }))
app.use(express.urlencoded({ extended: true, limit: limitSize }))

const tmpFolder = os.tmpdir()
app.use((req, res, next) => {
	fs.readdirSync(tmpFolder).map(file => {
		file = `${tmpFolder}/${file}`
		let stats = fs.statSync(file)
		if (!stats.isFile()) return
		if (Date.now() - stats.mtimeMs >= 1000 * 60 * 30) {
			fs.unlinkSync(file)
			console.log('Deleted file', file)
		}
	})
	next()
})

app.use('/file', express.static(tmpFolder))

app.all('/', (req, res) => {
	const status = {}
	const used = process.memoryUsage()
	for (let key in used) status[key] = formatSize(used[key])
	
	const disk = cp.execSync('du -sh').toString().split('M')[0]
	status.diskUsage = `${disk} MB`
	
	const totalmem = os.totalmem()
	const freemem = os.freemem()
	status.memoryUsage = `${formatSize(totalmem - freemem)} / ${formatSize(totalmem)}`
	
	res.json({
		creator: '@rippanteq7',
		message: 'Hello World',
		uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4],
		status
	})
})

app.all('/imagetopdf', async (req, res) => {
	if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
	
	try {
		console.log(new Date().toLocaleString('id', { timeZone: 'Asia/Jakarta' }), '\n', req.body)
		const { images } = req.body
		if (!(images && Array.isArray(images))) return res.json({ success: false, message: 'Required an array image url' })
		
		const buffer = await toPDF(images)
		res.setHeader('Content-Disposition', `attachment; filename=${Math.random().toString(36).slice(2)}.pdf`)
		res.setHeader('Content-Type', 'application/pdf')
		res.setHeader('Content-Length', buffer.byteLength)
		res.send(buffer)
	} catch (e) {
		console.log(e)
		e = String(e)
		res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e })
	}
})

app.all('/webp2png', async (req, res) => {
	if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
	
	try {
		const { file } = req.body
		if (!(file && isBase64(file))) return res.json({ success: false, message: 'Payload body file must be filled in base64 format' })
		
		const fileBuffer = Buffer.from(file, 'base64')
		const fileName = `${Math.random().toString(36).slice(2)}.png`
		const convertData = await sharp(fileBuffer).png().toBuffer()
		
		await fs.promises.writeFile(`${tmpFolder}/${fileName}`, convertData)
		res.send(`https://${req.get('host')}/file/${fileName}`)
	} catch (e) {
		console.log(e)
		e = String(e)
		res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e })
	}
})

app.all(['/webp2gif', '/webp2mp4'], async (req, res) => {
	if (!['POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
	
	try {
		const { file } = req.body
		if (!(file && isBase64(file))) return res.json({ success: false, message: 'Payload body file must be filled in base64 format' })
		
		const fileBuffer = Buffer.from(file, 'base64')
		const fileName = `${Math.random().toString(36).slice(2)}.webp`
		const filePath = `${tmpFolder}/${fileName}`
		await fs.promises.writeFile(filePath, fileBuffer)
		
		const exec = util.promisify(cp.exec).bind(cp)
		await exec(`convert ${filePath} ${filePath.replace('.webp', '.gif')}`)
		if (/gif/.test(req.path)) return res.send(`https://${req.get('host')}/file/${fileName.replace('.webp', '.gif')}`)
		
		await exec(`ffmpeg -i ${filePath.replace('.webp', '.gif')} -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" ${filePath.replace(/.webp|.gif/g, '')}.mp4`)
		res.send(`https://${req.get('host')}/file/${fileName.replace('.webp', '.mp4')}`)
	} catch (e) {
		console.log(e)
		e = String(e)
		res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e })
	}
})

app.all(['/enhance', '/hd', '/upscale'], async (req, res) => {
	if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
	
	try {
		const { url } = req.method !== 'GET' ? req.body : req.query
		if (!url) return res.json({ success: false, message: 'Required parameter url' })
		
		const result = await enhanceImage(url)
		res.json({ success: true, result })
	} catch (e) {
		console.log(e)
		e = String(e)
		res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e })
	}
})

app.all('/animelast', async (req, res) => {
        const result = await scrapeAnimeInfo();       
        res.json({
            creator: '@Kyouka',
            message: 'Success',
            uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4],
            result
        });
});



app.all('/stablediff/illusion', async (req, res) => {
	if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
	
	try {
		const {
			prompt,
			negative_prompt = 'low quality',
			image_url,
			num_inference_steps = 25,
			controlnet_conditioning_scale = 1
		} = req.method !== 'GET' ? req.body : req.query
		
		if (!(prompt && image_url)) return res.json({ success: false, message: 'Required parameter prompt & image_url' })
		
		const headers = {
			'Content-Type': 'application/json',
			Authorization: `Key ${process.env.falAIKey}`
		}
		
		const { detail, response_url } = await (await fetch('https://54285744-illusion-diffusion.gateway.alpha.fal.ai/fal/queue/submit', {
			method: 'POST',
			body: JSON.stringify({
				prompt, negative_prompt, image_url,
				num_inference_steps, controlnet_conditioning_scale
			}),
			headers
		})).json()
		if (detail) return res.json({ success: false, message: detail })
		
		let retry = 0
		while (true) {
			await new Promise(resolve => setTimeout(resolve, 2500))
			const prediction = await (await fetch(response_url, { headers })).json()
			console.log(prediction)
			if (retry > 10) return res.json({ success: false, message: prediction.detail || 'Max retry has reached' })
			if (prediction.image) return res.json({ success: true, result: prediction })
			retry += 1
		}
		
	} catch (e) {
		console.log(e)
		e = String(e)
		res.status(500).json({ error: true, message: e === '[object Object]' ? 'Internal Server Error' : e })
	}
})

const PORT = process.env.PORT || 7860
app.listen(PORT, () => console.log('App running on port', PORT))

function formatSize(num) {
	return bytes(+num || 0, { unitSeparator: ' ' })
}

function isBase64(str) {
	try {
		return btoa(atob(str)) === str
	} catch {
		return false
	}
}

function toPDF(urls) {
	return new Promise(async (resolve, reject) => {
		try {
			if (!Array.isArray(urls)) urls = [urls]
			const doc = new PDFDocument({ margin: 0, size: 'A4' })
			const buffers = []
			
			for (let i = 0; i < urls.length; i++) {
				const response = await fetch(urls[i], { headers: { referer: urls[i] }})
				if (!response.ok) continue
				
				const type = response.headers.get('content-type')
				if (!/image/.test(type)) continue
				
				let buffer = Buffer.from(await response.arrayBuffer())
				if (/gif|webp/.test(type)) buffer = await sharp(buffer).png().toBuffer()
				
				doc.image(buffer, 0, 0, { fit: [595.28, 841.89], align: 'center', valign: 'center' })
				if (urls.length !== i + 1) doc.addPage()
			}
			
			doc.on('data', (chunk) => buffers.push(chunk))
			doc.on('end', () => resolve(Buffer.concat(buffers)))
			doc.on('error', reject)
			doc.end()
		} catch (e) {
			console.log(e)
			reject(e)
		}
	})
}

async function scrapeAnimeInfo() {
    const browser = await playwright.chromium.launch({
		headless: true,
		executablePath: '/usr/bin/chromium',
		args: ['--no-sandbox']
	})
  
    const page = await browser.newPage();
    const url = 'https://154.26.137.28/rilisan-anime-terbaru/';

    await page.goto(url);
    await page.waitForSelector('.postbody');

    const articlesInfo = await page.$$eval('.postbody .is-anime', articles => {
        return articles.map(article => {
            const title = article.querySelector('h2').textContent.trim();
            const thumbnailUrl = article.querySelector('img').src;
            const uploadTime = article.querySelector('span x-ts').textContent.trim();
            const episodeUrl = article.querySelector('a').href;

            return {
                title,
                thumbnailUrl,
                uploadTime,
                episodeUrl
            };
        });
    });

    await browser.close();
    
    return articlesInfo;
}

async function enhanceImage(url) {
	const browser = await playwright.chromium.launch({
		headless: true,
		executablePath: '/usr/bin/chromium',
		args: ['--no-sandbox']
	})
	
	const page = await browser.newPage()
	await page.goto('https://snapedit.app/id/enhance/upload')
	await page.waitForLoadState('domcontentloaded')
	
	const arrayBuffer = await (await fetch(url)).arrayBuffer()
	page.on('filechooser', (fileChooser) => {
		const fileObject = {
			name: 'file.jpg',
			mimeType: 'image/jpg',
			buffer: Buffer.from(arrayBuffer)
		}
		fileChooser.setFiles([fileObject])
	})
	
	await page.getByRole('button', { name: 'Unggah gambar', exact: true }).click()
	const response = await page.waitForResponse(res => {
		console.log(res.url())
		return res.url().includes('api/enhance/v1')
	}, { timeout: 60 * 1000 })
	const json = await response.json()
	
	await browser.close()
	return json
}