您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
下载 B 站弹幕为 CSV 方便分析查找
'use scrict'; // ==UserScript== // @name 下载 B 站弹幕 CSV // @namespace http://tampermonkey.net/ // @version 1.1.3 // @description 下载 B 站弹幕为 CSV 方便分析查找 // @author malei0311 // @match https://www.bilibili.com/bangumi/play/* // @grant none // ==/UserScript== /** * 在支持 es6 的浏览器中使用 */ (function () { function formatDate (date, format) { const o = { 'M+': date.getMonth() + 1, // 月份 'd+': date.getDate(), // 日 'H+': date.getHours(), // 小时 'm+': date.getMinutes(), // 分 's+': date.getSeconds(), // 秒 'q+': Math.floor((date.getMonth() + 3) / 3), // 季度 S: date.getMilliseconds() // 毫秒 } let fmt = format || 'yyyy-MM-dd HH:mm:ss' if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length)) } for (let k in o) { if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length) ) } } return fmt } function parseXML (response = '') { try { response = response.replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]/g, '') } catch (e) { console.error('parse xml replace error', e) return } const xmlDoc = new window.DOMParser().parseFromString(response, 'text/xml') const danmuList = [] const $d = xmlDoc.getElementsByTagName('d') for (let i = 0; i < $d.length; i++) { const $item = $d[i] const [stime, mode, size, color, date, sc, uid, dmid] = $item.getAttribute('p').split(',') const text = $item.textContent || $item.text || '' danmuList.push({ stime, // 弹幕播放时间 mode, // 弹幕模式 1..3 滚动弹幕 4底端弹幕 5顶端弹幕 6逆向弹幕 7精准定位 8高级弹幕 size, // 字号 12非常小,16特小,18小,25中,36大,45很大,64特别大 color, // 弹幕颜色 10 进制 date, // unix 时间戳 sc, // 弹幕池 0普通池 1字幕池 2特殊池【目前特殊池为高级弹幕专用】 uid, // 发送者 id,加密算法 hash crc32b dmid, // 弹幕在弹幕数据库中 row id text // 弹幕内容 }) } return danmuList } function loadXML (url, cb) { const xhr = new XMLHttpRequest() xhr.timeout = 10000 xhr.addEventListener('load', () => { const ret = parseXML(xhr.response) if (ret) { cb (ret) } }) xhr.addEventListener('error', () => { console.error('load xml error', xhr.status, xhr.statusText) }) xhr.addEventListener('abort', () => { console.error('load xml abort', xhr.status, xhr.statusText) }) xhr.addEventListener('timeout', () => { console.error('load xml timeout', xhr.status, xhr.statusText) }) xhr.open('GET', url) xhr.withCredentials = true xhr.send() } function download (content, fileName, mimeType = 'text/csv;encoding:utf-8') { const a = document.createElement('a') content = `\uFEFF${content}` if (navigator.msSaveBlob) { // IE10 navigator.msSaveBlob(new Blob([content], { type: mimeType }), fileName) } else if (URL && 'download' in a) { a.href = URL.createObjectURL(new Blob([content], { type: mimeType })) a.setAttribute('download', fileName) document.body.appendChild(a) a.click() document.body.removeChild(a) } else { location.href = 'data:application/octet-stream,' + encodeURIComponent(content) } } function load (url, fileName) { loadXML(url, (danmuList) => { let writeHead = false let content = '' danmuList.forEach((item) => { if (!writeHead) { writeHead = true content += Object.keys(item).join(',') + '\n' } const str = Object.keys(item).reduce((ret, key) => { if (key === 'date') { ret.push(`"${formatDate(new Date(item[key] * 1000))}"`) } else if (key === 'text') { ret.push(`"${item[key].replace(/"/g, '""')}"`) } else { ret.push(`"${item[key]}"`) } return ret }, []).join(',') content += str + '\n' }) download(content, fileName) }) } function inject () { const { h1Title = window.$('h1[title]').text() || document.title, epInfo = {} } = window.__INITIAL_STATE__ const oid = epInfo.cid if (!oid) { return } let injected = false let timer (function tryInject () { const $btn = window.$('.up-load') if (!injected && $btn.length) { injected = true clearTimeout(timer) const $clone = $btn.clone() $clone.html('<a class="u-link" style="cursor: pointer;">下载弹幕</a>').on('click', () => { load(`https://api.bilibili.com/x/v1/dm/list.so?oid=${oid}`, `弹幕----${h1Title}.csv`) }) $btn.before($clone) } timer = setTimeout(tryInject, 3000) })() } inject() })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址