rippanteq7 commited on
Commit
dc36d19
·
verified ·
1 Parent(s): bab12b0

Add mediafire downloader

Browse files
Files changed (1) hide show
  1. index.js +280 -124
index.js CHANGED
@@ -13,20 +13,28 @@ import util from 'util'
13
  import yts from 'yt-search'
14
 
15
  const utils = {
16
- getBrowser: (...opts) => playwright.chromium.launch({
17
- args: [
18
- '--incognito', '--single-process',
19
- '--no-sandbox', '--no-zygote', '--no-cache'
20
- ],
21
- executablePath: process.env.CHROME_BIN,
22
- headless: true,
23
- ...opts
24
- }),
 
 
 
 
25
  // from https://github.com/petersolopov/carbonara
26
  fetchCarbonaraAPI: async (code, opts = {}) => {
27
- let resp = await utils.fetchPOST('https://carbonara.solopov.dev/api/cook', JSON.stringify({ code, ...opts }), {
28
- headers: { 'Content-Type': 'application/json' }
29
- })
 
 
 
 
30
  if (!resp.ok) {
31
  let content = resp.headers.get('content-type')
32
  if (/json$/.test(content)) {
@@ -35,38 +43,58 @@ const utils = {
35
  }
36
  throw resp.statusText
37
  }
38
-
39
  let img = await resp.arrayBuffer()
40
  const output = `${tmpDir}/${utils.randomName('.png')}`
41
  await fs.promises.writeFile(output, Buffer.from(img))
42
  return output
43
  },
44
- fetchCobaltAPI: async (url, opts = {}) => (
45
- await utils.fetchPOST('https://cobalt-7.kwiatekmiki.com/api/json', JSON.stringify({ url, ...opts }), {
46
- headers: { Accept: 'application/json', 'Content-Type': 'application/json' }
47
- })
48
- ).json(),
49
- fetchPOST: (url, body, opts = {}) => fetch(url, { method: 'POST', body, ...opts }),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  formatSize: (n) => bytes(+n, { unitSeparator: ' ' }),
51
- generateBrat: async (text) => {
52
- const browser = await utils.getBrowser()
53
-
54
  try {
55
  const page = await browser.newPage()
56
  await page.goto('https://www.bratgenerator.com/')
57
  await page.click('#toggleButtonWhite')
58
  await page.locator('#textInput').fill(text)
59
  const output = `${tmpDir}/${utils.randomName('.jpg')}`
60
- const ss = await page.locator('#textOverlay')
61
- .screenshot({ path: output })
62
  return output
63
  } catch (e) {
64
  throw e
65
  } finally {
66
- if (browser) await browser.close()
67
- }
68
  },
69
- getError: (e) => String(e).startsWith('[object ') ? 'Internal Server Error' : String(e),
 
 
 
 
 
70
  isBase64: (str) => {
71
  try {
72
  return btoa(atob(str)) === str
@@ -75,39 +103,51 @@ const utils = {
75
  }
76
  },
77
  isTrue: (str) => [true, 'true'].includes(str),
78
- randomIP: () => [...new Array(4)].map(() => ~~(Math.random() * 256)).join('.'),
79
- randomName: (str = '') => (Math.random().toString(36).slice(2) + str),
80
- toPDF: (urls, opts = {}) => new Promise(async (resolve, reject) => {
81
- try {
82
- const doc = new PDFDocument({ margin: 0, size: 'A4' })
83
- const buffs = []
84
-
85
- for (let x = 0; x < urls.length; x++) {
86
- if (!/https?:\/\//.test(urls[x])) continue
87
- const url = new URL(urls[x])
88
- let image = await fetch(url.toString(), { headers: { referer: url.origin } })
89
- if (!image.ok) continue
90
-
91
- const type = image.headers.get('content-type')
92
- if (!/image/.test(type)) continue
93
- image = Buffer.from(await image.arrayBuffer())
94
- if (/(gif|webp)$/.test(type)) image = await sharp(image).png().toBuffer()
95
-
96
- doc.image(image, 0, 0, { fit: [595.28, 841.89], align: 'center', valign: 'center', ...opts })
97
- if (urls.length != x + 1) doc.addPage()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  }
99
-
100
- doc.on('data', (chunk) => buffs.push(chunk))
101
- doc.on('end', () => resolve(Buffer.concat(buffs)))
102
- doc.on('error', (err) => reject(err))
103
- doc.end()
104
- } catch (e) {
105
- console.log(e)
106
- reject(e)
107
- }
108
- }),
109
  // from https://github.com/Nurutomo/wabot-aq/blob/master/lib/y2mate.js#L15
110
- ytIdRegex: /(?:http(?:s|):\/\/|)(?:(?:www\.|)?youtube(?:\-nocookie|)\.com\/(?:shorts\/)?(?:watch\?.*(?:|\&)v=|embed\/|live\/|v\/)?|youtu\.be\/)([-_0-9A-Za-z]{11})/,
 
111
  }
112
 
113
  const app = express()
@@ -140,41 +180,105 @@ app.use('/file', express.static(tmpDir))
140
  app.all('/', (_, res) => {
141
  const status = {}
142
  status['diskUsage'] = cp.execSync('du -sh').toString().split('M')[0] + ' MB'
143
-
144
  const used = process.memoryUsage()
145
  for (let x in used) status[x] = utils.formatSize(used[x])
146
-
147
  const totalmem = os.totalmem()
148
  const freemem = os.freemem()
149
- status['memoryUsage'] = `${utils.formatSize(totalmem - freemem)} / ${utils.formatSize(totalmem)}`
150
-
 
151
  const id = process.env.SPACE_ID
152
  res.json({
153
- message: id ? `Go to https://hf.co/spaces/${id}/discussions for discuss` : 'Hello World!',
 
 
154
  uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4],
155
  status
156
  })
157
  })
158
 
159
  app.all(/^\/(brat|carbon)/, async (req, res) => {
160
- if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
161
-
 
 
 
162
  try {
163
  const obj = req.allParams
164
  const isBrat = req.params[0] === 'brat'
165
  if (isBrat && !obj.text) {
166
- return res.status(400).json({ success: false, message: 'Required parameter \'text\'' })
 
 
167
  } else if (!isBrat && !(obj.code || obj.text)) {
168
- return res.status(400).json({ success: false, message: 'Required parameter \'code\'' })
 
 
169
  }
170
-
171
- const image = isBrat ?
172
- await utils.generateBrat(obj.text) :
173
- await utils.fetchCarbonaraAPI(obj.code || obj.text, obj)
174
  const resultUrl = `https://${req.hostname}/${image.replace(tmpDir, 'file')}`
175
- utils.isTrue(obj.json) ?
176
- res.json({ success: true, result: resultUrl }) :
177
- res[utils.isTrue(obj.raw) ? 'send' : 'redirect'](resultUrl)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  } catch (e) {
179
  console.log(e)
180
  res.status(500).json({ error: true, message: utils.getError(e) })
@@ -182,23 +286,33 @@ app.all(/^\/(brat|carbon)/, async (req, res) => {
182
  })
183
 
184
  app.all('/topdf', async (req, res) => {
185
- if (req.method !== 'POST') return res.status(405).json({ success: false, message: 'Method Not Allowed' })
186
-
 
 
 
187
  try {
188
  const { images: urls, json, raw } = req.body
189
- if (!urls) return res.status(400).json({ success: false, message: 'Payload \'images\' requires an array of urls' })
 
 
 
 
190
  if (!Array.isArray(urls)) urls = [urls]
191
-
192
  const bufferPDF = await utils.toPDF(urls)
193
- if (!bufferPDF.length) return res.status(400).json({ success: false, message: 'Can\'t convert to pdf' })
194
-
 
 
 
195
  const fileName = utils.randomName('.pdf')
196
  await fs.promises.writeFile(`${tmpDir}/${fileName}`, bufferPDF)
197
-
198
  const resultUrl = `https://${req.hostname}/file/${fileName}`
199
- utils.isTrue(json) ?
200
- res.json({ success: true, result: resultUrl }) :
201
- res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
202
  } catch (e) {
203
  console.log(e)
204
  res.status(500).json({ error: true, message: utils.getError(e) })
@@ -206,43 +320,58 @@ app.all('/topdf', async (req, res) => {
206
  })
207
 
208
  app.all(/^\/webp2(gif|mp4|png)/, async (req, res) => {
209
- if (req.method !== 'POST') return res.status(405).json({ success: false, message: 'Method Not Allowed' })
210
-
 
 
 
211
  try {
212
  const { file, json, raw } = req.body
213
- if (!file) return res.status(400).json({ success: false, message: 'Payload \'file\' requires base64 string' })
214
- if (!utils.isBase64(file)) return res.status(400).json({ success: false, message: 'Invalid base64 format' })
215
-
 
 
 
 
 
 
 
216
  const type = req.params[0]
217
  if (type === 'png') {
218
  const fileName = utils.randomName('.png')
219
- const fileBuffer = await sharp(Buffer.from(file, 'base64')).png().toBuffer()
 
 
220
  await fs.promises.writeFile(`${tmpDir}/${fileName}`, fileBuffer)
221
-
222
  const resultUrl = `https://${req.hostname}/file/${fileName}`
223
- utils.isTrue(json) ?
224
- res.json({ success: true, result: resultUrl }) :
225
- res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
226
  return
227
  }
228
-
229
  const fileName = utils.randomName('.webp')
230
  const filePath = `${tmpDir}/${fileName}`
231
  await fs.promises.writeFile(filePath, Buffer.from(file, 'base64'))
232
-
233
  const exec = util.promisify(cp.exec).bind(cp)
234
  await exec(`convert ${filePath} ${filePath.replace('webp', 'gif')}`)
235
-
236
  let resultUrl
237
- if (type === 'gif') resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'gif')}`
 
238
  else {
239
- 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', 'mp4')}`)
 
 
240
  resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'mp4')}`
241
  }
242
-
243
- utils.isTrue(json) ?
244
- res.json({ success: true, result: resultUrl }) :
245
- res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
246
  } catch (e) {
247
  console.log(e)
248
  res.status(500).json({ error: true, message: utils.getError(e) })
@@ -251,23 +380,36 @@ app.all(/^\/webp2(gif|mp4|png)/, async (req, res) => {
251
 
252
  // /yt /yt/dl /yt/download /yt/search /youtube/dl /youtube/download /youtube/search
253
  app.all(/^\/y(outube|t)(\/(d(ownload|l)|search)?)?/, async (req, res) => {
254
- if (!['GET', 'POST'].includes(req.method)) return res.status(405).json({ success: false, message: 'Method Not Allowed' })
255
-
 
 
 
256
  try {
257
  const type = req.params[2]
258
  const obj = req.allParams
259
  if (type === 'search') {
260
- if (!obj.query) return res.status(400).json({ success: false, message: 'Required parameter \'query\'' })
261
-
 
 
 
262
  const result = await yts(obj)
263
- if (!(result.all?.length || result?.url)) return res.status(400).json({ success: false, message: 'Video unavailable' })
264
-
 
 
 
265
  res.json({ success: true, result })
266
  return
267
  } else if (['dl', 'download'].includes(type)) {
268
- if (!obj.url) return res.status(400).json({ success: false, message: 'Required parameter \'url\'' })
269
- if (!utils.ytIdRegex.test(obj.url)) return res.status(400).json({ success: false, message: 'Invalid url' })
270
-
 
 
 
 
271
  const payload = { filenamePattern: 'pretty', ...obj }
272
  if (obj.type === 'audio') {
273
  payload.isAudioOnly = true
@@ -275,21 +417,37 @@ app.all(/^\/y(outube|t)(\/(d(ownload|l)|search)?)?/, async (req, res) => {
275
  } else {
276
  payload.vQuality = obj.quality || '720'
277
  }
278
- // nembak lagi woila
279
  const result = await utils.fetchCobaltAPI(obj.url, payload)
280
- if (result.status === 'error') return res.status(400).json({ success: false, message: 'An error occurred' })
 
 
 
281
  res.redirect(result.url)
282
  return
283
  }
284
-
285
- if (!obj.query) return res.status(400).json({ success: false, message: 'Required parameter \'query\'' })
286
-
287
- let result = await yts(utils.ytIdRegex.test(obj.query) ? { videoId: utils.ytIdRegex.exec(obj.query)[1] } : obj.query)
 
 
 
 
 
 
 
288
  result = result.videos ? result.videos[0] : result
289
- if (!result?.url) return res.status(400).json({ success: false, message: 'Video unavailable' })
290
-
 
 
 
291
  const dlUrl = `https://${req.hostname}/yt/dl?url=${result.url}`
292
- const download = { audio: `${dlUrl}&type=audio`, video: `${dlUrl}&type=video` }
 
 
 
293
  res.json({
294
  success: true,
295
  result: { ...result, download }
@@ -303,6 +461,4 @@ app.all(/^\/y(outube|t)(\/(d(ownload|l)|search)?)?/, async (req, res) => {
303
  // app.use((req, res, next) => {})
304
 
305
  const PORT = process.env.PORT || 7860
306
- app.listen(PORT, () => {
307
- console.log(`App running on port ${PORT}`)
308
- })
 
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)) {
 
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://cobalt-7.kwiatekmiki.com/api/json',
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
+ (await (await fetch(url)).text()).match(
94
+ /href="(.*?)".*id="downloadButton"/
95
+ )[1],
96
+ getError: (e) =>
97
+ String(e).startsWith('[object ') ? 'Internal Server Error' : String(e),
98
  isBase64: (str) => {
99
  try {
100
  return btoa(atob(str)) === str
 
103
  }
104
  },
105
  isTrue: (str) => [true, 'true'].includes(str),
106
+ mediafireIdRegex: /https?:\/\/(www.)?mediafire.com\/(file|folder)\/(\w+)/,
107
+ randomIP: () =>
108
+ [...new Array(4)].map(() => ~~(Math.random() * 256)).join('.'),
109
+ randomName: (str = '') => Math.random().toString(36).slice(2) + str,
110
+ toPDF: (urls, opts = {}) =>
111
+ new Promise(async (resolve, reject) => {
112
+ try {
113
+ const doc = new PDFDocument({ margin: 0, size: 'A4' })
114
+ const buffs = []
115
+
116
+ for (let x = 0; x < urls.length; x++) {
117
+ if (!/https?:\/\//.test(urls[x])) continue
118
+ const url = new URL(urls[x])
119
+ let image = await fetch(url.toString(), {
120
+ headers: { referer: url.origin }
121
+ })
122
+ if (!image.ok) continue
123
+
124
+ const type = image.headers.get('content-type')
125
+ if (!/image/.test(type)) continue
126
+ image = Buffer.from(await image.arrayBuffer())
127
+ if (/(gif|webp)$/.test(type))
128
+ image = await sharp(image).png().toBuffer()
129
+
130
+ doc.image(image, 0, 0, {
131
+ fit: [595.28, 841.89],
132
+ align: 'center',
133
+ valign: 'center',
134
+ ...opts
135
+ })
136
+ if (urls.length != x + 1) doc.addPage()
137
+ }
138
+
139
+ doc.on('data', (chunk) => buffs.push(chunk))
140
+ doc.on('end', () => resolve(Buffer.concat(buffs)))
141
+ doc.on('error', (err) => reject(err))
142
+ doc.end()
143
+ } catch (e) {
144
+ console.log(e)
145
+ reject(e)
146
  }
147
+ }),
 
 
 
 
 
 
 
 
 
148
  // from https://github.com/Nurutomo/wabot-aq/blob/master/lib/y2mate.js#L15
149
+ ytIdRegex:
150
+ /(?:http(?:s|):\/\/|)(?:(?:www\.|)?youtube(?:\-nocookie|)\.com\/(?:shorts\/)?(?:watch\?.*(?:|\&)v=|embed\/|live\/|v\/)?|youtu\.be\/)([-_0-9A-Za-z]{11})/
151
  }
152
 
153
  const app = express()
 
180
  app.all('/', (_, res) => {
181
  const status = {}
182
  status['diskUsage'] = cp.execSync('du -sh').toString().split('M')[0] + ' MB'
183
+
184
  const used = process.memoryUsage()
185
  for (let x in used) status[x] = utils.formatSize(used[x])
186
+
187
  const totalmem = os.totalmem()
188
  const freemem = os.freemem()
189
+ status['memoryUsage'] =
190
+ `${utils.formatSize(totalmem - freemem)} / ${utils.formatSize(totalmem)}`
191
+
192
  const id = process.env.SPACE_ID
193
  res.json({
194
+ message: id
195
+ ? `Go to https://hf.co/spaces/${id}/discussions for discuss`
196
+ : 'Hello World!',
197
  uptime: new Date(process.uptime() * 1000).toUTCString().split(' ')[4],
198
  status
199
  })
200
  })
201
 
202
  app.all(/^\/(brat|carbon)/, async (req, res) => {
203
+ if (!['GET', 'POST'].includes(req.method))
204
+ return res
205
+ .status(405)
206
+ .json({ success: false, message: 'Method Not Allowed' })
207
+
208
  try {
209
  const obj = req.allParams
210
  const isBrat = req.params[0] === 'brat'
211
  if (isBrat && !obj.text) {
212
+ return res
213
+ .status(400)
214
+ .json({ success: false, message: "Required parameter 'text'" })
215
  } else if (!isBrat && !(obj.code || obj.text)) {
216
+ return res
217
+ .status(400)
218
+ .json({ success: false, message: "Required parameter 'code'" })
219
  }
220
+
221
+ const image = isBrat
222
+ ? await utils.generateBrat(obj.text)
223
+ : await utils.fetchCarbonaraAPI(obj.code || obj.text, obj)
224
  const resultUrl = `https://${req.hostname}/${image.replace(tmpDir, 'file')}`
225
+ utils.isTrue(obj.json)
226
+ ? res.json({ success: true, result: resultUrl })
227
+ : res[utils.isTrue(obj.raw) ? 'send' : 'redirect'](resultUrl)
228
+ } catch (e) {
229
+ console.log(e)
230
+ res.status(500).json({ error: true, message: utils.getError(e) })
231
+ }
232
+ })
233
+
234
+ app.all(/^\/mediafire(\/d(ownload|l))?$/, async (req, res) => {
235
+ if (!['GET', 'POST'].includes(req.method))
236
+ return res
237
+ .status(405)
238
+ .json({ success: false, message: 'Method Not Allowed' })
239
+
240
+ try {
241
+ const _type = req.params[0]
242
+ const obj = req.allParams
243
+
244
+ if (_type && ['dl', 'download'].includes(_type.slice(1))) {
245
+ const url = `https://mediafire.com/file/${obj.id}`
246
+ const result = await utils.getMediafireDownloadLink(url)
247
+ res.redirect(result)
248
+ return
249
+ }
250
+
251
+ if (!obj.url)
252
+ return res
253
+ .status(400)
254
+ .json({ success: false, message: "Required parameter 'url'" })
255
+ if (!utils.mediafireIdRegex.test(obj.url))
256
+ return res.status(400).json({ success: false, message: 'Invalid url' })
257
+
258
+ const [, _, type, id] = utils.mediafireIdRegex.exec(obj.url)
259
+ if (type === 'folder')
260
+ return res
261
+ .status(400)
262
+ .json({ success: false, message: 'Folder download not supported yet' })
263
+ if (!id)
264
+ return res
265
+ .status(400)
266
+ .json({ success: false, message: 'Cannot find file id' })
267
+
268
+ const result = {}
269
+ const data = await utils.fetchMediafireAPI(id)
270
+ if (data.error)
271
+ return res.status(400).json({ success: false, message: data.message })
272
+
273
+ for (let [key, val] of Object.entries(data.file_info)) {
274
+ if (key === 'links') continue
275
+ key = key.split('_')[0]
276
+ if (key === 'size') val = utils.formatSize(val)
277
+ result[key] = val
278
+ }
279
+ result['download'] =
280
+ `https://${req.hostname + req.originalUrl.split('?')[0]}/dl?id=${id}`
281
+ res.json({ success: true, result })
282
  } catch (e) {
283
  console.log(e)
284
  res.status(500).json({ error: true, message: utils.getError(e) })
 
286
  })
287
 
288
  app.all('/topdf', async (req, res) => {
289
+ if (req.method !== 'POST')
290
+ return res
291
+ .status(405)
292
+ .json({ success: false, message: 'Method Not Allowed' })
293
+
294
  try {
295
  const { images: urls, json, raw } = req.body
296
+ if (!urls)
297
+ return res.status(400).json({
298
+ success: false,
299
+ message: "Payload 'images' requires an array of urls"
300
+ })
301
  if (!Array.isArray(urls)) urls = [urls]
302
+
303
  const bufferPDF = await utils.toPDF(urls)
304
+ if (!bufferPDF.length)
305
+ return res
306
+ .status(400)
307
+ .json({ success: false, message: "Can't convert to pdf" })
308
+
309
  const fileName = utils.randomName('.pdf')
310
  await fs.promises.writeFile(`${tmpDir}/${fileName}`, bufferPDF)
311
+
312
  const resultUrl = `https://${req.hostname}/file/${fileName}`
313
+ utils.isTrue(json)
314
+ ? res.json({ success: true, result: resultUrl })
315
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
316
  } catch (e) {
317
  console.log(e)
318
  res.status(500).json({ error: true, message: utils.getError(e) })
 
320
  })
321
 
322
  app.all(/^\/webp2(gif|mp4|png)/, async (req, res) => {
323
+ if (req.method !== 'POST')
324
+ return res
325
+ .status(405)
326
+ .json({ success: false, message: 'Method Not Allowed' })
327
+
328
  try {
329
  const { file, json, raw } = req.body
330
+ if (!file)
331
+ return res.status(400).json({
332
+ success: false,
333
+ message: "Payload 'file' requires base64 string"
334
+ })
335
+ if (!utils.isBase64(file))
336
+ return res
337
+ .status(400)
338
+ .json({ success: false, message: 'Invalid base64 format' })
339
+
340
  const type = req.params[0]
341
  if (type === 'png') {
342
  const fileName = utils.randomName('.png')
343
+ const fileBuffer = await sharp(Buffer.from(file, 'base64'))
344
+ .png()
345
+ .toBuffer()
346
  await fs.promises.writeFile(`${tmpDir}/${fileName}`, fileBuffer)
347
+
348
  const resultUrl = `https://${req.hostname}/file/${fileName}`
349
+ utils.isTrue(json)
350
+ ? res.json({ success: true, result: resultUrl })
351
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
352
  return
353
  }
354
+
355
  const fileName = utils.randomName('.webp')
356
  const filePath = `${tmpDir}/${fileName}`
357
  await fs.promises.writeFile(filePath, Buffer.from(file, 'base64'))
358
+
359
  const exec = util.promisify(cp.exec).bind(cp)
360
  await exec(`convert ${filePath} ${filePath.replace('webp', 'gif')}`)
361
+
362
  let resultUrl
363
+ if (type === 'gif')
364
+ resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'gif')}`
365
  else {
366
+ await exec(
367
+ `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')}`
368
+ )
369
  resultUrl = `https://${req.hostname}/file/${fileName.replace('webp', 'mp4')}`
370
  }
371
+
372
+ utils.isTrue(json)
373
+ ? res.json({ success: true, result: resultUrl })
374
+ : res[utils.isTrue(raw) ? 'send' : 'redirect'](resultUrl)
375
  } catch (e) {
376
  console.log(e)
377
  res.status(500).json({ error: true, message: utils.getError(e) })
 
380
 
381
  // /yt /yt/dl /yt/download /yt/search /youtube/dl /youtube/download /youtube/search
382
  app.all(/^\/y(outube|t)(\/(d(ownload|l)|search)?)?/, async (req, res) => {
383
+ if (!['GET', 'POST'].includes(req.method))
384
+ return res
385
+ .status(405)
386
+ .json({ success: false, message: 'Method Not Allowed' })
387
+
388
  try {
389
  const type = req.params[2]
390
  const obj = req.allParams
391
  if (type === 'search') {
392
+ if (!obj.query)
393
+ return res
394
+ .status(400)
395
+ .json({ success: false, message: "Required parameter 'query'" })
396
+
397
  const result = await yts(obj)
398
+ if (!(result.all?.length || result?.url))
399
+ return res
400
+ .status(400)
401
+ .json({ success: false, message: 'Video unavailable' })
402
+
403
  res.json({ success: true, result })
404
  return
405
  } else if (['dl', 'download'].includes(type)) {
406
+ if (!obj.url)
407
+ return res
408
+ .status(400)
409
+ .json({ success: false, message: "Required parameter 'url'" })
410
+ if (!utils.ytIdRegex.test(obj.url))
411
+ return res.status(400).json({ success: false, message: 'Invalid url' })
412
+
413
  const payload = { filenamePattern: 'pretty', ...obj }
414
  if (obj.type === 'audio') {
415
  payload.isAudioOnly = true
 
417
  } else {
418
  payload.vQuality = obj.quality || '720'
419
  }
420
+
421
  const result = await utils.fetchCobaltAPI(obj.url, payload)
422
+ if (result.status === 'error')
423
+ return res
424
+ .status(400)
425
+ .json({ success: false, message: 'An error occurred' })
426
  res.redirect(result.url)
427
  return
428
  }
429
+
430
+ if (!obj.query)
431
+ return res
432
+ .status(400)
433
+ .json({ success: false, message: "Required parameter 'query'" })
434
+
435
+ let result = await yts(
436
+ utils.ytIdRegex.test(obj.query)
437
+ ? { videoId: utils.ytIdRegex.exec(obj.query)[1] }
438
+ : obj.query
439
+ )
440
  result = result.videos ? result.videos[0] : result
441
+ if (!result?.url)
442
+ return res
443
+ .status(400)
444
+ .json({ success: false, message: 'Video unavailable' })
445
+
446
  const dlUrl = `https://${req.hostname}/yt/dl?url=${result.url}`
447
+ const download = {
448
+ audio: `${dlUrl}&type=audio`,
449
+ video: `${dlUrl}&type=video`
450
+ }
451
  res.json({
452
  success: true,
453
  result: { ...result, download }
 
461
  // app.use((req, res, next) => {})
462
 
463
  const PORT = process.env.PORT || 7860
464
+ app.listen(PORT, () => console.log(`App running on port ${PORT}`))