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 +21 -0
- package/index.js +10 -0
- package/lib/downloader.js +202 -0
- package/lib/maker.js +58 -0
- package/package.json +35 -0
- package/readme.md +70 -0
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
|
+
[](https://www.npmjs.com/package/lurcloud)
|
|
6
|
+
[](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.
|