@danonino/moon 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/README.md +1 -0
- package/index.js +25 -0
- package/index.mjs +16 -0
- package/package.json +33 -0
- package/src/allinonedownloader.js +66 -0
- package/src/applemusicdl.js +63 -0
- package/src/brat.js +192 -0
- package/src/bypasstools.js +35 -0
- package/src/douyindl.js +69 -0
- package/src/fake-ovo.js +106 -0
- package/src/geniusdetail.js +44 -0
- package/src/geniussearch.js +42 -0
- package/src/igdl.js +53 -0
- package/src/igstalk.js +59 -0
- package/src/iqc-darkmode.js +382 -0
- package/src/iqc-pinkmode.js +390 -0
- package/src/mediafiredl.js +144 -0
- package/src/nanobanana.js +115 -0
- package/src/novaai.js +34 -0
- package/src/pinterestdownload.js +72 -0
- package/src/pixaremovebg.js +32 -0
- package/src/savetube.js +85 -0
- package/src/sharpify.js +37 -0
- package/src/spotify.js +374 -0
- package/src/spotifycard.js +142 -0
- package/src/spotifydl.js +25 -0
- package/src/threadsdownload.js +65 -0
- package/src/tiktokdm-qc.js +225 -0
- package/src/tiktokdownload.js +56 -0
- package/src/twetterdownload.js +39 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
const srcPath = path.join(__dirname, 'src')
|
|
5
|
+
const modules = {}
|
|
6
|
+
const listScraper = []
|
|
7
|
+
|
|
8
|
+
fs.readdirSync(srcPath).forEach(file => {
|
|
9
|
+
if (file.endsWith('.js')) {
|
|
10
|
+
const name = file.replace('.js', '')
|
|
11
|
+
modules[name] = require(`./src/${file}`)
|
|
12
|
+
listScraper.push(name)
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
modules.docs = async () => {
|
|
17
|
+
return {
|
|
18
|
+
success: true,
|
|
19
|
+
total: listScraper.length,
|
|
20
|
+
scrapers: listScraper,
|
|
21
|
+
message: "Gunakan nama scraper sebagai function. Contoh pemakaian: await nama_scraper('url')"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = modules
|
package/index.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import scraper from './index.js';
|
|
2
|
+
|
|
3
|
+
export const applemusicdl = scraper.applemusicdl;
|
|
4
|
+
export const geniusdetail = scraper.geniusdetail;
|
|
5
|
+
export const geniussearch = scraper.geniussearch;
|
|
6
|
+
export const igdl = scraper.igdl;
|
|
7
|
+
export const igstalk = scraper.igstalk;
|
|
8
|
+
export const novaai = scraper.novaai;
|
|
9
|
+
export const pinterestdownload = scraper.pinterestdownload;
|
|
10
|
+
export const pixaremovebg = scraper.pixaremovebg;
|
|
11
|
+
export const sharpify = scraper.sharpify;
|
|
12
|
+
export const threadsdownload = scraper.threadsdownload;
|
|
13
|
+
export const twetterdownload = scraper.twetterdownload;
|
|
14
|
+
export const docs = scraper.docs;
|
|
15
|
+
|
|
16
|
+
export default scraper;
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@danonino/moon",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "femboys",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"test",
|
|
7
|
+
"moon",
|
|
8
|
+
"scraping"
|
|
9
|
+
],
|
|
10
|
+
"main": "index.js",
|
|
11
|
+
"type": "commonjs",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./index.mjs",
|
|
15
|
+
"require": "./index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
20
|
+
},
|
|
21
|
+
"author": "moon",
|
|
22
|
+
"license": "ISC",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@fontsource/plus-jakarta-sans": "^5.2.8",
|
|
25
|
+
"@napi-rs/canvas": "^1.0.2",
|
|
26
|
+
"@zenaveline/scraper": "^1.2.2",
|
|
27
|
+
"axios": "^1.6.0",
|
|
28
|
+
"cheerio": "^1.0.0",
|
|
29
|
+
"crypto": "^1.0.1",
|
|
30
|
+
"form-data": "^4.0.0",
|
|
31
|
+
"sharp": "^0.33.2"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Base : https://wowdownloader.com
|
|
3
|
+
Author : Neo
|
|
4
|
+
WhatsApp Channel: https://whatsapp.com/channel/0029Vb6hVYK8V0tkiz4bKs0N
|
|
5
|
+
Support:
|
|
6
|
+
Tiktok
|
|
7
|
+
Twitter
|
|
8
|
+
Facebook
|
|
9
|
+
Instagram
|
|
10
|
+
Pinterest
|
|
11
|
+
LinkedIn
|
|
12
|
+
Douyin
|
|
13
|
+
Likee
|
|
14
|
+
SoundCloud
|
|
15
|
+
Spotify
|
|
16
|
+
Apple Music
|
|
17
|
+
YouTube
|
|
18
|
+
*/
|
|
19
|
+
const axios = require('axios');
|
|
20
|
+
|
|
21
|
+
const tools = [
|
|
22
|
+
'apple-music-downloader', 'douyin-downloader', 'facebook-video-downloader',
|
|
23
|
+
'instagram-reels-downloader', 'instagram-story-downloader', 'instagram-video-downloader',
|
|
24
|
+
'likee-downloader', 'linkedin-video-downloader', 'pinterest-video-downloader',
|
|
25
|
+
'soundcloud-downloader', 'spotify-downloader', 'tiktok-photo-downloader',
|
|
26
|
+
'tiktok-story-downloader', 'tiktok-video-downloader', 'twitter-gif-downloader',
|
|
27
|
+
'twitter-video-downloader', 'youtube-monetization-checker', 'youtube-money-calculator',
|
|
28
|
+
'youtube-tags-extractor', 'youtube-thumbnail-downloader', 'youtube-transcript',
|
|
29
|
+
'youtube-video-downloader'
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
async function wowdownloader(url, tool) {
|
|
33
|
+
try {
|
|
34
|
+
if (!url.includes('https://')) throw new Error('Invalid url.');
|
|
35
|
+
if (!tools.includes(tool)) throw new Error('Invalid tool.');
|
|
36
|
+
|
|
37
|
+
const { data: html, headers } = await axios.get(`https://wowdownloader.com/tool/${tool}`, {
|
|
38
|
+
headers: {
|
|
39
|
+
'user-agent': 'Neo/1.0'
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const csrfToken = html.match(/<meta name="csrf-token" content="([^"]+)">/)?.[1];
|
|
44
|
+
if (!csrfToken) throw new Error('Failed to get token.');
|
|
45
|
+
|
|
46
|
+
const { data } = await axios.post('https://wowdownloader.com/api/download', {
|
|
47
|
+
url: url,
|
|
48
|
+
tool: tool
|
|
49
|
+
}, {
|
|
50
|
+
headers: {
|
|
51
|
+
origin: 'https://wowdownloader.com',
|
|
52
|
+
referer: `https://wowdownloader.com/tool/${tool}`,
|
|
53
|
+
'x-csrf-token': csrfToken,
|
|
54
|
+
cookie: headers['set-cookie']?.map(c => c.split(';')[0]).join('; '),
|
|
55
|
+
'content-type': 'application/json',
|
|
56
|
+
'user-agent': 'Neo/1.0'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return data;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw new Error(error.response?.data?.error || error.message);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
module.exports = wowdownloader;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Base : https://aaplmusicdownloader.com/
|
|
3
|
+
By : ZennzXD
|
|
4
|
+
Created : Kamis 2 April 2026
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const axios = require('axios')
|
|
8
|
+
|
|
9
|
+
const headers = {
|
|
10
|
+
'User-Agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Mobile Safari/537.36',
|
|
11
|
+
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
|
12
|
+
'origin': 'https://aaplmusicdownloader.com',
|
|
13
|
+
'referer': 'https://aaplmusicdownloader.com/',
|
|
14
|
+
'sec-fetch-site': 'same-origin',
|
|
15
|
+
'sec-fetch-mode': 'cors',
|
|
16
|
+
'accept-language': 'id-ID,id;q=0.9,en-AU;q=0.8,en;q=0.7,en-US;q=0.6'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function aapldown(url) {
|
|
20
|
+
const init = await axios.get('https://aaplmusicdownloader.com/', { headers })
|
|
21
|
+
const cookies = init.headers['set-cookie']
|
|
22
|
+
const cookieStr = cookies ? cookies.map(c => c.split(';')[0]).join('; ') : ''
|
|
23
|
+
|
|
24
|
+
const reqheaders = { ...headers, 'Cookie': cookieStr, 'x-requested-with': 'XMLHttpRequest' }
|
|
25
|
+
|
|
26
|
+
const metadata = await axios.get(`https://aaplmusicdownloader.com/api/song_url.php?url=${encodeURIComponent(url)}`, { headers: reqheaders })
|
|
27
|
+
const meta = metadata.data
|
|
28
|
+
|
|
29
|
+
const swdData = new URLSearchParams()
|
|
30
|
+
swdData.append('song_name', meta.name.replace(/['"]/g, ''))
|
|
31
|
+
swdData.append('artist_name', meta.artist.replace(/['"]/g, ''))
|
|
32
|
+
swdData.append('url', meta.url)
|
|
33
|
+
swdData.append('token', 'none')
|
|
34
|
+
swdData.append('zip_download', 'false')
|
|
35
|
+
swdData.append('quality', '320')
|
|
36
|
+
|
|
37
|
+
const swdRes = await axios.post('https://aaplmusicdownloader.com/api/composer/swd.php', swdData, {
|
|
38
|
+
headers: { ...reqheaders, 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const id3Data = new URLSearchParams()
|
|
42
|
+
id3Data.append('url', swdRes.data.dlink)
|
|
43
|
+
id3Data.append('name', meta.name)
|
|
44
|
+
id3Data.append('artist', meta.artist)
|
|
45
|
+
id3Data.append('album', meta.albumname)
|
|
46
|
+
id3Data.append('thumb', meta.thumb)
|
|
47
|
+
|
|
48
|
+
const id3Res = await axios.post('https://aaplmusicdownloader.com/api/composer/ffmpeg/saveid3.php', id3Data, {
|
|
49
|
+
headers: { ...reqheaders, 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
50
|
+
responseType: 'text'
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
title: meta.name,
|
|
55
|
+
album: meta.albumname,
|
|
56
|
+
artist: meta.artist,
|
|
57
|
+
thumb: meta.thumb,
|
|
58
|
+
duration: meta.duration,
|
|
59
|
+
url_dl: `https://aaplmusicdownloader.com/api/composer/ffmpeg/saved/${id3Res.data}`
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = aapldown
|
package/src/brat.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Source : https://whatsapp.com/channel/0029VbCHRSDAzNboLatr0W0o/471
|
|
3
|
+
Creator : Ditzzx
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { createCanvas, loadImage, GlobalFonts } = require('@napi-rs/canvas')
|
|
7
|
+
const { writeFileSync, existsSync, readFileSync } = require('fs')
|
|
8
|
+
const path = require('path')
|
|
9
|
+
|
|
10
|
+
const THEMES = {
|
|
11
|
+
black: { bg: '#000000', text: '#ffffff' },
|
|
12
|
+
white: { bg: '#ffffff', text: '#000000' },
|
|
13
|
+
green: { bg: '#8ace00', text: '#000000' }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const FONT_URL = 'https://raw.githubusercontent.com/Ditzzx-vibecoder/Assets/main/Font/ARIALN.ttf'
|
|
17
|
+
const EMOJI_JSON_URL = 'https://media.githubusercontent.com/media/Ditzzx-vibecoder/entahlah/main/emoji-apple.json'
|
|
18
|
+
const FONT_PATH = path.join(__dirname, 'ARIALN.ttf')
|
|
19
|
+
const EMOJI_JSON_PATH = path.join(__dirname, 'emoji-apple.json')
|
|
20
|
+
|
|
21
|
+
async function downloadFile(url, dest) {
|
|
22
|
+
const res = await fetch(url)
|
|
23
|
+
const buf = Buffer.from(await res.arrayBuffer())
|
|
24
|
+
writeFileSync(dest, buf)
|
|
25
|
+
return buf
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function ensureFont() {
|
|
29
|
+
if (!existsSync(FONT_PATH)) await downloadFile(FONT_URL, FONT_PATH)
|
|
30
|
+
GlobalFonts.registerFromPath(FONT_PATH, 'ArialNarrow')
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let emojiMap = null
|
|
34
|
+
const emojiImageCache = new Map()
|
|
35
|
+
|
|
36
|
+
function emojiToUnicode(emoji) {
|
|
37
|
+
return [...emoji].map(c => c.codePointAt(0).toString(16).padStart(4, '0')).join('-')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function loadEmojiMap() {
|
|
41
|
+
if (emojiMap) return emojiMap
|
|
42
|
+
if (!existsSync(EMOJI_JSON_PATH)) await downloadFile(EMOJI_JSON_URL, EMOJI_JSON_PATH)
|
|
43
|
+
emojiMap = JSON.parse(readFileSync(EMOJI_JSON_PATH, 'utf-8'))
|
|
44
|
+
return emojiMap
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function getEmojiImage(emoji) {
|
|
48
|
+
if (emojiImageCache.has(emoji)) return emojiImageCache.get(emoji)
|
|
49
|
+
const map = await loadEmojiMap()
|
|
50
|
+
const base = emojiToUnicode(emoji)
|
|
51
|
+
const variants = [
|
|
52
|
+
base,
|
|
53
|
+
base.replace(/-fe0f/gi, ''),
|
|
54
|
+
`${base.replace(/-fe0f/gi, '')}-fe0f`,
|
|
55
|
+
base.toUpperCase(),
|
|
56
|
+
base.replace(/-fe0f/gi, '').toUpperCase(),
|
|
57
|
+
base.replace(/-fe0f/gi, '').toUpperCase() + '-FE0F'
|
|
58
|
+
]
|
|
59
|
+
let b64 = null
|
|
60
|
+
for (const v of variants) {
|
|
61
|
+
if (map[v]) { b64 = map[v]; break }
|
|
62
|
+
}
|
|
63
|
+
if (!b64) return null
|
|
64
|
+
const img = await loadImage(Buffer.from(b64, 'base64'))
|
|
65
|
+
emojiImageCache.set(emoji, img)
|
|
66
|
+
return img
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function drawAppleEmoji(ctx, emoji, x, y, size) {
|
|
70
|
+
const img = await getEmojiImage(emoji)
|
|
71
|
+
if (!img) { ctx.fillText(emoji, x, y); return }
|
|
72
|
+
ctx.drawImage(img, x, y, size, size)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const EMOJI_REGEX = /(\p{Emoji_Modifier_Base}\p{Emoji_Modifier}|\p{Emoji_Presentation}\uFE0F?|\p{Emoji}\uFE0F|[\u{1F1E0}-\u{1F1FF}]{2}|\p{Extended_Pictographic}\uFE0F?)/gu
|
|
76
|
+
|
|
77
|
+
function measureTextCustom(ctx, text, fontSize) {
|
|
78
|
+
const parts = text.split(EMOJI_REGEX)
|
|
79
|
+
let w = 0
|
|
80
|
+
for (const part of parts) {
|
|
81
|
+
if (!part) continue
|
|
82
|
+
EMOJI_REGEX.lastIndex = 0
|
|
83
|
+
if (EMOJI_REGEX.test(part)) w += fontSize
|
|
84
|
+
else w += ctx.measureText(part).width
|
|
85
|
+
EMOJI_REGEX.lastIndex = 0
|
|
86
|
+
}
|
|
87
|
+
return w
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function drawTextWithEmojis(ctx, text, x, y, fontSize) {
|
|
91
|
+
const parts = text.split(EMOJI_REGEX)
|
|
92
|
+
let curX = x
|
|
93
|
+
for (const part of parts) {
|
|
94
|
+
if (!part) continue
|
|
95
|
+
EMOJI_REGEX.lastIndex = 0
|
|
96
|
+
if (EMOJI_REGEX.test(part)) {
|
|
97
|
+
await drawAppleEmoji(ctx, part, curX, y, fontSize)
|
|
98
|
+
curX += fontSize
|
|
99
|
+
} else {
|
|
100
|
+
ctx.fillText(part, curX, y)
|
|
101
|
+
curX += ctx.measureText(part).width
|
|
102
|
+
}
|
|
103
|
+
EMOJI_REGEX.lastIndex = 0
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function wrapText(ctx, text, maxWidth, fontSize) {
|
|
108
|
+
ctx.font = `${fontSize}px ArialNarrow`
|
|
109
|
+
const words = text.split(' ')
|
|
110
|
+
const lines = []
|
|
111
|
+
let cur = ''
|
|
112
|
+
for (const word of words) {
|
|
113
|
+
const test = cur ? cur + ' ' + word : word
|
|
114
|
+
if (measureTextCustom(ctx, test, fontSize) > maxWidth && cur) {
|
|
115
|
+
lines.push(cur)
|
|
116
|
+
cur = word
|
|
117
|
+
} else {
|
|
118
|
+
cur = test
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (cur) lines.push(cur)
|
|
122
|
+
return lines
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function fitsAt(ctx, text, fontSize, maxWidth, maxHeight, lineGap) {
|
|
126
|
+
const lines = wrapText(ctx, text, maxWidth, fontSize)
|
|
127
|
+
const longestWord = Math.max(...text.split(' ').map(w => measureTextCustom(ctx, w, fontSize)))
|
|
128
|
+
const totalHeight = lines.length * (fontSize + lineGap) - lineGap
|
|
129
|
+
return longestWord <= maxWidth && totalHeight <= maxHeight
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function findBestFontSize(ctx, text, maxWidth, maxHeight, lineGap) {
|
|
133
|
+
let lo = 10
|
|
134
|
+
let hi = 700
|
|
135
|
+
let best = lo
|
|
136
|
+
|
|
137
|
+
while (lo <= hi) {
|
|
138
|
+
const mid = Math.floor((lo + hi) / 2)
|
|
139
|
+
if (fitsAt(ctx, text, mid, maxWidth, maxHeight, lineGap)) {
|
|
140
|
+
best = mid
|
|
141
|
+
lo = mid + 1
|
|
142
|
+
} else {
|
|
143
|
+
hi = mid - 1
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return best
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
async function generateBrat({ text = 'Halo Guys Nama Saya', theme = 'white', blur = 0 } = {}) {
|
|
150
|
+
const selectedTheme = THEMES[theme] || THEMES.white
|
|
151
|
+
const blurAmount = [0, 1, 2, 3].includes(blur) ? blur : 0
|
|
152
|
+
|
|
153
|
+
const size = 1000
|
|
154
|
+
const padding = 80
|
|
155
|
+
const lineGap = 20
|
|
156
|
+
const maxWidth = size - padding * 2
|
|
157
|
+
const maxHeight = size - padding * 2
|
|
158
|
+
|
|
159
|
+
await ensureFont()
|
|
160
|
+
await loadEmojiMap()
|
|
161
|
+
|
|
162
|
+
const canvas = createCanvas(size, size)
|
|
163
|
+
const ctx = canvas.getContext('2d')
|
|
164
|
+
|
|
165
|
+
const fontSize = findBestFontSize(ctx, text, maxWidth, maxHeight, lineGap)
|
|
166
|
+
const lines = wrapText(ctx, text, maxWidth, fontSize)
|
|
167
|
+
|
|
168
|
+
ctx.fillStyle = selectedTheme.bg
|
|
169
|
+
ctx.fillRect(0, 0, size, size)
|
|
170
|
+
|
|
171
|
+
ctx.fillStyle = selectedTheme.text
|
|
172
|
+
ctx.font = `${fontSize}px ArialNarrow`
|
|
173
|
+
ctx.textAlign = 'left'
|
|
174
|
+
ctx.textBaseline = 'top'
|
|
175
|
+
|
|
176
|
+
ctx.save()
|
|
177
|
+
if (blurAmount > 0) ctx.filter = `blur(${blurAmount}px)`
|
|
178
|
+
|
|
179
|
+
const totalTextHeight = lines.length * (fontSize + lineGap) - lineGap
|
|
180
|
+
let y = (size - totalTextHeight) / 2
|
|
181
|
+
for (const line of lines) {
|
|
182
|
+
await drawTextWithEmojis(ctx, line, padding, y, fontSize)
|
|
183
|
+
y += fontSize + lineGap
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
ctx.restore()
|
|
187
|
+
|
|
188
|
+
const buffer = await canvas.encode('png')
|
|
189
|
+
return buffer
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
module.exports = generateBrat
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//credit by nazir
|
|
2
|
+
//support sf.gl, sub2unlock, tinyurl, linkvertise dll
|
|
3
|
+
|
|
4
|
+
const crypto = require("crypto");
|
|
5
|
+
|
|
6
|
+
async function bypass(url, androidId = crypto.randomBytes(16).toString("hex")) {
|
|
7
|
+
const deviceId = crypto.createHash("sha256").update(`bypasstools:${androidId}`).digest("hex");
|
|
8
|
+
const { sessionToken } = await fetch("https://bypass.tools/api/mobile/init", {
|
|
9
|
+
method: "POST",
|
|
10
|
+
headers: { "Content-Type": "application/json" },
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
deviceId,
|
|
13
|
+
platform: "android",
|
|
14
|
+
appVersion: "1.0.0"
|
|
15
|
+
})
|
|
16
|
+
}).then(r => r.json());
|
|
17
|
+
return fetch("https://bypass.tools/api/mobile/bypass", {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
Authorization: `Bearer ${sessionToken}`,
|
|
22
|
+
"X-Device-ID": deviceId
|
|
23
|
+
},
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
url,
|
|
26
|
+
forceRefresh: false
|
|
27
|
+
})
|
|
28
|
+
}).then(async r => {
|
|
29
|
+
const d = await r.json();
|
|
30
|
+
if (!r.ok) throw new Error(d.message || "Bypass failed");
|
|
31
|
+
return d.result;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = bypass;
|
package/src/douyindl.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//© Nazir
|
|
2
|
+
|
|
3
|
+
async function getAwemeId(input) {
|
|
4
|
+
if (/^\d+$/.test(input)) return input;
|
|
5
|
+
if (input.includes('v.douyin.com')) {
|
|
6
|
+
const res = await fetch(input, { redirect: 'follow' });
|
|
7
|
+
input = res.url;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const match = input.match(/\/video\/(\d+)/);
|
|
11
|
+
if (match) return match[1];
|
|
12
|
+
|
|
13
|
+
throw new Error("Gagal mengekstrak ID dari URL.");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function douyin(input) {
|
|
17
|
+
try {
|
|
18
|
+
const awemeId = await getAwemeId(input);
|
|
19
|
+
const url = "https://so.douyin.com/aweme/v1/web/aweme/detail/";
|
|
20
|
+
|
|
21
|
+
const headers = {
|
|
22
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
23
|
+
"accept": "application/json",
|
|
24
|
+
"user-agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Mobile Safari/537.36"
|
|
25
|
+
};
|
|
26
|
+
const body = `aweme_id=${awemeId}&request_source=280`;
|
|
27
|
+
|
|
28
|
+
const response = await fetch(url, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: headers,
|
|
31
|
+
body: body
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
|
|
35
|
+
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
|
|
38
|
+
if (!data.aweme_detail) {
|
|
39
|
+
throw new Error("Metadata tidak ditemukan.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const videoData = data.aweme_detail.video;
|
|
43
|
+
const desc = data.aweme_detail.desc || "no_description";
|
|
44
|
+
const author = data.aweme_detail.author ? data.aweme_detail.author.nickname : "unknown";
|
|
45
|
+
const videoUrl = videoData.play_addr.url_list[0];
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
status: "success",
|
|
49
|
+
video_id: awemeId,
|
|
50
|
+
metadata: {
|
|
51
|
+
description: desc,
|
|
52
|
+
author: author,
|
|
53
|
+
author_id: data.aweme_detail.author ? data.aweme_detail.author.unique_id : null,
|
|
54
|
+
statistics: data.aweme_detail.statistics,
|
|
55
|
+
cover: videoData.cover.url_list[0],
|
|
56
|
+
duration: Math.round(videoData.duration / 1000) + "s",
|
|
57
|
+
video_url: videoUrl
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return {
|
|
63
|
+
status: "error",
|
|
64
|
+
message: error.message
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = douyin;
|
package/src/fake-ovo.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Source : https://whatsapp.com/channel/0029VbCHRSDAzNboLatr0W0o/471
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { createCanvas, loadImage, GlobalFonts } = require("@napi-rs/canvas");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const fsp = require("fs/promises");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
|
|
10
|
+
const ROOT = process.cwd();
|
|
11
|
+
const OUTPUT_DIR = path.join(ROOT, "tmp");
|
|
12
|
+
|
|
13
|
+
const IMAGE_URL =
|
|
14
|
+
"https://raw.githubusercontent.com/Ditzzx-vibecoder/Assets/main/Image/file_0000000078bc71fa87da5cf26dc6c008.jpeg";
|
|
15
|
+
|
|
16
|
+
const WIDTH = 841;
|
|
17
|
+
const HEIGHT = 1870;
|
|
18
|
+
|
|
19
|
+
const FONT_PATHS = [
|
|
20
|
+
path.join(
|
|
21
|
+
ROOT,
|
|
22
|
+
"node_modules/@fontsource/plus-jakarta-sans/files/plus-jakarta-sans-latin-600-normal.woff2"
|
|
23
|
+
),
|
|
24
|
+
path.join(
|
|
25
|
+
ROOT,
|
|
26
|
+
"node_modules/@fontsource/plus-jakarta-sans/files/plus-jakarta-sans-latin-ext-600-normal.woff2"
|
|
27
|
+
),
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const FIXED_RP = Object.freeze({
|
|
31
|
+
text: "Rp",
|
|
32
|
+
x: 61,
|
|
33
|
+
y: 368,
|
|
34
|
+
size: 20,
|
|
35
|
+
weight: 800,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const AMOUNT_STYLE = {
|
|
39
|
+
x: 94,
|
|
40
|
+
y: 371,
|
|
41
|
+
size: 28,
|
|
42
|
+
weight: 800,
|
|
43
|
+
color: "#FFFFFF",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function formatAmount(input) {
|
|
47
|
+
const digits = String(input).replace(/[^\d]/g, "") || "0";
|
|
48
|
+
const normalized = digits.replace(/^0+(?=\d)/, "");
|
|
49
|
+
|
|
50
|
+
return normalized.replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function registerFont() {
|
|
54
|
+
for (const fontPath of FONT_PATHS) {
|
|
55
|
+
if (fs.existsSync(fontPath)) {
|
|
56
|
+
GlobalFonts.registerFromPath(fontPath, "Plus Jakarta Sans");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new Error("Font Plus Jakarta Sans tidak ketemu. Pastikan package @fontsource/plus-jakarta-sans terinstal.");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function loadImageFromUrl(url) {
|
|
65
|
+
const res = await fetch(url);
|
|
66
|
+
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
throw new Error(`Gagal download image: HTTP ${res.status}`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
72
|
+
return loadImage(Buffer.from(arrayBuffer));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function fakeOvo(amountInput = "5000002828") {
|
|
76
|
+
fs.mkdirSync(OUTPUT_DIR, {
|
|
77
|
+
recursive: true,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
registerFont();
|
|
81
|
+
|
|
82
|
+
const image = await loadImageFromUrl(IMAGE_URL);
|
|
83
|
+
|
|
84
|
+
const canvas = createCanvas(WIDTH, HEIGHT);
|
|
85
|
+
const ctx = canvas.getContext("2d");
|
|
86
|
+
|
|
87
|
+
ctx.imageSmoothingEnabled = true;
|
|
88
|
+
ctx.drawImage(image, 0, 0, WIDTH, HEIGHT);
|
|
89
|
+
|
|
90
|
+
ctx.fillStyle = AMOUNT_STYLE.color;
|
|
91
|
+
ctx.textAlign = "left";
|
|
92
|
+
ctx.textBaseline = "alphabetic";
|
|
93
|
+
|
|
94
|
+
ctx.font = `${FIXED_RP.weight} ${FIXED_RP.size}px "Plus Jakarta Sans"`;
|
|
95
|
+
ctx.fillText(FIXED_RP.text, FIXED_RP.x, FIXED_RP.y);
|
|
96
|
+
|
|
97
|
+
const AMOUNT_TEXT = formatAmount(amountInput);
|
|
98
|
+
|
|
99
|
+
ctx.font = `${AMOUNT_STYLE.weight} ${AMOUNT_STYLE.size}px "Plus Jakarta Sans"`;
|
|
100
|
+
ctx.fillText(AMOUNT_TEXT, AMOUNT_STYLE.x, AMOUNT_STYLE.y);
|
|
101
|
+
|
|
102
|
+
const buffer = await canvas.encode("png");
|
|
103
|
+
return buffer;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = fakeOvo;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Genius
|
|
3
|
+
Base : https://play.google.com/store/apps/details?id=com.genius.android
|
|
4
|
+
Author : ZennzXD
|
|
5
|
+
Created : Sabtu 2 mei 2026
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const headers = {
|
|
9
|
+
'Accept-Encoding': 'gzip',
|
|
10
|
+
'x-genius-app-background-request': '0',
|
|
11
|
+
'x-genius-logged-out': 'true',
|
|
12
|
+
'x-genius-android-version': '8.1.1',
|
|
13
|
+
'user-agent': 'Genius/8.1.1 (Android; Android 13; ZN/Android)'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function parselirik(node) {
|
|
17
|
+
if (typeof node === 'string') return node
|
|
18
|
+
if (!node || !node.children) return ''
|
|
19
|
+
if (node.tag === 'br') return '\n'
|
|
20
|
+
return node.children.map(parselirik).join('')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function detail(id) {
|
|
24
|
+
const res = await fetch(`https://api.genius.com/songs/${id}`, { headers })
|
|
25
|
+
const data = await res.json()
|
|
26
|
+
const song = data.response.song
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
id: song.id,
|
|
30
|
+
title: song.title,
|
|
31
|
+
artist: song.artist_names,
|
|
32
|
+
header_image_url: song.header_image_url,
|
|
33
|
+
song_art_image_url: song.song_art_image_url,
|
|
34
|
+
instrumental: song.instrumental,
|
|
35
|
+
is_music: song.is_music,
|
|
36
|
+
hidden: song.hidden,
|
|
37
|
+
explicit: song.explicit,
|
|
38
|
+
release_date: song.release_date_for_display,
|
|
39
|
+
url: song.url,
|
|
40
|
+
lyrics: song.lyrics ? parselirik(song.lyrics.dom).trim() : null
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports = detail
|