// ==UserScript==
// @name B站大会员影视+番剧+弹幕+字幕
// @namespace http://tampermonkey.net/
// @version 1.6
// @description B站观影 弹幕 字幕替换
// @author Polygon
// @match https://www.cuan.la/m3u8.php*
// @match https://vip.parwix.com/*
// @require https://gf.qytechs.cn/scripts/407985-ajax-hook/code/Ajax-hook.js?version=940269
// @include https://www.bilibili.com/bangumi/play/*
// @include https://www.bilibili.com/video/BV*
// @require http://code.jquery.com/jquery-1.11.0.min.js
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_addStyle
// @run-at document-ildm
// @connect *
// ==/UserScript==
async function dataQuery() {
'use strict'
var cid, aid
if (document.URL.startsWith('https://www.bilibili.com/')) {
// 网页加载完后在bili网站获取cid,aid,并储存
(function() {
if (typeof cid == "undefined") {
cid = unsafeWindow.__INITIAL_STATE__.epInfo.cid
console.log('更新cid=' + unsafeWindow.__INITIAL_STATE__.epInfo.cid)
GM_setValue('cid', cid)
}
if (typeof aid == "undefined") {
aid = unsafeWindow.__INITIAL_STATE__.epInfo.aid
console.log('更新aid=' + aid)
GM_setValue('aid', aid)
}
})()
var danmu = { code: 23, msg: "success", dannum: 0, danmuku: [], name: cid }
// 字幕
let subtitleApi = 'https://api.bilibili.com/x/player/v2?'
let season_id = document.querySelector("meta[property='og:url']").content.match(/ss(\d+)/g)[0].replace('ss', '')
let params = ['aid=' + aid, 'cid=' + cid, 'season_id=' + season_id]
console.log(subtitleApi + params.join('&'))
let subtitleUrl = await fetch(subtitleApi + params.join('&'), { credentials: 'include' })
.then(res => res.json())
.then(res => {
console.log(res)
if (!res['data']['subtitle']['subtitles'].length) {
console.log('未发现字幕'); return ''
} else {
// 0中文简体 1中文繁体
let url = 'https:' + res['data']['subtitle']['subtitles'][0]['subtitle_url']
console.log('发现字幕 - ' + url)
return url
}
})
var subtitleArray = []
if (subtitleUrl) {
subtitleArray = await fetch(subtitleUrl)
.then(res => res.json())
.then(res => {
let subtitleArray = []
res.body.forEach(subtitle => {
subtitleArray.push([subtitle['from'], 'bottom', '#FFFFFF', '', subtitle.content, '', '', '25px'])
})
return subtitleArray
})
danmu.danmuku = subtitleArray
}
// 弹幕
let danmuApi = `https://api.bilibili.com/x/v1/dm/list.so?oid=${cid}`
danmu = await fetch(danmuApi, { credentials: 'include' })
.then(res => res.text())
.then(restxt => {
let matchObj = restxt.match(/<d p=".+?">.+?<\/d>/g)
matchObj.forEach(ele => {
let r = /<d p="(.+?)">(.+?)<\/d>/g.exec(ele)
let params = r[1].split(',')
let content = r[2]
let time = params[0]
let direction = parseInt(params[1])
let fontsize = params[2]
let color = '#' + parseInt(params[3]).toString(16)
let direction_info
if (direction <= 3) {
direction_info = 'right'
} else if (direction == 4) {
direction_info = 'bottom'
} else if (direction == 5) {
direction_info = 'top'
} else {
direction_info = 'right'
}
danmu.danmuku.push([time, direction_info, color, "", content, "", "", `${fontsize}px`])
})
danmu.danmuku.push(["0", 'bottom', '#FF616D', "", `替换弹幕源成功,前方共有${danmu.danmuku.length}条弹幕,请做好准备哟`, "", "", `30px`])
danmu.msg = 'subtitle'
danmu.dannum = danmu.danmuku.length - subtitleArray.length
return danmu
})
GM_setValue('danmu', danmu)
console.log(danmu)
}
return danmu
}
function pageChange() {
// 添加按钮和frame
let parentId = '#toolbar_module'
//添加样式
let style = document.createElement("style")
style.innerHTML = (".coldrainf-get-dm{float:right;}.coldrainf-get-dm>div{display:inline-block;}.coldrainf-get-dm a{font-size:15px;color:#00a1d6;margin:0 12px;line-height:28px;}.coldrainf-get-dm a:hover{cursor:pointer;color:#f25d8e;}")
document.head.appendChild(style)
let addButton = () => {
if (!document.URL.startsWith('https://www.bilibili.com/')) { return }
let ele = document.querySelector(parentId)
let switchButton = document.createElement("div")
switchButton.setAttribute('class', 'share-info')
switchButton.setAttribute('id', 'switch')
switchButton.innerHTML = '<i class="iconfont"></i><span style="background-color: #FB7299; border: 1px solid #FB7299; color: #fff; border-radius: 16px; text-align: center;">切换</span> <!---->'
ele.appendChild(switchButton)
let modules = document.querySelectorAll('.player-module')
switchButton.addEventListener('click', function () {
let activateIndex
for (let i = 0; i < modules.length; i++) {
if (modules[i].style.display == 'block') {
activateIndex = i
modules[i].style.display = 'none'
break
}
}
let nextIndex = (activateIndex < modules.length - 1) ? activateIndex + 1 : 0
modules[nextIndex].style.display = 'block'
// 按钮颜色
let color
if (nextIndex == 0) {
color = '#fb7299'
} else {
color = origin[nextIndex - 1].color
}
switchButton.querySelector('span').style['background-color'] = color
switchButton.querySelector('span').style['border-color'] = color
})
$(switchButton).hover(function () {
let gray = '#757575'
switchButton.querySelector('span').style['background-color'] = gray
switchButton.querySelector('span').style['border-color'] = gray
}, function () {
let activateIndex, color
for (let i = 0; i < modules.length; i++) {
if (modules[i].style.display == 'block') {
activateIndex = i
break
}
}
if (activateIndex == 0) {
color = '#fb7299'
} else {
color = origin[activateIndex - 1].color
}
switchButton.querySelector('span').style['background-color'] = color
switchButton.querySelector('span').style['border-color'] = color
})
}
let addFrame = (index) => {
if (!document.URL.startsWith('https://www.bilibili.com/')) { return }
// 防止匹配到解析网址,控制台会输出错误
if (!document.URL.startsWith('https://www.bilibili.com/')) return
let biliDiv = document.querySelector('#player_module')
biliDiv.style.display = 'block'
// 创建新player_module
let diyDiv = biliDiv.cloneNode(true)
diyDiv.style['padding-left'] = '0px'
diyDiv.style['margin-left'] = '0px'
diyDiv.style.display = 'none'
diyDiv.innerHTML = ""
diyDiv.setAttribute('id', `diy_module_${index}`)
let iframe = document.createElement("iframe")
iframe.id = 'video-iframe'
iframe.style.height = biliDiv.style.height
diyDiv.append(iframe)
let read_url = location.href
iframe.src = origin[index].api + read_url
console.log(iframe.src)
if (document.body.className.includes('player-mode-widescreen')) {
iframe.style.position = 'absolute'
iframe.style.top = '0px'
}
iframe.height = '0%'
iframe.width = '100%'
iframe.setAttribute('frameborder', 'no')
iframe.setAttribute('border', '0')
iframe.setAttribute('allowfullscreen', 'allowfullscreen')
iframe.setAttribute('webkitallowfullscreen', 'webkitallowfullscreen')
document.querySelector('.plp-l').insertBefore(diyDiv, document.querySelector('.media-wrapper'))
}
let init = () => {
// 将所源作为frmae添加到页面
for (let i = 0; i < origin.length; i++) {
addFrame(i)
}
// 设置button
addButton()
}
setTimeout(init, 800)
// 这里延迟可以避免频繁刷新
setTimeout(() => {
let obs = document.querySelector('head title')
if (obs) {
new MutationObserver(function (mutations, observer) {
setTimeout(() => { location.reload() }, 500)
}).observe(obs, { childList: true })
}
}, 800)
}
const origin = [
{ regex: 'barrage', api: 'https://www.cuan.la/m3u8.php?url=', color: '#a62aee' },
{ regex: 'dmku', api: 'https://vip.parwix.com:4433/player/?url=', color: '#ff6429' }
]
window.addEventListener("DOMContentLoaded", ()=>{
// 开启代理
ah.proxy({
onRequest: (config, handler) => {
let match = false
for (let i = 0; i < origin.length; i++) {
if (config.url.search(origin[i].regex) !== -1) {
match = true
break
}
}
if (match) {
console.log('拦截弹幕接口 - ' + config.url)
handler.resolve({
config: config,
status: 200,
headers: { 'content-type': 'text/text' },
response: JSON.stringify(GM_getValue('danmu'))
})
} else handler.next(config)
}
})
})
window.addEventListener("load", () => {
dataQuery().then(
() => {
pageChange()
}
)
})