lurcloud 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Carlos Alexis (Zam)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/index.js ADDED
@@ -0,0 +1,10 @@
1
+ const { gdrive, dropbox, mediafire, fetchDownloadLinks, getDownloadLink } = require('./lib/downloader')
2
+ const { rainbow, blur, invert, blue, greyscale, circle, heart, comrade } = require('./lib/maker')
3
+
4
+ module.exports = {
5
+ gdrive, dropbox, mediafire,
6
+ fetchDownloadLinks, getDownloadLink,
7
+
8
+ rainbow, blur, invert, blue,
9
+ greyscale, circle, heart, comrade
10
+ }
@@ -0,0 +1,202 @@
1
+ const fetch = require('node-fetch')
2
+ const axios = require('axios')
3
+ const cheerio = require('cheerio')
4
+ const { lookup } = require('mime-types')
5
+
6
+
7
+ function formatSize(bytes) {
8
+ if (!bytes) return 'unknown'
9
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
10
+ const i = Math.floor(Math.log(bytes) / Math.log(1024))
11
+ return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`
12
+ }
13
+
14
+
15
+ async function gdrive(url) {
16
+ if (!(url && url.match(/drive\.google/i))) throw new Error('Invalid URL')
17
+ const id = (url.match(/\/?id=(.+)/i) || url.match(/\/d\/(.*?)\//))?.[1]
18
+ if (!id) throw new Error('ID Not Found')
19
+
20
+ const res = await fetch(`https://drive.google.com/uc?id=${id}&authuser=0&export=download`, {
21
+ method: 'post',
22
+ headers: {
23
+ 'accept-encoding': 'gzip, deflate, br',
24
+ 'content-length': 0,
25
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
26
+ 'origin': 'https://drive.google.com',
27
+ 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36',
28
+ 'x-client-data': 'CKG1yQEIkbbJAQiitskBCMS2yQEIqZ3KAQioo8oBGLeYygE=',
29
+ 'x-drive-first-party': 'DriveWebUi',
30
+ 'x-json-requested': 'true'
31
+ }
32
+ })
33
+
34
+ const text = await res.text()
35
+
36
+ const { fileName, sizeBytes, downloadUrl } = JSON.parse(text.slice(4))
37
+ if (!downloadUrl) throw new Error('Link Download Limit!')
38
+
39
+ const data = await fetch(downloadUrl)
40
+ if (data.status !== 200) throw new Error(data.statusText)
41
+
42
+ return {
43
+ downloadUrl,
44
+ fileName,
45
+ fileSize: formatSize(sizeBytes),
46
+ mimetype: data.headers.get('content-type')
47
+ }
48
+ }
49
+
50
+
51
+ async function dropbox(url) {
52
+ if (!url || !url.match(/dropbox\.com/i)) throw new Error('URL inválida de Dropbox')
53
+
54
+ const directLink = url.replace('dl=0', 'dl=1')
55
+
56
+ let res = await fetch(directLink, { method: 'HEAD' })
57
+ if (!res.ok) throw new Error('No se pudo acceder al archivo')
58
+
59
+ let fileName = res.headers.get('content-disposition')?.match(/filename="(.+)"/)?.[1] || 'archivo_desconocido'
60
+ let fileSize = res.headers.get('content-length')
61
+
62
+ if (!fileSize) {
63
+ const rangeRes = await fetch(directLink, { method: 'GET', headers: { Range: 'bytes=0-0' } })
64
+ fileSize = rangeRes.headers.get('content-range')?.split('/')[1] || null
65
+ }
66
+
67
+ return {
68
+ downloadUrl: directLink,
69
+ fileName,
70
+ fileSize: formatSize(fileSize ? parseInt(fileSize) : null),
71
+ mimetype: res.headers.get('content-type') || 'application/octet-stream'
72
+ }
73
+ }
74
+
75
+
76
+ async function mediafire(url) {
77
+ try {
78
+ if (!url.includes('mediafire.com')) throw new Error('URL de MediaFire inválida')
79
+
80
+ let res, $, link
81
+
82
+ try {
83
+ res = await axios.get(url, {
84
+ headers: {
85
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
86
+ }
87
+ })
88
+ $ = cheerio.load(res.data)
89
+
90
+ const downloadButton = $('#downloadButton')
91
+ link = downloadButton.attr('href')
92
+
93
+ if (!link || link.includes('javascript:void(0)')) {
94
+ link = downloadButton.attr('data-href') || downloadButton.attr('data-url') || downloadButton.attr('data-link')
95
+
96
+ const scrambledUrl = downloadButton.attr('data-scrambled-url')
97
+ if (scrambledUrl) {
98
+ try { link = atob(scrambledUrl) } catch {}
99
+ }
100
+
101
+ if (!link || link.includes('javascript:void(0)')) {
102
+ const htmlContent = res.data
103
+ const linkMatch = htmlContent.match(/href="(https:\/\/download\d+\.mediafire\.com[^"]+)"/)
104
+ if (linkMatch) link = linkMatch[1]
105
+ else {
106
+ const altMatch = htmlContent.match(/"(https:\/\/[^"]*mediafire[^"]*\.(zip|rar|pdf|jpg|jpeg|png|gif|mp4|mp3|exe|apk|txt)[^"]*)"/i)
107
+ if (altMatch) link = altMatch[1]
108
+ }
109
+ }
110
+ }
111
+ } catch (directError) {
112
+ const translateUrl = `https://www-mediafire-com.translate.goog/${url.replace('https://www.mediafire.com/', '')}?_x_tr_sl=en&_x_tr_tl=fr&_x_tr_hl=en&_x_tr_pto=wapp`
113
+ res = await axios.get(translateUrl, {
114
+ headers: {
115
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
116
+ }
117
+ })
118
+ $ = cheerio.load(res.data)
119
+
120
+ const downloadButton = $('#downloadButton')
121
+ link = downloadButton.attr('href')
122
+ if (!link || link.includes('javascript:void(0)')) {
123
+ const scrambledUrl = downloadButton.attr('data-scrambled-url')
124
+ if (scrambledUrl) {
125
+ try { link = atob(scrambledUrl) } catch {}
126
+ }
127
+ }
128
+ }
129
+
130
+ if (!link || link.includes('javascript:void(0)')) throw new Error('No se encontró un enlace válido')
131
+
132
+ const name = $('body > main > div.content > div.center > div > div.dl-btn-cont > div.dl-btn-labelWrap > div.promoDownloadName.notranslate > div').attr('title')?.replace(/\s+/g, '')?.replace(/\n/g, '') || $('.dl-btn-label').attr('title') || $('.filename').text().trim() || 'archivo_descargado'
133
+
134
+ const date = $('body > main > div.content > div.center > div > div.dl-info > ul > li:nth-child(2) > span').text().trim() || $('.details li:nth-child(2) span').text().trim() || 'Fecha no disponible'
135
+
136
+ const size = $('#downloadButton').text().replace('Download', '').replace(/[()]/g, '').replace(/\n/g, '').replace(/\s+/g, ' ').trim() || $('.details li:first-child span').text().trim() || 'Tamaño no disponible'
137
+
138
+ const ext = name.split('.').pop()?.toLowerCase()
139
+ const mime = lookup(ext) || 'application/octet-stream'
140
+
141
+ return { name, size, date, mime, link }
142
+ } catch (e) {
143
+ throw new Error(`Error al procesar MediaFire: ${e.message}`)
144
+ }
145
+ }
146
+
147
+
148
+ async function fetchDownloadLinks(text, platform, m) {
149
+ const { SITE_URL, form } = createApiRequest(text, platform)
150
+
151
+ const res = await axios.post(`${SITE_URL}api`, form.toString(), {
152
+ headers: {
153
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
154
+ 'Origin': SITE_URL,
155
+ 'Referer': SITE_URL,
156
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
157
+ 'X-Requested-With': 'XMLHttpRequest'
158
+ }
159
+ })
160
+
161
+ const html = res?.data?.html
162
+
163
+ if (!html || res?.data?.status !== 'success') {
164
+ console.log('Error al obtener datos del servidor')
165
+ return null
166
+ }
167
+
168
+ const $ = cheerio.load(html)
169
+ const links = []
170
+
171
+ $('a.btn[href^="http"]').each((_, el) => {
172
+ const link = $(el).attr('href')
173
+ if (link && !links.includes(link)) {
174
+ links.push(link)
175
+ }
176
+ })
177
+
178
+ return links
179
+ }
180
+
181
+ function createApiRequest(text, platform) {
182
+ const SITE_URL = 'https://instatiktok.com/'
183
+ const form = new URLSearchParams()
184
+ form.append('url', text)
185
+ form.append('platform', platform)
186
+ form.append('siteurl', SITE_URL)
187
+ return { SITE_URL, form }
188
+ }
189
+
190
+ function getDownloadLink(platform, links) {
191
+ if (platform === 'instagram') {
192
+ return links
193
+ } else if (platform === 'tiktok') {
194
+ return links.find(link => /hdplay/.test(link)) || links[0]
195
+ } else if (platform === 'facebook') {
196
+ return links.at(-1)
197
+ }
198
+ return null
199
+ }
200
+
201
+
202
+ module.exports = { gdrive, dropbox, mediafire, fetchDownloadLinks, getDownloadLink }
package/lib/maker.js ADDED
@@ -0,0 +1,58 @@
1
+ const fetch = require('node-fetch')
2
+ const FormData = require('form-data')
3
+ const API_KEY = 'ac838c309fcc94c8be1f8e753804c924'
4
+
5
+ async function uploadImage(base64Image) {
6
+ const form = new FormData()
7
+ form.append('image', base64Image)
8
+
9
+ let res = await fetch(`https://api.imgbb.com/1/upload?key=${API_KEY}`, {
10
+ method: 'POST',
11
+ body: form
12
+ })
13
+
14
+ let json = await res.json()
15
+ return json.data.url
16
+ }
17
+
18
+ async function rainbow(image) {
19
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
20
+ return `https://some-random-api.com/canvas/gay?avatar=${encodeURIComponent(imageUrl)}`
21
+ }
22
+
23
+ async function blur(image) {
24
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
25
+ return `https://some-random-api.com/canvas/blur?avatar=${encodeURIComponent(imageUrl)}`
26
+ }
27
+
28
+ async function invert(image) {
29
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
30
+ return `https://some-random-api.com/canvas/invert?avatar=${encodeURIComponent(imageUrl)}`
31
+ }
32
+
33
+ async function blue(image) {
34
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
35
+ return `https://some-random-api.com/canvas/blue?avatar=${encodeURIComponent(imageUrl)}`
36
+ }
37
+
38
+ async function greyscale(image) {
39
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
40
+ return `https://some-random-api.com/canvas/greyscale?avatar=${encodeURIComponent(imageUrl)}`
41
+ }
42
+
43
+ async function circle(image) {
44
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
45
+ return `https://some-random-api.com/canvas/circle?avatar=${encodeURIComponent(imageUrl)}`
46
+ }
47
+
48
+ async function heart(image) {
49
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
50
+ return `https://some-random-api.com/canvas/heart?avatar=${encodeURIComponent(imageUrl)}`
51
+ }
52
+
53
+ async function comrade(image) {
54
+ let imageUrl = Buffer.isBuffer(image) ? await uploadImage(image.toString('base64')) : image
55
+ return `https://some-random-api.com/canvas/overlay/comrade?avatar=${encodeURIComponent(imageUrl)}`
56
+ }
57
+
58
+ module.exports = { rainbow, blur, invert, blue, greyscale, circle, heart, comrade }
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "lurcloud",
3
+ "version": "1.0.0",
4
+ "description": "Un scraper ligero y modular para Node.js, basado en axios, cheerio y got",
5
+ "main": "index.js",
6
+ "keywords": [
7
+ "scraper",
8
+ "crawler",
9
+ "parser",
10
+ "axios",
11
+ "cheerio",
12
+ "got",
13
+ "node-fetch"
14
+ ],
15
+ "author": {
16
+ "name": "AzamiJs",
17
+ "url": "https://github.com/AzamiJs"
18
+ },
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/AzamiJs/lurcloud.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/AzamiJs/lurcloud/issues"
26
+ },
27
+ "homepage": "https://github.com/AzamiJs/lurcloud#readme",
28
+ "dependencies": {
29
+ "axios": "*",
30
+ "cheerio": "npm:cheerio@1.0.0-rc.12",
31
+ "form-data": "^4.0.0",
32
+ "got": "^11.8.6",
33
+ "node-fetch": "^2.6.7"
34
+ }
35
+ }
package/readme.md ADDED
@@ -0,0 +1,70 @@
1
+ # Lurcloud 🌧️
2
+
3
+ > Herramienta útil para Node.js
4
+
5
+ [![npm version](https://img.shields.io/npm/v/lurcloud.svg)](https://www.npmjs.com/package/lurcloud)
6
+ [![License](https://img.shields.io/npm/l/lurcloud.svg)](LICENSE)
7
+
8
+ ---
9
+
10
+ ### Características
11
+ `Descargas`
12
+ - [x] Facebook
13
+ - [x] Instagram
14
+ - [x] Tiktok
15
+ - [x] Google Drive
16
+ - [x] DropBox
17
+
18
+ `Maker`
19
+ - [x] Blue
20
+ - [x] Blur
21
+ - [x] Circle
22
+ - [x] Comrade
23
+ - [x] Greyscale
24
+ - [x] Heart
25
+ - [x] Rainbow
26
+
27
+ > [!NOTE]
28
+ > Con el tiempo se agregaran más funciones según las necesidades.
29
+
30
+ ### Instalación
31
+
32
+ ```bash
33
+ npm install lurcloud
34
+ ```
35
+
36
+ ### Ejemplo
37
+ `Descargas`
38
+ ```Javascript
39
+ const { gdrive } = require('lurcloud')
40
+
41
+ const result = gdrive('question')
42
+ //Funciona igual con dropbox
43
+
44
+ console.log(result)
45
+ ```
46
+
47
+ ```Javascript
48
+ const { fetchDownloadLinks, getDownloadLink } = require('lurcloud')
49
+
50
+ const link = await fetchDownloadLinks('fb.com', 'facebook')
51
+ //fb.com debera ser reemplazado por un enlace de algún video de Facebook
52
+
53
+ const videoUrl = getDownloadLink('facebook', link)
54
+ ```
55
+
56
+ `Maker`
57
+ ```Javascript
58
+ const { blue, comrade, rainbow } = require('lurcloud')
59
+
60
+ const input = '' //Aquí puedes configurar si quieres subir una imagen o un enlace de una imagen
61
+
62
+ const imageUrl = await blue(input)
63
+ //Cambia blue según la configuración que necesites
64
+ ```
65
+
66
+ > [!WARNING]
67
+ > Este es un módulo experimental, no esta 100% completo y puede tener fallas.
68
+
69
+ > [!TIP]
70
+ > Si encuentras un fallo o quieres agregar una nueva función, puedes hacer un pull request.