Created
January 1, 2026 06:37
-
-
Save ayashiiiyo/0830b91d37f2b1cb608a6b36aca10e61 to your computer and use it in GitHub Desktop.
Downloader Bilibili
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import axios from 'axios' | |
| import * as cheerio from 'cheerio' | |
| import { exec } from 'node:child_process' | |
| import fs from 'node:fs/promises' | |
| import { promisify } from 'node:util' | |
| const execPromise = promisify(exec) | |
| async function bilibilidl(url, quality = '480P') { | |
| let aid = /\/video\/(\d+)/.exec(url)?.[1] | |
| if (!aid) throw new Error('ID Video not found') | |
| const html = await axios.get(url).then(v => v.data) | |
| const $ = cheerio.load(html) | |
| const title = $('meta[property="og:title"]').attr('content')?.split('|')[0]?.trim() || '' | |
| const description = $('meta[property="og:description"]').attr('content') || '' | |
| const type = $('meta[property="og:video:type"]').attr('content') || '' | |
| const cover = $('meta[property="og:image"]').attr('content') || '' | |
| const like = $('.interactive__btn.interactive__like .interactive__text').text() || '' | |
| const views = $('.bstar-meta__tips-left .bstar-meta-text').first().text().replace(' Ditonton', '') || '' | |
| const play = await axios.get( | |
| 'https://api.bilibili.tv/intl/gateway/web/playurl', | |
| { | |
| params: { | |
| s_locale: 'id_ID', | |
| platform: 'web', | |
| aid, | |
| qn: '64', | |
| type: '0', | |
| device: 'wap', | |
| tf: '0', | |
| spm_id: 'bstar-web.ugc-video-detail.0.0', | |
| from_spm_id: 'bstar-web.homepage.trending.all', | |
| fnval: '16', | |
| fnver: '0' | |
| } | |
| } | |
| ).then(v => v.data) | |
| const videoSel = play.data.playurl.video.find(v => v.stream_info.desc_words === quality) | |
| if (!videoSel) throw new Error('No video found for specified quality') | |
| const videoUrl = videoSel.video_resource.url || videoSel.video_resource.backup_url?.[0] | |
| const audioUrl = play.data.playurl.audio_resource[0].url || play.data.playurl.audio_resource[0].backup_url?.[0] | |
| async function downloadBuffer(url) { | |
| let chunks = [] | |
| let start = 0 | |
| let end = 5 * 1024 * 1024 - 1 | |
| let size = 0 | |
| while (true) { | |
| const res = await axios.get( | |
| url, | |
| { | |
| headers: { | |
| Range: `bytes=${start}-${end}`, | |
| Origin: 'https://www.bilibili.tv', | |
| Referer: 'https://www.bilibili.tv/video/', | |
| 'User-Agent': 'Mozilla/5.0' | |
| }, | |
| responseType: 'arraybuffer' | |
| } | |
| ) | |
| if (!size) { | |
| const cr = res.headers['content-range'] | |
| if (cr) size = Number(cr.split('/')[1]) | |
| } | |
| chunks.push(Buffer.from(res.data)) | |
| if (end >= size - 1) break | |
| start = end + 1 | |
| end = Math.min(start + 5 * 1024 * 1024 - 1, size - 1) | |
| } | |
| return Buffer.concat(chunks) | |
| } | |
| const vBuf = await downloadBuffer(videoUrl) | |
| const aBuf = await downloadBuffer(audioUrl) | |
| const vPath = 'tmp_v.mp4' | |
| const aPath = 'tmp_a.mp3' | |
| const oPath = 'tmp_o.mp4' | |
| await fs.writeFile(vPath, vBuf) | |
| await fs.writeFile(aPath, aBuf) | |
| await execPromise(`ffmpeg -i "${vPath}" -i "${aPath}" -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 "${oPath}"`) | |
| const out = await fs.readFile(oPath) | |
| await Promise.all([ | |
| fs.unlink(vPath).catch(() => {}), | |
| fs.unlink(aPath).catch(() => {}), | |
| fs.unlink(oPath).catch(() => {}) | |
| ]) | |
| return { | |
| title, | |
| description, | |
| type, | |
| cover, | |
| views, | |
| like, | |
| buffer: out | |
| } | |
| } | |
| let handler = async (m, { conn, args, command }) => { | |
| try { | |
| if (!args[0]) return m.reply(`*Example :* .${command} https://www.bilibili.tv/id/video/4789258100016128?bstar_from=bstar-web.ugc-video-detail.related-recommend.all,720`) | |
| m.reply('Wait') | |
| const q = args.join(' ') | |
| const [url, reso] = q.split(',').map(v => v.trim()) | |
| const quality = reso ? `${reso}P` : '480P' | |
| const r = await bilibilidl(url, quality) | |
| const size = r.buffer.length | |
| if (size > 100 * 1024 * 1024) { | |
| await conn.sendMessage( | |
| m.chat, | |
| { | |
| document: r.buffer, | |
| fileName: `${r.title || 'bilibili'}.mp4`, | |
| mimetype: 'video/mp4' | |
| }, | |
| { quoted: m } | |
| ) | |
| } else { | |
| await conn.sendMessage( | |
| m.chat, | |
| { video: r.buffer }, | |
| { quoted: m } | |
| ) | |
| } | |
| } catch (e) { | |
| m.reply(e.message) | |
| } | |
| } | |
| handler.help = ['bilibili'] | |
| handler.tags = ['downloader'] | |
| handler.command = ['bilibili','bili'] | |
| export default handler |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment