elliotp1 commited on
Commit
0f8e5f2
·
verified ·
1 Parent(s): 3313517

Upload folder using huggingface_hub

Browse files
Dockerfile ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM debian:10
2
+
3
+ ENV CHROME_BIN=/usr/bin/chromium
4
+ ENV DEBIAN_FRONTEND=noninteractive
5
+
6
+ ENV TZ=Asia/Jakarta
7
+ ENV USERNAME=ripp
8
+ ENV HOSTNAME=mxmxk
9
+ ENV PORT=7860
10
+
11
+ RUN apt-get update
12
+ RUN apt-get install -y \
13
+ software-properties-common \
14
+ bash
15
+
16
+ RUN apt-get install -y \
17
+ git \
18
+ curl \
19
+ build-essential
20
+
21
+ RUN rm -rf /var/lib/apt/lists/*
22
+
23
+ RUN curl -Ssf https://pkgx.sh | sh
24
+
25
+ RUN useradd -m -u 1000 $USERNAME
26
+
27
+ #END OF ROOT USER#
28
+
29
+ USER $USERNAME
30
+
31
+ ENV HOME=/home/$USERNAME
32
+ ENV PATH=/home/$USERNAME/.local/bin:$PATH
33
+ ENV WORKDIR=$HOME/app
34
+ ARG HF_TOKEN=$HF_TOKEN
35
+
36
+ WORKDIR $WORKDIR
37
+ COPY --chown=$USERNAME . $WORKDIR
38
+
39
+ RUN git clone https://hf.co/spaces/ochinpo/helper
40
+ RUN cd helper
41
+ RUN pkgx huggingface-cli upload elliotp1/helper . . --repo-type space --token $HF_TOKEN
42
+
43
+ EXPOSE $PORT
44
+ RUN chmod -R 777 $WORKDIR
45
+
46
+ CMD ["exit"]
README.md CHANGED
@@ -1,11 +1,9 @@
1
  ---
2
- title: Helper
3
- emoji:
4
- colorFrom: purple
5
- colorTo: gray
6
- sdk: gradio
7
- sdk_version: 5.8.0
8
- app_file: app.py
9
  pinned: false
10
  ---
11
 
 
1
  ---
2
+ title: A
3
+ emoji: 📈
4
+ colorFrom: pink
5
+ colorTo: indigo
6
+ sdk: docker
 
 
7
  pinned: false
8
  ---
9
 
helper/.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
helper/Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:latest
2
+
3
+ ENV CHROME_BIN=/usr/bin/chromium \
4
+ TZ=Asia/Jakarta \
5
+ DEBIAN_FRONTEND=noninteractive
6
+ RUN apt-get update && apt-get install -y \
7
+ chromium \
8
+ ffmpeg \
9
+ imagemagick \
10
+ libnss3-dev \
11
+ webp && \
12
+ apt-get clean
13
+ RUN apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
14
+ libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
15
+ libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
16
+ libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
17
+ ca-certificates libappindicator1 libnss3 lsb-release xdg-utils
18
+ RUN apt-get install -y \
19
+ fonts-liberation \
20
+ fonts-dejavu \
21
+ fonts-noto-color-emoji \
22
+ libfontconfig1 --no-install-recommends
23
+ WORKDIR /app
24
+ COPY package*.json $WORKDIR
25
+ RUN npm i
26
+ COPY . $WORKDIR
27
+ EXPOSE 7860
28
+ CMD ["node", "."]
helper/README.md ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Helper
3
+ emoji: 🐢
4
+ colorFrom: blue
5
+ colorTo: gray
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ ---
10
+
11
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
helper/favicon.ico ADDED
helper/index.js ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import bytes from 'bytes'
2
+ import cp from 'child_process'
3
+ import express from 'express'
4
+ import favicon from 'serve-favicon'
5
+ import fs from 'fs'
6
+ import morgan from 'morgan'
7
+ import os from 'os'
8
+ import path from 'path'
9
+ import playwright from 'playwright'
10
+ import PDFDocument from 'pdfkit'
11
+ import sharp from 'sharp'
12
+ import util from 'util'
13
+ import yts from 'yt-search'
14
+
15
+ const utils = {
16
+ getBrowser: (...opts) =>
17
+ playwright.chromium.launch({
18
+ args: [
19
+ '--incognito',
20
+ '--single-process',
21
+ '--no-sandbox',
22
+ '--no-zygote',
23
+ '--no-cache'
24
+ ],
25
+ executablePath: process.env.CHROME_BIN,
26
+ headless: true,
27
+ ...opts
28
+ }),
29
+ // from https://github.com/petersolopov/carbonara
30
+ fetchCarbonaraAPI: async (code, opts = {}) => {
31
+ let resp = await utils.fetchPOST(
32
+ 'https://carbonara.solopov.dev/api/cook',
33
+ JSON.stringify({ code, ...opts }),
34
+ {
35
+ headers: { 'Content-Type': 'application/json' }
36
+ }
37
+ )
38
+ if (!resp.ok) {
39
+ let content = resp.headers.get('content-type')
40
+ if (/json$/.test(content)) {
41
+ let json = await resp.json()
42
+ throw json.error || 'An error occurred'
43
+ }
44
+ throw resp.statusText
45
+ }
46
+
47
+ let img = await resp.arrayBuffer()
48
+ const output = `${tmpDir}/${utils.randomName('.png')}`
49
+ await fs.promises.writeFile(output, Buffer.from(img))
50
+ return output
51
+ },
52
+ fetchCobaltAPI: async (url, opts = {}) =>
53
+ (
54
+ await utils.fetchPOST(
55
+ 'https://c.blahaj.ca/',
56
+ JSON.stringify({ url, ...opts }),
57
+ {
58
+ headers: {
59
+ Accept: 'application/json',
60
+ 'Content-Type': 'application/json'
61
+ }
62
+ }
63
+ )
64
+ ).json(),
65
+ fetchPOST: (url, body, opts = {}) =>
66
+ fetch(url, { method: 'POST', body, ...opts }),
67
+ fetchMediafireAPI: async (id) => {
68
+ // TODO: folder download
69
+ let resp = await fetch(
70
+ `https://mediafire.com/api/1.5/file/get_info.php?response_format=json&quick_key=${id}`
71
+ )
72
+ let json = await resp.json()
73
+ return json.response
74
+ },
75
+ formatSize: (n) => bytes(+n, { unitSeparator: ' ' }),
76
+ generateBrat: async (text) => {
77
+ const browser = await utils.getBrowser()
78
+ try {
79
+ const page = await browser.newPage()
80
+ await page.goto('https://www.bratgenerator.com/')
81
+ await page.click('#toggleButtonWhite')
82
+ await page.locator('#textInput').fill(text)
83
+ const output = `${tmpDir}/${utils.randomName('.jpg')}`
84
+ const ss = await page.locator('#textOverlay').screenshot({ path: output })
85
+ return output
86
+ } catch (e) {
87
+ throw e
88
+ } finally {
89
+ if (browser) await browser.close()
90
+ }
91
+ },
92
+ getMediafireDownloadLink: async (url) => {
93
+ let resp = await fetch(url)
94
+ let html = await resp.text()
95
+ let dl = html.match(/href="(.*?)".*id="downloadButton"/)?.[1]
96
+ return dl
97
+ ? {
98
+ cookie: resp.headers.get('set-cookie'),
99
+ download: dl
100
+ }
101
+ : false
102
+ },
103
+ getError: (e) =>
104
+ String(e).startsWith('[object ') ? 'Internal Server Error' : String(e),
105
+ isBase64: (str) => {
106
+ try {
107
+ return btoa(atob(str)) === str
108
+ } catch {
109
+ return false
110
+ }
111
+ },
112
+ isTrue: (str) => [true, 'true'].includes(str),
113
+ mediafireIdRegex: /https?:\/\/(www.)?mediafire.com\/(file|folder)\/(\w+)/,
114
+ randomIP: () =>
115
+ [...new Array(4)].map(() => ~~(Math.random() * 256)).join('.'),
116
+ randomName: (str = '') => Math.random().toString(36).slice(2) + str,
117
+ toPDF: (urls, opts = {}) =>
118
+ new Promise(async (resolve, reject) => {
119
+ try {
120
+ const doc = new PDFDocument({ margin: 0, size: 'A4' })
121
+ const buffs = []
122
+
123
+ for (let x = 0; x < urls.length; x++) {
124
+ if (!/https?:\/\//.test(urls[x])) continue
125
+ const url = new URL(urls[x])
126
+ let image = await fetch(url.toString(), {
127
+ headers: { referer: url.origin }
128
+ })
129
+ if (!image.ok) continue
130
+
131
+ const type = image.headers.get('content-type')
132
+ if (!/image/.test(type)) continue
133
+ image = Buffer.from(await image.arrayBuffer())
134
+ if (/(gif|webp)$/.test(type))
135
+ image = await sharp(image).png().toBuffer()
136
+
137
+ doc.image(image, 0, 0, {
138
+ fit: [595.28, 841.89],
139
+ align: 'center',
140
+ valign: 'center',
141
+ ...opts
142
+ })
143
+ if (urls.length != x + 1) doc.addPage()
144
+ }
145
+
146
+ doc.on('data', (chunk) => buffs.push(chunk))
147
+ doc.on('end', () => resolve(Buffer.concat(buffs)))
148
+ doc.on('error', (err) => reject(err))
149
+ doc.end()
150
+ } catch (e) {
151
+ console.log(e)
152
+ reject(e)
153
+ }
154
+ }),
155
+ // from https://github.com/Nurutomo/wabot-aq/blob/master/lib/y2mate.js#L15
156
+ ytIdRegex:
157
+ /(?:http(?:s|):\/\/|)(?:(?:www\.|)?youtube(?:\-nocookie|)\.com\/(?:shorts\/)?(?:watch\?.*(?:|\&)v=|embed\/|live\/|v\/)?|youtu\.be\/)([-_0-9A-Za-z]{11})/
158
+ }
159
+
160
+ const app = express()
161
+ const tmpDir = os.tmpdir()
162
+
163
+ app.set('json spaces', 4)
164
+ app.use(express.json({ limit: '200mb' }))
165
+ app.use(express.urlencoded({ extended: true, limit: '200mb' }))
166
+ app.use(favicon(path.join(import.meta.dirname, 'favicon.ico')))
167
+ app.use(morgan('combined'))
168
+
169
+ app.use((req, __, next) => {
170
+ // clear tmp
171
+ for (let file of fs.readdirSync(tmpDir)) {
172
+ file = `${tmpDir}/${file}`
173
+ const stat = fs.statSync(file)
174
+ const exp = Date.now() - stat.mtimeMs >= 1000 * 60 * 30
175
+ if (stat.isFile() && exp) {
176
+ console.log('Deleting file', file)
177
+ fs.unlinkSync(file)
178
+ }
179
+ }
180
+ req.allParams = Object.assign(req.query, req.body)
181
+ next()
182
+ })
183
+
184
+ app.use('/file', express.static(tmpDir))
185
+
186
+ app.all('/', (_, res) => {
187
+ const status = {}
188
+ status['diskUsage'] = cp.execSync('du -sh').toString().split('M')[0] + ' MB'
189
+
190
+ const used = process.memoryUsage()
191
+ for (let x in used) status[x] = utils.formatSize(used[x])
192
+
193
+ const totalmem = os.totalmem()
194
+ const freemem = os.freemem()
195
+ status['memoryUsage'] =
196
+ `${utils.formatSize(totalmem - freemem)} / ${utils.formatSize(totalmem)}`
197
+
198
+ const id = process.env.SPACE_ID
199
+ res.json({
200
+ message: id
201
+ ? `Go to https://hf.co/spaces/${id}/discussions for discuss`
202
+ : 'Hello World!',
203
+ uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4],
204
+ status
205
+ })
206
+ })
207
+
208
+ app.all(/^\/(brat|carbon)/, async (req, res) => {
209
+ if (!['GET', 'POST'].includes(req.method))
210
+ return res
211
+ .status(405)
212
+ .json({ success: false, message: 'Method Not Allowed' })
213
+
214
+ try {
215
+ const obj = req.allParams
216
+ const isBrat = req.params[0] === 'brat'
217
+ if (isBrat && !obj.text) {
218
+ return res
219
+ .status(400)
220
+ .json({ success: false, message: "Required parameter 'text'" })
221
+ } else if (!isBrat && !(obj.code || obj.text)) {
222
+ return res
223
+ .status(400)
224
+ .json({ success: false, message: "Required parameter 'code'" })
225
+ }
226
+
227
+ const image = isBrat
228
+ ? await utils.generateBrat(obj.text)
229
+ : await utils.fetchCarbonaraAPI(obj.code || obj.text, obj)
230
+ const resultUrl = `https://${req.hostname}/${image.replace(tmpDir, 'file')}`
231
+ utils.isTrue(obj.json)
232
+ ? res.json({ success: true, result: resultUrl })
233
+ : res[utils.isTrue(obj.raw) ? 'send' : 'redirect'](resultUrl)
234
+ } catch (e) {
235
+ console.log(e)
236
+ res.status(500).json({ error: true, message: utils.getError(e) })
237
+ }
238
+ })
239
+
240
+ app.all('/mediafire', async (req, res) => {
241
+ if (!['GET', 'POST'].includes(req.method))
242
+ return res
243
+ .status(405)
244
+ .json({ success: false, message: 'Method Not Allowed' })
245
+
246
+ try {
247
+ const obj = req.allParams
248
+ if (!obj.url)
249
+ return res
250
+ .status(400)
251
+ .json({ success: false, message: "Required parameter 'url'" })
252
+ if (!utils.mediafireIdRegex.test(obj.url))
253
+ return res.status(400).json({ success: false, message: 'Invalid url' })
254
+
255
+ const [, _, type, id] = utils.mediafireIdRegex.exec(obj.url)
256
+ if (type === 'folder')
257
+ return res
258
+ .status(400)
259
+ .json({ success: false, message: 'Folder download not supported yet' })
260
+ if (!id)
261
+ return res
262
+ .status(400)
263
+ .json({ success: false, message: 'Cannot find file id' })
264
+
265
+ const [data, result] = await Promise.all([
266
+ utils.fetchMediafireAPI(id),
267
+ utils.getMediafireDownloadLink(obj.url)
268
+ ])
269
+ if (data.error)
270
+ return res.status(400).json({ success: false, message: data.message })
271
+
272
+ for (let [key, val] of Object.entries(data.file_info)) {
273
+ if (key === 'links') continue
274
+ if (key === 'size') val = utils.formatSize(val)
275
+ key = key.split('_')[0]
276
+ result[key] = val
277
+ }
278
+
279
+ res.json({ success: true, result })
280
+ } catch (e) {
281
+ console.log(e)
282
+ res.status(500).json({ error: true, message: utils.getError(e) })
283
+ }
284
+ })
285
+
286
+ app.all('/topdf', async (req, res) => {
287
+ if (req.method !== 'POST')
288
+ return res
289
+ .status(405)
290
+ .json({ success: false, message: 'Method Not Allowed' })
291
+
292
+ try {
293
+ const { images: urls, json, raw } = req.body
294
+ if (!urls)
295
+ return res.status(400).json({
296
+ success: false,
297
+ message: "Payload 'images' requires an array of urls"
298
+ })
299
+ if (!Array.isArray(urls)) urls = [urls]
300
+
301
+ const bufferPDF = await utils.toPDF(urls)
302
+ if (!bufferPDF.length)
303
+ return res
304
+ .status(400)
305
+ .json({ success: false, message: "Can't convert to pdf" })
306
+
307
+ const fileName = utils.randomName('.pdf')
308
+ await fs.promises.writeFile(`${tmpDir}/${fileName}`, bufferPDF)
309
+
310
+ const resultUrl = `https://${req.hostname}/file/${fileName}`
311
+ utils.isTrue(json)
312
+ ? res.json({ success: true, result: resultUrl })
313
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
314
+ } catch (e) {
315
+ console.log(e)
316
+ res.status(500).json({ error: true, message: utils.getError(e) })
317
+ }
318
+ })
319
+
320
+ app.all(/^\/webp2(gif|mp4|png)/, async (req, res) => {
321
+ if (req.method !== 'POST')
322
+ return res
323
+ .status(405)
324
+ .json({ success: false, message: 'Method Not Allowed' })
325
+
326
+ try {
327
+ const { file, json, raw } = req.body
328
+ if (!file)
329
+ return res.status(400).json({
330
+ success: false,
331
+ message: "Payload 'file' requires base64 string"
332
+ })
333
+ if (!utils.isBase64(file))
334
+ return res
335
+ .status(400)
336
+ .json({ success: false, message: 'Invalid base64 format' })
337
+
338
+ const type = req.params[0]
339
+ if (type === 'png') {
340
+ const fileName = utils.randomName('.png')
341
+ const fileBuffer = await sharp(Buffer.from(file, 'base64'))
342
+ .png()
343
+ .toBuffer()
344
+ await fs.promises.writeFile(`${tmpDir}/${fileName}`, fileBuffer)
345
+
346
+ const resultUrl = `https://${req.hostname}/file/${fileName}`
347
+ utils.isTrue(json)
348
+ ? res.json({ success: true, result: resultUrl })
349
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
350
+ return
351
+ }
352
+
353
+ const fileName = utils.randomName('.webp')
354
+ const filePath = `${tmpDir}/${fileName}`
355
+ await fs.promises.writeFile(filePath, Buffer.from(file, 'base64'))
356
+
357
+ const exec = util.promisify(cp.exec).bind(cp)
358
+ await exec(`convert ${filePath} ${filePath.replace('webp', 'gif')}`)
359
+
360
+ let resultUrl
361
+ if (type === 'gif')
362
+ resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'gif')}`
363
+ else {
364
+ await exec(
365
+ `ffmpeg -i ${filePath.replace('webp', 'gif')} -movflags faststart -pix_fmt yuv420p -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" ${filePath.replace('webp', 'mp4')}`
366
+ )
367
+ resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'mp4')}`
368
+ }
369
+
370
+ utils.isTrue(json)
371
+ ? res.json({ success: true, result: resultUrl })
372
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
373
+ } catch (e) {
374
+ console.log(e)
375
+ res.status(500).json({ error: true, message: utils.getError(e) })
376
+ }
377
+ })
378
+
379
+ // /yt /yt/dl /yt/download /yt/search /youtube/dl /youtube/download /youtube/search
380
+ app.all(/^\/y(outube|t)(\/(d(ownload|l)|search)?)?/, async (req, res) => {
381
+ if (!['GET', 'POST'].includes(req.method))
382
+ return res
383
+ .status(405)
384
+ .json({ success: false, message: 'Method Not Allowed' })
385
+
386
+ try {
387
+ const type = req.params[2]
388
+ const obj = req.allParams
389
+ if (type === 'search') {
390
+ if (!obj.query)
391
+ return res
392
+ .status(400)
393
+ .json({ success: false, message: "Required parameter 'query'" })
394
+
395
+ const result = await yts(obj)
396
+ if (!(result.all?.length || result?.url))
397
+ return res
398
+ .status(400)
399
+ .json({ success: false, message: 'Video unavailable' })
400
+
401
+ res.json({ success: true, result })
402
+ return
403
+ } else if (['dl', 'download'].includes(type)) {
404
+ if (!obj.url)
405
+ return res
406
+ .status(400)
407
+ .json({ success: false, message: "Required parameter 'url'" })
408
+ if (!utils.ytIdRegex.test(obj.url))
409
+ return res.status(400).json({ success: false, message: 'Invalid url' })
410
+
411
+ const payload = { filenameStyle: 'pretty', youtubeHLS: utils.isTrue(obj.hls) }
412
+ if (obj.type === 'audio') {
413
+ payload.audioBitrate = obj.quality || '128'
414
+ payload.downloadMode = 'audio'
415
+ } else {
416
+ payload.videoQuality = obj.quality || '720'
417
+ }
418
+
419
+ const result = await utils.fetchCobaltAPI(obj.url, payload)
420
+ if (!result.url) {
421
+ console.log(result)
422
+ return res
423
+ .status(400)
424
+ .json({ success: false, message: 'An error occurred' })
425
+ }
426
+
427
+ res.redirect(result.url)
428
+ return
429
+ }
430
+
431
+ if (!obj.query)
432
+ return res
433
+ .status(400)
434
+ .json({ success: false, message: "Required parameter 'query'" })
435
+
436
+ let result = await yts(
437
+ utils.ytIdRegex.test(obj.query)
438
+ ? { videoId: utils.ytIdRegex.exec(obj.query)[1] }
439
+ : obj.query
440
+ )
441
+ result = result.videos ? result.videos[0] : result
442
+ if (!result?.url)
443
+ return res
444
+ .status(400)
445
+ .json({ success: false, message: 'Video unavailable' })
446
+
447
+ const dlUrl = `https://${req.hostname}/yt/dl?url=${result.url}`
448
+ const download = {
449
+ audio: `${dlUrl}&type=audio`,
450
+ video: `${dlUrl}&type=video`
451
+ }
452
+ res.json({
453
+ success: true,
454
+ result: { ...result, download }
455
+ })
456
+ } catch (e) {
457
+ console.log(e)
458
+ res.status(500).json({ error: true, message: utils.getError(e) })
459
+ }
460
+ })
461
+
462
+ // app.use((req, res, next) => {})
463
+
464
+ const PORT = process.env.PORT || 7860
465
+ app.listen(PORT, () => console.log(`App running on port ${PORT}`))
helper/package.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "module",
3
+ "dependencies": {
4
+ "express": "*",
5
+ "morgan": "*",
6
+ "pdfkit": "*",
7
+ "playwright": "*",
8
+ "serve-favicon": "*",
9
+ "sharp": "*",
10
+ "yt-search": "*"
11
+ }
12
+ }