// ==UserScript==
// @name qb-fix-bilibili
// @version 0.0.24
// @description inQ_Beta wants to fix some of bilibili problem
// @license Apache-2.0
// @author inQ_Beta
// @match https://*.bilibili.com/*
// @grant GM_addStyle
// @grant GM_notification
// @grant unsafeWindow
// @namespace no1xsyzy
// ==/UserScript==
(function() {
"use strict";
function trace(description, center) {
return center;
}
const $ = (x) => document.querySelector(x);
function betterSelector(parentNode2, selector2) {
const className = /^\.([\w_-]+)$/.exec(selector2);
if (className) {
return {
select: () => trace(`betterSelector("${selector2}").select#class`, parentNode2.getElementsByClassName(className[1])[0]),
selectAll: () => trace(
`betterSelector("${selector2}").selectAll#class`,
Array.from(parentNode2.getElementsByClassName(className[1]))
)
};
}
const elementID = /^#([\w_-]+)$/.exec(selector2);
if (elementID) {
return {
select: () => trace(`betterSelector("${selector2}").select#id=${elementID[1]}`, document.getElementById(elementID[1])),
selectAll: () => trace(`betterSelector("${selector2}").selectAll#id=${elementID[1]}`, [
document.getElementById(elementID[1])
])
};
}
const tagName = /^([\w_-]+)$/.exec(selector2);
if (tagName) {
return {
select: () => trace(`betterSelector("${selector2}").select#tag`, parentNode2.getElementsByTagName(tagName[1])[0]),
selectAll: () => trace(
`betterSelector("${selector2}").selectAll#tag`,
Array.from(parentNode2.getElementsByTagName(tagName[1]))
)
};
}
return {
select: () => trace(`betterSelector("${selector2}").select#qs`, parentNode2.querySelector(selector2)),
selectAll: () => trace(`betterSelector("${selector2}").selectAll#qs`, Array.from(parentNode2.querySelectorAll(selector2)))
};
}
function selectAncestor(childNode, selector2) {
let p = childNode;
while (p != null && !p.matches(selector2)) {
p = p.parentElement;
}
return p;
}
function launchObserver({
parentNode: parentNode2,
selector: selector2,
failCallback = null,
successCallback = null,
stopWhenSuccess = true,
config = {
childList: true,
subtree: true
}
}) {
if (!parentNode2) {
parentNode2 = document;
}
const { select, selectAll } = betterSelector(parentNode2, selector2);
let _connected = false;
const off = () => {
if (_connected) {
observer.takeRecords();
observer.disconnect();
_connected = false;
}
};
const on = () => {
if (!_connected) {
observer.observe(parentNode2, config);
_connected = true;
}
};
const connected = () => _connected;
const reroot = (newParentNode) => {
parentNode2 = newParentNode;
};
const wrapped = { on, off, connected, reroot };
const observeFunc = (mutationList) => {
const selected = select();
if (!selected) {
if (failCallback) {
failCallback({ ...wrapped, mutationList });
}
return;
}
if (stopWhenSuccess) {
off();
}
if (successCallback) {
const maybePromise = successCallback({
...wrapped,
selected,
selectAll,
mutationList
});
if (maybePromise instanceof Promise) {
maybePromise.then(() => {
});
}
}
};
const observer = new MutationObserver(observeFunc);
on();
return wrapped;
}
function attrChange({
node,
attributeFilter,
callback,
once = true
}) {
let _connected = false;
let _resolve;
const promise = new Promise((resolve) => {
_resolve = resolve;
});
const wrapped = {
on() {
if (_connected)
return;
_connected = true;
observer.observe(node, { attributeFilter, attributeOldValue: true });
},
off() {
if (!_connected)
return;
_connected = false;
observer.disconnect();
},
connected() {
return _connected;
},
reroot(x) {
if (_connected) {
wrapped.off();
node = x;
wrapped.on();
} else {
node = x;
}
},
then(onfulfill, onrejected) {
return promise.then(onfulfill, onrejected);
}
};
const observer = new MutationObserver((mutationList) => {
if (once) {
wrapped.off();
}
callback(mutationList, wrapped);
_resolve(mutationList[0].attributeName);
});
wrapped.on();
return wrapped;
}
function elementEmerge(selector2, parentNode2, subtree = true) {
const g = betterSelector(parentNode2 ?? document, selector2).select();
if (g)
return Promise.resolve(g);
return new Promise((resolve) => {
launchObserver({
parentNode: parentNode2,
selector: selector2,
successCallback: ({ selected }) => {
resolve(selected);
},
config: { subtree, childList: true }
});
});
}
const waitAppBodyMount = async function() {
const appBody = betterSelector(document, `.app-body`).select();
if (!appBody) {
throw new Error("activity page");
}
await new Promise((resolve) => {
launchObserver({
parentNode: appBody,
selector: `#sections-vm`,
successCallback: ({ selected }) => {
resolve(null);
},
config: { childList: true }
});
});
return appBody;
}();
async function 关注栏尺寸() {
GM_addStyle(`
.section-content-cntr{height:calc(100vh - 250px)!important;}
.follow-cntr{height:calc(100vh - 150px)!important;}
.follow-cntr>.anchor-list{height:auto!important;}
.follow-cntr>.anchor-list>.three-anchor{height:auto!important;}
`);
const sidebarVM = await (async () => {
if (location.pathname === "/") {
return betterSelector(document, `.flying-vm`).select();
} else if (location.pathname === "/p/eden/area-tags") {
return betterSelector(document, `#area-tags`).select();
} else if (/^(?:\/blanc)?\/(\d+)$/.exec(location.pathname)) {
const appBody = await waitAppBodyMount;
return betterSelector(appBody, `#sidebar-vm`).select();
}
})();
const sidebarPopup = await elementEmerge(`.side-bar-popup-cntr`, sidebarVM);
launchObserver({
parentNode: sidebarPopup,
selector: `*`,
successCallback: ({ mutationList }) => {
if (sidebarPopup.style.height !== "0px") {
sidebarPopup.style.bottom = "75px";
sidebarPopup.style.height = "calc(100vh - 150px)";
}
setTimeout(() => $(`.side-bar-popup-cntr.ts-dot-4 .ps`)?.dispatchEvent(new Event("scroll")), 2e3);
},
stopWhenSuccess: false,
config: {
attributes: true,
attributeFilter: ["class"]
}
});
}
const makeTitle$1 = () => `${($(`#area-tags header img+div`) || $(`#area-tags header h2`)).innerText} - 分区列表 - 哔哩哔哩直播`;
const parentNode$3 = $(`#area-tags`);
const selector$4 = `header`;
function 分区标题() {
launchObserver({
parentNode: parentNode$3,
selector: selector$4,
successCallback: () => {
document.title = makeTitle$1();
},
stopWhenSuccess: false
});
document.title = makeTitle$1();
}
const followersTextClass = (followers) => {
if (followers > 1e6) {
return [`${Math.round(followers / 1e5) / 10}m★`, "followers-m"];
} else if (followers > 1e3) {
return [`${Math.round(followers / 100) / 10}k★`, "followers-k"];
} else {
return [`${followers}★`, "followers-1"];
}
};
function defaultCacheStorageFactory(id) {
let store = [];
const get = (key) => store.filter(([k, t, v]) => k === key).map(([k, t, v]) => [t, v])[0] ?? [0, void 0];
const set = (key, time, value) => {
const i = store.findIndex(([k, t, v]) => k === key);
if (i === -1) {
store.push([key, time, value]);
} else {
store[i] = [key, time, value];
}
};
const cleanup = (ttl, now) => {
store = store.filter(([k, t]) => t + ttl > now);
};
return { get, set, cleanup };
}
function timedLRU(func, {
id,
version = 1,
ttl = 10 * 60 * 1e3,
cleanupInterval = 60 * 1e3,
cacheStorageFactory = defaultCacheStorageFactory
}) {
const cacheStorage = cacheStorageFactory(id, version);
let timeout = null;
const cleanup = () => {
if (timeout !== null) {
clearTimeout(timeout);
}
cacheStorage.cleanup(ttl, (/* @__PURE__ */ new Date()).getTime());
timeout = setTimeout(cleanup, cleanupInterval);
};
setTimeout(cleanup, cleanupInterval / 10);
const wrapped = async (k) => {
const t = (/* @__PURE__ */ new Date()).getTime();
let [_, v] = cacheStorage.get(k);
if (v === void 0) {
v = await func(k);
}
cacheStorage.set(k, t, v);
return v;
};
wrapped.cleanup = cleanup;
return wrapped;
}
function localStorageCacheStorageFactory(id, version) {
const get = (key) => JSON.parse(localStorage.getItem(`cacheStore__${id}__${version}__${key}`)) ?? [0, void 0];
const set = (key, time, value) => {
localStorage.setItem(`cacheStore__${id}__${version}__${key}`, JSON.stringify([time, value]));
};
const cleanup = (ttl, now) => {
for (let i = 0; i < localStorage.length; i++) {
const k = localStorage.key(i);
if (!k.startsWith(`cacheStore__${id}__`)) {
continue;
}
if (!k.startsWith(`cacheStore__${id}__${version}__`))
;
const [t, _] = JSON.parse(localStorage.getItem(k));
if (t + ttl < now) {
localStorage.removeItem(k);
}
}
};
return { get, set, cleanup };
}
const getCard = timedLRU(
async (uid) => {
const json = await (await fetch(`https://api.bilibili.com/x/web-interface/card?mid=${uid}`, {
// credentials: 'include',
headers: {
Accept: "application/json"
},
method: "GET",
mode: "cors"
})).json();
if (json.code !== 0) {
throw json.message;
}
const {
data: {
card: { fans, sex }
}
} = json;
return { fans, gender: sex };
},
{
id: "getCard",
version: 2,
ttl: 86400 * 1e3,
cacheStorageFactory: localStorageCacheStorageFactory
}
);
const getFansCount = async (uid) => {
return (await getCard(uid)).fans;
};
const getSexTag = async (uid) => {
const { gender } = await getCard(uid);
switch (gender) {
case "男":
return "♂";
case "女":
return "♀";
default:
return "〼";
}
};
const getInfoByRoom = timedLRU(
async (roomid) => {
const json = await (await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=${roomid}`, {
// credentials: 'include',
headers: {
Accept: "application/json"
},
method: "GET",
mode: "cors"
})).json();
if (json.code !== 0) {
throw json.message;
}
const followers = json.data.anchor_info.relation_info.attention;
return { followers };
},
{
id: "getInfoByRoom",
version: 2,
ttl: 86400 * 1e3,
cacheStorageFactory: localStorageCacheStorageFactory
}
);
const getRoomFollowers = async (roomid) => {
return (await getInfoByRoom(roomid)).followers;
};
async function* getDynamicFeed({
timezone = -480,
type = "all"
}) {
let page = 1;
let json = await (await fetch(
`https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=${timezone}&type=${type}&page=${page}`,
{
credentials: "include",
headers: {
Accept: "application/json"
},
method: "GET",
mode: "cors"
}
)).json();
if (json.code === 0) {
for (const item of json.data.items) {
yield item;
}
} else {
throw json.message;
}
while (json.data.has_more) {
page += 1;
json = await (await fetch(
`https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=${timezone}&type=${type}&offset=${json.data.offset}&page=${page}`,
{
credentials: "include",
headers: {
Accept: "application/json"
},
method: "GET",
mode: "cors"
}
)).json();
if (json.code === 0) {
for (const item of json.data.items) {
yield item;
}
} else {
throw json.message;
}
}
}
function compareDynamicID(a, b) {
if (a === b)
return 0;
if (a.length < b.length)
return -1;
if (a.length > b.length)
return 1;
if (a < b)
return -1;
if (a > b)
return 1;
}
function recordDynamicFeed(spec) {
const registry = [];
const gen = getDynamicFeed(spec);
const extend = async (n = 1) => {
for (let i = 0; i < n; i++) {
let v;
try {
v = (await gen.next()).value;
} catch (err) {
}
if (v) {
registry.push(v);
} else {
return false;
}
}
return true;
};
const getByIndex = async (i) => {
while (registry.length < i) {
if (!await extend())
break;
}
if (registry.length > i) {
return registry[i];
}
};
const lastVisibleDynamic = () => {
for (let i = registry.length - 1; i >= 0; i--) {
if (registry[i].visible) {
return registry[i];
}
}
return null;
};
const getByDynamicID = async (did) => {
if (!registry.length && !await extend()) {
return null;
}
do {
if (registry[registry.length - 1].id_str === did) {
return registry[registry.length - 1];
}
if (compareDynamicID(lastVisibleDynamic().id_str, did) < 0) {
for (const dyn of registry) {
if (dyn.id_str === did) {
return dyn;
}
}
return null;
}
} while (await extend());
};
const getByBVID = async (bvid) => {
if (spec.type === "article") {
return null;
}
for (const dyn of registry) {
if (dyn.modules.module_dynamic.major.archive.bvid === bvid) {
return dyn;
}
}
do {
if (lastVisibleDynamic()?.modules.module_dynamic.major.archive.bvid === bvid) {
return lastVisibleDynamic();
}
} while (await extend());
return null;
};
return { getByIndex, getByDynamicID, getByBVID };
}
const CARDCLS$1 = "Item_1EohdhbR";
const NAMECLS = "Item_QAOnosoB";
const parentNode$2 = $(`#area-tag-list`);
const selector$3 = `.${CARDCLS$1}`;
GM_addStyle(`
.${NAMECLS}.processed::after {
content: attr(data-followers);
}
.${NAMECLS}.processed.followers-m {
color: purple !important;
}
.${NAMECLS}.processed.followers-k {
color: grey !important;
}
.${NAMECLS}.processed.followers-1 {
color: red !important;
}
`);
function 分区添加粉丝数() {
launchObserver({
parentNode: parentNode$2,
selector: selector$3,
successCallback: ({ selectAll }) => {
for (const card of selectAll()) {
(async () => {
const nametag = card.querySelector(`.${NAMECLS}`);
if (nametag.classList.contains("processed")) {
return;
}
const followers = await getRoomFollowers(card.pathname.slice(1));
const [txt, cls] = followersTextClass(followers);
nametag.dataset.followers = txt;
nametag.title = txt;
nametag.classList.add("processed");
nametag.classList.add(cls);
})();
}
},
stopWhenSuccess: false
});
}
const CARDCLS = "Item_1EohdhbR";
const TITLECLS = "Item_2GEmdhg6";
const parentNode$1 = $(`#area-tag-list`);
const selector$2 = `.${CARDCLS}`;
function 分区卡片直播间标题指向() {
launchObserver({
parentNode: parentNode$1,
selector: selector$2,
successCallback: ({ selectAll }) => {
for (const card of selectAll()) {
(async () => {
const titletag = card.querySelector(`.${TITLECLS}`);
titletag.title = titletag.textContent.trim();
})();
}
},
stopWhenSuccess: false
});
}
function 分区() {
关注栏尺寸();
分区标题();
分区添加粉丝数();
分区卡片直播间标题指向();
}
function liveStatus() {
const liveStatus2 = betterSelector(document, `.live-status`).select().innerText;
switch (liveStatus2) {
case "直播":
return "▶️";
case "闲置":
return "⏹️";
case "轮播":
return "🔁";
default:
return `【${liveStatus2}】`;
}
}
const liveTitle = () => betterSelector(document, `.live-title`).select().innerText;
const liveHost = () => betterSelector(document, `.room-owner-username`).select().innerText;
const makeTitle = () => `${liveStatus()} ${liveTitle()} - ${liveHost()} - 哔哩哔哩直播`;
const selector$1 = `.live-title`;
async function 直播间标题() {
launchObserver({
parentNode: await elementEmerge(`#head-info-vm .left-header-area`),
selector: selector$1,
successCallback: () => {
document.title = makeTitle();
},
stopWhenSuccess: false
});
document.title = makeTitle();
}
function 通用表情框尺寸修复() {
GM_addStyle(`
#control-panel-ctnr-box > .border-box.top-left[style^="transform-origin: 249px "],
#control-panel-ctnr-box > .border-box.top-left[style^="transform-origin: 251px "]
{
height: 500px
}
`);
}
const parentNode = betterSelector(document, `#chat-items`).select();
const selector = `.user-name`;
GM_addStyle(`
.infoline::before{
content: attr(data-infoline);
}
.infoline.followers-m::before{
color: purple;
}
.infoline.followers-k::before{
color: red;
}
`);
const append = async (un) => {
const uid = selectAncestor(un, `.chat-item`).dataset.uid;
const fans = await getFansCount(uid);
const [txt, cls] = followersTextClass(fans);
const sextag = await getSexTag(uid);
un.dataset.infoline = `${sextag} ${txt} `;
if (cls !== "")
un.classList.add(cls);
};
function 直播间留言者显示粉丝数() {
launchObserver({
parentNode,
selector,
successCallback: ({ selectAll }) => {
for (const un of selectAll()) {
if (!un.classList.contains("infoline")) {
un.classList.add("infoline");
append(un);
}
}
},
stopWhenSuccess: false
});
}
async function 自动刷新崩溃直播间() {
await new Promise((resolve) => setTimeout(resolve, 5e3));
const player = betterSelector(document, `#live-player`).select();
const video = elementEmerge(`video`, player, false).then((x) => void 0);
const endingPanel = elementEmerge(`.web-player-ending-panel`, player, false).then(
(x) => void 0
);
const errorPanel = elementEmerge(`.web-player-error-panel`, player, false).then((x) => void 0);
const last = await Promise.race([video, endingPanel, errorPanel]);
if (last.tagName === "VIDEO")
;
else if (last.classList.contains("web-player-error-panel")) {
location.reload();
}
}
function define(name, defaultValue) {
const v = localStorage.getItem(name);
if (v === null) {
localStorage.setItem(name, JSON.stringify(defaultValue));
}
return {
get() {
return localStorage.getItem(name);
},
set(v2) {
return localStorage.setItem(name, JSON.stringify(v2));
}
};
}
const oldFetch = unsafeWindow.fetch;
const middlewares = [];
unsafeWindow.fetch = function(input, init = {}) {
const request = new Request(input, init);
return processFetchWithMiddlewares(middlewares)(request);
};
const processFetchWithMiddlewares = function(middlewares2) {
if (middlewares2.length === 0) {
return oldFetch;
}
const [head, ...tail] = middlewares2;
const next = processFetchWithMiddlewares(tail);
if (head.type === "before") {
return (input) => next(head.func(input));
} else if (head.type === "after") {
return (input) => head.func(next(input));
} else if (head.type === "wrap") {
return (input) => head.func(next, input);
}
};
function hijack(m) {
middlewares.push(m);
}
const MCDN_RE = /[xy0-9]+\.mcdn\.bilivideo\.cn:\d+/;
const QUALITY_SUFFIX_RE = /(\d+)_(?:minihevc|prohevc|bluray)/g;
const disableMcdn = define("disableMcdn", true);
let forceHighestQuality = true;
let recentErrors = 0;
setInterval(() => {
if (recentErrors > 0) {
recentErrors /= 2;
}
}, 1e4);
function healthChecker(promise) {
promise.then((response) => {
if (!response.url.match(/\.(m3u8|m4s)/))
return;
if (response.status >= 400 && response.status < 500) {
recentErrors++;
if (recentErrors >= 5 && forceHighestQuality) {
forceHighestQuality = false;
GM_notification({
title: "真原画",
text: "最高清晰度可能不可用,取消强制",
timeout: 3e3,
silent: true
});
}
}
});
}
function 真原画() {
hijack({
type: "wrap",
func: async (fetch2, req) => {
try {
if (MCDN_RE.test(req.url) && disableMcdn.get()) {
return Promise.reject(new Error());
}
if (QUALITY_SUFFIX_RE.test(req.url) && forceHighestQuality) {
req = new Request(req.url.replace(QUALITY_SUFFIX_RE, "$1"), req);
}
const url = req.url;
const promise = fetch2(req);
healthChecker(promise);
return promise;
} catch (e) {
}
return fetch2(req);
}
});
}
function 直播间() {
关注栏尺寸();
直播间标题();
直播间留言者显示粉丝数();
通用表情框尺寸修复();
自动刷新崩溃直播间();
真原画();
}
function 直播主页() {
关注栏尺寸();
}
async function 分离视频类型() {
GM_addStyle(`
.qfb__subselect_list {display: none;}
.bili-dyn-list-tabs__item.active:nth-child(2) ~ .qfb__subselect_list {
display: flex;
}
#qfb_upload, #qfb_live_replay {
display: none;
}
#qfb_upload:not(:checked) ~ .bili-dyn-list-tabs .qfb_upload::before {content:"☐"}
#qfb_upload:checked ~ .bili-dyn-list-tabs .qfb_upload::before {content:"☑"}
#qfb_upload:not(:checked) ~ .bili-dyn-list .qfb_upload {
display: none;
}
#qfb_live_replay:not(:checked) ~ .bili-dyn-list-tabs .qfb_live_replay::before {content:"☐"}
#qfb_live_replay:checked ~ .bili-dyn-list-tabs .qfb_live_replay::before {content:"☑"}
#qfb_live_replay:not(:checked) ~ .bili-dyn-list .qfb_live_replay {
display: none;
}
`);
const listTabs = await elementEmerge(`.bili-dyn-list-tabs`);
const cmbUpload = document.createElement("input");
cmbUpload.setAttribute("type", "checkbox");
cmbUpload.setAttribute("id", "qfb_upload");
cmbUpload.checked = true;
listTabs.before(cmbUpload);
const cmbLiveReplay = document.createElement("input");
cmbLiveReplay.setAttribute("type", "checkbox");
cmbLiveReplay.setAttribute("id", "qfb_live_replay");
cmbLiveReplay.checked = true;
listTabs.before(cmbLiveReplay);
const listTabsUpload = await elementEmerge(`.bili-dyn-list-tabs__item:nth-child(2)`, listTabs);
const subSelect = document.createElement("div");
subSelect.classList.add("bili-dyn-list-tabs");
subSelect.classList.add("qfb__subselect_list");
subSelect.innerHTML = `
<div class="bili-dyn-list-tabs__list">
<label class="bili-dyn-list-tabs__item qfb_upload" for="qfb_upload">
投稿视频
</label>
<label class="bili-dyn-list-tabs__item qfb_live_replay" for="qfb_live_replay">
直播回放
</label>
</div>
`;
listTabs.after(subSelect);
attrChange({
node: listTabsUpload,
attributeFilter: ["class"],
callback: () => {
if (listTabsUpload.classList.contains("active")) {
subSelect.style.display = "flex";
} else {
subSelect.style.display = "none";
}
},
once: false
});
listTabs.addEventListener("click", (e) => {
listTabsUpload.classList.contains("");
if (e.target === listTabsUpload) {
subSelect.style.display = "flex";
} else {
subSelect.style.display = "none";
}
});
const dynList = await elementEmerge(`.bili-dyn-list__items`);
launchObserver({
parentNode: dynList,
selector: `.bili-dyn-list__item`,
successCallback: ({ selectAll }) => {
for (const div of selectAll()) {
if (div.classList.contains("processed"))
continue;
const type = div.getElementsByClassName(`bili-dyn-card-video__badge`)[0]?.textContent.trim();
switch (type) {
case "直播回放":
div.classList.add("qfb_live_replay");
break;
case "合作视频":
case "投稿视频":
div.classList.add("qfb_upload");
break;
}
div.classList.add("processed");
}
},
config: {
childList: true
}
});
}
async function 动态首页联合投稿具名() {
const record = recordDynamicFeed({ type: "video" });
launchObserver({
parentNode: document.body,
selector: `.bili-dyn-item`,
successCallback: async ({ selectAll }) => {
for (const dynItem of selectAll()) {
if (dynItem.dataset.qfb_expanded_did === "processing") {
return;
}
if (dynItem.dataset.qfb_expanded_did && !dynItem.querySelector(`.bili-dyn-item-fold`)) {
dynItem.dataset.qfb_expanded_did = "processing";
const dyn = await record.getByDynamicID(dynItem.querySelector(`.bili-dyn-card-video`).getAttribute("dyn-id"));
const timediv = dynItem.querySelector(`.bili-dyn-time`);
timediv.innerHTML = `${dyn.modules.module_author.pub_time} · ${dyn.modules.module_author.pub_action}`;
delete dynItem.dataset.qfb_expanded_did;
} else if (!dynItem.dataset.qfb_expanded_did && dynItem.querySelector(`.bili-dyn-item-fold`)) {
dynItem.dataset.qfb_expanded_did = "processing";
const dyn = await record.getByDynamicID(dynItem.querySelector(`.bili-dyn-card-video`).getAttribute("dyn-id"));
const timediv = dynItem.querySelector(`.bili-dyn-time`);
if (!dyn.modules.module_fold)
return;
const description = (await Promise.all(dyn.modules.module_fold.ids.map((did) => record.getByDynamicID(did)))).map((dyn2) => `<a href="${dyn2.modules.module_author.jump_url}">${dyn2.modules.module_author.name}</a>`).join(`、`);
timediv.innerHTML = `${dyn.modules.module_author.pub_time} · 与${description}联合创作`;
dynItem.dataset.qfb_expanded_did = dyn.id_str;
}
}
},
stopWhenSuccess: false
});
}
function 动态页面() {
动态首页联合投稿具名();
分离视频类型();
}
async function 单条动态页面$1() {
const dyn = await elementEmerge(`.bili-rich-text`, document);
const uname = $(`.bili-dyn-title>span`).textContent.trim();
const dtime = $(`.bili-dyn-time`).textContent.trim();
const dcont = dyn.textContent.trim();
const ddisp = dcont.length > 23 ? dcont.slice(0, 20) + "..." : dcont;
document.title = `${uname} 于 ${dtime} 说道:『${ddisp}』-哔哩哔哩`;
}
async function opus$1() {
const uname = $(`.opus-module-author__name`).textContent.trim();
const dtime = $(`.opus-module-author__pub__text`).textContent.trim();
const dcont = $(`.opus-module-content`).textContent.trim();
const ddisp = dcont.length > 23 ? dcont.slice(0, 20) + "..." : dcont;
document.title = `${uname} 于 ${dtime} 说道:『${ddisp}』-哔哩哔哩`;
}
function 单条动态页面() {
单条动态页面$1();
}
function opus() {
opus$1();
}
async function 排序粉丝勋章() {
const list = await elementEmerge(`.medalList .list`);
Array.from(list.children).sort(
(a, b) => betterSelector(b, ".btn").selectAll().length - betterSelector(a, ".btn").selectAll().length || betterSelector(b, ".living").selectAll().length - betterSelector(a, ".living").selectAll().length || +betterSelector(b, ".m-medal__fans-medal-level").select().textContent - +betterSelector(a, ".m-medal__fans-medal-level").select().textContent
).forEach((node) => list.appendChild(node));
}
function 粉丝勋章页() {
排序粉丝勋章();
}
function 专栏可以复制() {
$(".article-container").addEventListener("copy", (e) => e.stopImmediatePropagation(), true);
}
function 专栏() {
专栏可以复制();
}
if (location.host === "live.bilibili.com") {
if (location.pathname === "/") {
直播主页();
} else if (location.pathname === "/p/eden/area-tags") {
分区();
} else if (location.pathname === "/p/html/live-fansmedal-wall/") {
粉丝勋章页();
} else if (/^(?:\/blanc)?\/(\d+)$/.exec(location.pathname) && $(`.app-body`)) {
直播间();
} else
;
} else if (location.host === "space.bilibili.com")
;
else if (location.host === "t.bilibili.com") {
if (/\/\d+/.exec(location.pathname)) {
单条动态页面();
} else {
动态页面();
}
} else if (location.host === "www.bilibili.com") {
if (/^\/opus\//.exec(location.pathname)) {
opus();
} else if (location.pathname.startsWith("/read/cv")) {
专栏();
}
} else
;
})();