Last active
September 15, 2020 20:40
-
-
Save CL-Jeremy/2240480d24df3b0f829c6cde50264e39 to your computer and use it in GitHub Desktop.
Load external ass subtitle hosted with WsgiDAV 3.0.x for Bilibili's HTML5 player
This file contains 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
// ==UserScript== | |
// @name Load external ass subtitle for Bilibili | |
// @version 0.2.2.3 | |
// @include /:\/\/www\.bilibili\.com\/video\/(BV|[ab]v).*/ | |
// @require https://code.jquery.com/jquery-1.12.4.min.js | |
// @require https://cdn.jsdelivr.net/gh/CL-Jeremy/ASS@next/dist/ass.min.js | |
// @require https://cdn.jsdelivr.net/npm/css-element-queries/src/ResizeSensor.js | |
// @grant GM_addStyle | |
// ==/UserScript== | |
(() => { | |
const domain = 'https://example.tld' // edit here: <protocol>://<domain> | |
const danmakuRepository = '/' // edit here: a directory (with trailing slash) on WsgiDAV containing | |
// ass files of names like: av<avid>-<...>_comments.ass | |
GM_addStyle('\ | |
.ASS-dialogue > span {\ | |
transform: scale(0.83);\ | |
-webkit-transform: scale(0.83);\ | |
-moz-osx-font-smoothing: grayscale;\ | |
}') | |
const fullyLoaded = (callback) => { | |
if (document.readyState === 'complete') { | |
callback() | |
} else { | |
unsafeWindow.addEventListener('load', callback) | |
} | |
} | |
const actionObserver = (callback, filter) => new MutationObserver((mutations) => { | |
mutations.forEach((mutationRecord) => { | |
if (filter === undefined || filter(mutationRecord)) callback() | |
}) | |
}) | |
fullyLoaded(() => { | |
let ass | |
const bilibiliPlayerVideo = $('.bilibili-player-video') | |
const OpacitySlider = '.bilibili-player-setting-opacity' | |
const SettingsPopup = '.bilibili-player-video-danmaku-setting' | |
const PlayerBottom = '.bilibili-player-video-bottom-area' | |
const DanmakuSwitch = '.bilibili-player-video-danmaku-switch' | |
const updateVisibility = () => $('.choose_danmaku').text().match(/^关闭/) ? ass.show() : ass.hide() | |
const updateOpacity = () => $('.ASS-stage').css('opacity', | |
(($(OpacitySlider).find('.bui-bar').css('transform') || '').match(/\(([\d\.]*)/) || | |
localStorage.bilibili_player_settings.match(/"opacity":"(.+?)"/) | |
)[1]) | |
fetch(domain + danmakuRepository) | |
.then(res => res.text()) | |
.then((text) => { | |
$($.parseHTML(text)) | |
.filter('table') | |
.find('a') | |
.each((i, el) => { | |
const file = $.trim(el.href) | |
if (file.match(new RegExp(String.raw`av${$('meta[itemprop="url"]').attr('content').match(/\/video\/av(\d+)/)[1]}.*_comments\.ass$`))) { | |
fetch(file.replace(new RegExp(String.raw`^.*(${location.hostname})?${danmakuRepository}`), domain + danmakuRepository)) | |
.then(res => res.text()) | |
.then((text) => { | |
ass = new ASS(text, bilibiliPlayerVideo.find('video')[0], { | |
container: bilibiliPlayerVideo[0], | |
resampling: 'video-width' | |
}) | |
new ResizeSensor(bilibiliPlayerVideo[0], () => ass.resize()) | |
new ResizeSensor(bilibiliPlayerVideo[0], () => { | |
bilibiliPlayerVideo.attr('style', 'width: 100%; height: 100%;') | |
if ($('#bilibiliPlayer')[0].className.match(/fullscreen|mini/)) | |
bilibiliPlayerVideo.find('video').attr('style', 'width: 100%; height: 100%;') | |
ass.resize() | |
updateOpacity() | |
}) | |
const playerBottomObserver = actionObserver((mutations) => { | |
$(SettingsPopup).mouseover(() => { | |
const observer = actionObserver(updateOpacity); | |
observer.observe( | |
$(OpacitySlider).find('.bui-bar')[0], | |
{ attributes : true, attributeFilter : ['style'] } | |
) | |
$(SettingsPopup).mouseout(() => { observer.disconnect() }) | |
}) | |
var observeVisibility = () => { var o = actionObserver(() => { updateVisibility(); o.disconnect() }); return o } | |
$(DanmakuSwitch).click(() => observeVisibility().observe($('.choose_danmaku')[0], { childList: true })) | |
observeVisibility().observe($(DanmakuSwitch)[0], { childList: true }) | |
$(DanmakuSwitch).append($('<span class="choose_danmaku">' + ( | |
$(DanmakuSwitch).find('.bui-switch-dot').css('margin-left') !== '-18px' ? '开启': '关闭' | |
) + '弹幕</span>')) | |
observeVisibility().observe($('.choose_danmaku')[0], { childList: true }) | |
playerBottomObserver.disconnect() | |
}, (mutationRecord) => { | |
if ($(DanmakuSwitch).find('.bui-switch-label')[0]) return true | |
for (const node of mutationRecord.addedNodes.values()) { | |
if (node.className === 'bui-switch-label') return true | |
} | |
return false | |
}) | |
playerBottomObserver.observe($(PlayerBottom)[0], { childList: true, subtree: true }) | |
}) | |
} | |
}) | |
}) | |
}) | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment