// ==UserScript==
// @name bilibili-joybook
// @namespace https://github.com/PC6live/bilibili-joybook-tampermonkey
// @version 0.0.14
// @author PC6live
// @description 共享大会员
// @license MIT
// @homepage https://github.com/PC6live/bilibili-joybook-tampermonkey
// @supportURL https://github.com/PC6live/bilibili-joybook-tampermonkey/issues
// @match *://*.bilibili.com/*
// @exclude *://passport.bilibili.com/*
// @connect bilibili.com
// @grant GM_addStyle
// @grant GM_cookie
// @grant GM_deleteValue
// @grant GM_getTab
// @grant GM_getValue
// @grant GM_listValues
// @grant GM_saveTab
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @run-at document-start
// @noframes
// ==/UserScript==
(o=>{if(typeof GM_addStyle=="function"){GM_addStyle(o);return}const t=document.createElement("style");t.textContent=o,document.head.append(t)})(" .d-none{display:none}.button{display:flex;min-width:32px;min-height:32px;border-radius:50%;overflow:hidden;border:2px solid rgb(138,138,138);cursor:pointer}#joybook-container{z-index:99;width:48px;height:48px;position:fixed;bottom:30px;left:-30px;transition:.3s ease-in-out}#joybook-settings{position:relative;display:flex;flex-direction:column;justify-content:center;align-items:center}.joybook-avatar{box-sizing:border-box;position:relative;cursor:pointer;overflow:hidden;border-radius:50%;background-color:#888;border:4px solid #fb7299;opacity:1;width:100%;height:100%}.joybook-avatar>img{width:100%;height:100%}.joybook-avatar.user{border:4px solid #47b5ff}#settings-options-container{position:relative}#settings-options-container>*{margin:6px 0} ");
(function () {
'use strict';
var _GM_cookie = /* @__PURE__ */ (() => typeof GM_cookie != "undefined" ? GM_cookie : void 0)();
var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
var _GM_getTab = /* @__PURE__ */ (() => typeof GM_getTab != "undefined" ? GM_getTab : void 0)();
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_listValues = /* @__PURE__ */ (() => typeof GM_listValues != "undefined" ? GM_listValues : void 0)();
var _GM_saveTab = /* @__PURE__ */ (() => typeof GM_saveTab != "undefined" ? GM_saveTab : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)();
var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)();
const USER_INFO_URL = "https://api.bilibili.com/x/web-interface/nav";
const get = (key, defaultValue) => {
return _GM_getValue(key, defaultValue);
};
const set = (key, value) => {
_GM_setValue(key, value);
};
const del = (key) => {
_GM_deleteValue(key);
};
const store = {
get,
set,
del,
getAll: () => {
const key = _GM_listValues();
const obj = {};
key.forEach((v) => {
obj[v] = _GM_getValue(v);
});
return obj;
}
};
const cookie = {
get: (details = {}) => new Promise(
(resolve2) => _GM_cookie.list(details, (cookies) => resolve2(cookies))
),
set: async (cookies) => Promise.all(
cookies.map(
(v) => new Promise((resolve2) => _GM_cookie.set(v, (error) => resolve2(error)))
)
),
delete: async (cookies) => Promise.all(
cookies.map(
(v) => new Promise(
(resolve2) => _GM_cookie.delete(v, (error) => resolve2(error))
)
)
),
deleteAll: async () => cookie.delete(await cookie.get())
};
const sleep = (time = 1) => new Promise((resolve2) => setTimeout(resolve2, 1e3 * time));
const createElement = (str) => {
const el = document.createElement("div");
el.innerHTML = str;
return el.firstElementChild;
};
const deleteAllValue = () => _GM_listValues().forEach((v) => _GM_deleteValue(v));
const message = (message2) => {
console.log(`bili-joybook: ${message2}`);
};
function cookiesReady() {
const { userCookie, vipCookie } = store.getAll();
return !!userCookie && !!vipCookie;
}
function cookieToString(cookies) {
return cookies.map((v) => `${v.name}=${v.value}`).join("; ");
}
const container = document.createElement("div");
function avatar() {
const { userCookie, vipCookie } = store.getAll();
const cookie2 = vipCookie || userCookie;
_GM_xmlhttpRequest({
url: USER_INFO_URL,
cookie: cookie2 && cookieToString(cookie2),
anonymous: true,
headers: {
referer: window.location.href
},
onload(resp) {
const { face, vipStatus } = JSON.parse(resp.response).data;
const avatarClass = vipStatus ? "joybook-avatar" : "joybook-avatar user";
const img = face ? `<img src=${face}></img>` : "";
const html = createElement(`
<div class="${avatarClass}">
${img}
</div>
`);
if (html) container.appendChild(html);
}
});
}
function handleEvent() {
const delay = 1500;
let timeout;
const onMouseEnter = () => {
if (timeout) window.clearTimeout(timeout);
container.style.transform = "translateX(50px)";
};
const onMouseLeave = () => {
timeout = window.setTimeout(() => {
container.style.transform = "translateX(0px)";
}, delay);
};
const onDeleteClick = async () => {
const result = window.confirm("确定要删除脚本数据吗?");
if (!result) return;
deleteAllValue();
await cookie.deleteAll();
window.location.reload();
};
container.addEventListener("mouseenter", onMouseEnter);
container.addEventListener("mouseleave", onMouseLeave);
container.addEventListener("click", onDeleteClick);
}
const __vite_glob_0_0 = () => {
window.addEventListener("load", () => {
container.id = "joybook-container";
document.body.appendChild(container);
avatar();
handleEvent();
});
};
const getUserType = async () => {
const resp = await fetch(USER_INFO_URL, {
method: "get",
credentials: "include"
});
const result = await resp.json();
return result.data;
};
async function handleLogin(key) {
const storeKey = ["SESSDATA", "DedeUserID", "DedeUserID__ckMd5", "bili_jct"];
const cookies = await cookie.get({ domain: ".bilibili.com" });
store.set(
key,
cookies.filter((v) => storeKey.includes(v.name))
);
await cookie.deleteAll();
const { userCookie, vipCookie } = store.getAll();
if (userCookie && vipCookie) {
await cookie.set(userCookie);
}
window.location.reload();
}
const __vite_glob_0_1 = async () => {
const { isLogin, vipStatus } = await getUserType();
if (!isLogin || cookiesReady()) return;
const user = vipStatus ? "vipCookie" : "userCookie";
await handleLogin(user);
};
var events = ["load", "loadend", "timeout", "error", "readystatechange", "abort"];
var OriginXhr = "__origin_xhr";
function configEvent(event, xhrProxy) {
var e = {};
for (var attr in event) e[attr] = event[attr];
e.target = e.currentTarget = xhrProxy;
return e;
}
function hook(proxy2, win) {
win = win || window;
var originXhr = win.XMLHttpRequest;
var hooking = true;
var HookXMLHttpRequest = function() {
var xhr = new originXhr();
for (var i = 0; i < events.length; ++i) {
var key = "on" + events[i];
if (xhr[key] === void 0) xhr[key] = null;
}
for (var attr in xhr) {
var type = "";
try {
type = typeof xhr[attr];
} catch (e) {
}
if (type === "function") {
this[attr] = hookFunction(attr);
} else if (attr !== OriginXhr) {
Object.defineProperty(this, attr, {
get: getterFactory(attr),
set: setterFactory(attr),
enumerable: true
});
}
}
var that = this;
xhr.getProxy = function() {
return that;
};
this[OriginXhr] = xhr;
};
HookXMLHttpRequest.prototype = originXhr.prototype;
HookXMLHttpRequest.prototype.constructor = HookXMLHttpRequest;
win.XMLHttpRequest = HookXMLHttpRequest;
Object.assign(win.XMLHttpRequest, { UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4 });
function getterFactory(attr) {
return function() {
var originValue = this[OriginXhr][attr];
if (hooking) {
var v = this.hasOwnProperty(attr + "_") ? this[attr + "_"] : originValue;
var attrGetterHook = (proxy2[attr] || {})["getter"];
return attrGetterHook && attrGetterHook(v, this) || v;
} else {
return originValue;
}
};
}
function setterFactory(attr) {
return function(v) {
var xhr = this[OriginXhr];
if (hooking) {
var that = this;
var hook2 = proxy2[attr];
if (attr.substring(0, 2) === "on") {
that[attr + "_"] = v;
xhr[attr] = function(e) {
e = configEvent(e, that);
var ret = proxy2[attr] && proxy2[attr].call(that, xhr, e);
ret || v.call(that, e);
};
} else {
var attrSetterHook = (hook2 || {})["setter"];
v = attrSetterHook && attrSetterHook(v, that) || v;
this[attr + "_"] = v;
try {
xhr[attr] = v;
} catch (e) {
}
}
} else {
xhr[attr] = v;
}
};
}
function hookFunction(fun) {
return function() {
var args = [].slice.call(arguments);
if (proxy2[fun] && hooking) {
var ret = proxy2[fun].call(this, args, this[OriginXhr]);
if (ret) return ret;
}
return this[OriginXhr][fun].apply(this[OriginXhr], args);
};
}
function unHook() {
hooking = false;
if (win.XMLHttpRequest === HookXMLHttpRequest) {
win.XMLHttpRequest = originXhr;
HookXMLHttpRequest.prototype.constructor = originXhr;
originXhr = void 0;
}
}
return { originXhr, unHook };
}
var eventLoad = events[0], eventLoadEnd = events[1], eventTimeout = events[2], eventError = events[3], eventReadyStateChange = events[4], eventAbort = events[5];
var prototype = "prototype";
function proxy(proxy2, win) {
win = win || window;
return proxyAjax(proxy2, win);
}
function trim(str) {
return str.replace(/^\s+|\s+$/g, "");
}
function getEventTarget(xhr) {
return xhr.watcher || (xhr.watcher = document.createElement("a"));
}
function triggerListener(xhr, name) {
var xhrProxy = xhr.getProxy();
var callback = "on" + name + "_";
var event = configEvent({ type: name }, xhrProxy);
xhrProxy[callback] && xhrProxy[callback](event);
var evt;
if (typeof Event === "function") {
evt = new Event(name, { bubbles: false });
} else {
evt = document.createEvent("Event");
evt.initEvent(name, false, true);
}
getEventTarget(xhr).dispatchEvent(evt);
}
function Handler(xhr) {
this.xhr = xhr;
this.xhrProxy = xhr.getProxy();
}
Handler[prototype] = /* @__PURE__ */ Object.create({
resolve: function resolve(response) {
var xhrProxy = this.xhrProxy;
var xhr = this.xhr;
xhrProxy.readyState = 4;
xhr.resHeader = response.headers;
xhrProxy.response = xhrProxy.responseText = response.response;
xhrProxy.statusText = response.statusText;
xhrProxy.status = response.status;
triggerListener(xhr, eventReadyStateChange);
triggerListener(xhr, eventLoad);
triggerListener(xhr, eventLoadEnd);
},
reject: function reject(error) {
this.xhrProxy.status = 0;
triggerListener(this.xhr, error.type);
triggerListener(this.xhr, eventLoadEnd);
}
});
function makeHandler(next) {
function sub(xhr) {
Handler.call(this, xhr);
}
sub[prototype] = Object.create(Handler[prototype]);
sub[prototype].next = next;
return sub;
}
var RequestHandler = makeHandler(function(rq) {
var xhr = this.xhr;
rq = rq || xhr.config;
xhr.withCredentials = rq.withCredentials;
xhr.open(rq.method, rq.url, rq.async !== false, rq.user, rq.password);
for (var key in rq.headers) {
xhr.setRequestHeader(key, rq.headers[key]);
}
xhr.send(rq.body);
});
var ResponseHandler = makeHandler(function(response) {
this.resolve(response);
});
var ErrorHandler = makeHandler(function(error) {
this.reject(error);
});
function proxyAjax(proxy2, win) {
var onRequest = proxy2.onRequest, onResponse = proxy2.onResponse, onError = proxy2.onError;
function getResponseData(xhrProxy) {
var responseType = xhrProxy.responseType;
if (!responseType || responseType === "text") {
return xhrProxy.responseText;
}
var response = xhrProxy.response;
if (responseType === "json" && !response) {
try {
return JSON.parse(xhrProxy.responseText);
} catch (e) {
console.warn(e);
}
}
return response;
}
function handleResponse(xhr, xhrProxy) {
var handler = new ResponseHandler(xhr);
var ret = {
response: getResponseData(xhrProxy),
status: xhrProxy.status,
statusText: xhrProxy.statusText,
config: xhr.config,
headers: xhr.resHeader || xhr.getAllResponseHeaders().split("\r\n").reduce(function(ob, str) {
if (str === "") return ob;
var m = str.split(":");
ob[m.shift()] = trim(m.join(":"));
return ob;
}, {})
};
if (!onResponse) return handler.resolve(ret);
onResponse(ret, handler);
}
function onerror(xhr, xhrProxy, error, errorType) {
var handler = new ErrorHandler(xhr);
error = { config: xhr.config, error, type: errorType };
if (onError) {
onError(error, handler);
} else {
handler.next(error);
}
}
function preventXhrProxyCallback() {
return true;
}
function errorCallback(errorType) {
return function(xhr, e) {
onerror(xhr, this, e, errorType);
return true;
};
}
function stateChangeCallback(xhr, xhrProxy) {
if (xhr.readyState === 4 && xhr.status !== 0) {
handleResponse(xhr, xhrProxy);
} else if (xhr.readyState !== 4) {
triggerListener(xhr, eventReadyStateChange);
}
return true;
}
var { originXhr, unHook } = hook({
onload: preventXhrProxyCallback,
onloadend: preventXhrProxyCallback,
onerror: errorCallback(eventError),
ontimeout: errorCallback(eventTimeout),
onabort: errorCallback(eventAbort),
onreadystatechange: function(xhr) {
return stateChangeCallback(xhr, this);
},
open: function open(args, xhr) {
var _this = this;
var config = xhr.config = { headers: {} };
config.method = args[0];
config.url = args[1];
config.async = args[2];
config.user = args[3];
config.password = args[4];
config.xhr = xhr;
var evName = "on" + eventReadyStateChange;
if (!xhr[evName]) {
xhr[evName] = function() {
return stateChangeCallback(xhr, _this);
};
}
if (onRequest) return true;
},
send: function(args, xhr) {
var config = xhr.config;
config.withCredentials = xhr.withCredentials;
config.body = args[0];
if (onRequest) {
var req = function() {
onRequest(config, new RequestHandler(xhr));
};
config.async === false ? req() : setTimeout(req);
return true;
}
},
setRequestHeader: function(args, xhr) {
xhr.config.headers[args[0].toLowerCase()] = args[1];
if (onRequest) return true;
},
addEventListener: function(args, xhr) {
var _this = this;
if (events.indexOf(args[0]) !== -1) {
var handler = args[1];
getEventTarget(xhr).addEventListener(args[0], function(e) {
var event = configEvent(e, _this);
event.type = args[0];
event.isTrusted = true;
handler.call(_this, event);
});
return true;
}
},
getAllResponseHeaders: function(_, xhr) {
var headers = xhr.resHeader;
if (headers) {
var header = "";
for (var key in headers) {
header += key + ": " + headers[key] + "\r\n";
}
return header;
}
},
getResponseHeader: function(args, xhr) {
var headers = xhr.resHeader;
if (headers) {
return headers[(args[0] || "").toLowerCase()];
}
}
}, win);
return {
originXhr,
unProxy: unHook
};
}
const reloadByLogin = (url) => {
if (url.includes("/passport-login/web/login")) {
message("login reload");
sleep(1).then(() => window.location.reload());
}
};
const listenLogout = async (url) => {
if (url.includes("/login/exit")) {
store.del("userCookie");
await cookie.deleteAll();
window.location.reload();
}
};
const request = (config) => {
return new Promise((resolve2) => {
const { vipCookie } = store.getAll();
if (!vipCookie) return;
const url = new URL(config.url, window.location.href);
_GM_xmlhttpRequest({
method: config.method,
url: url.href,
anonymous: true,
cookie: cookieToString(vipCookie),
headers: {
referer: window.location.href
},
responseType: "json",
onload(event) {
return resolve2(event.response);
},
onabort() {
return resolve2();
},
onerror() {
return resolve2();
}
});
});
};
const handlers = [
{
// 视频信息
url: "api.bilibili.com/x/player/wbi/playurl",
on: (userResponse, vipResponse) => {
delete vipResponse.data.last_play_cid;
delete vipResponse.data.last_play_time;
userResponse.data = {
...userResponse.data,
...vipResponse.data
};
return userResponse;
}
},
{
// 用户信息
url: "api.bilibili.com/x/player/wbi/v2",
on: (userResponse, vipResponse) => {
userResponse.data.vip = vipResponse.data.vip;
return userResponse;
}
},
{
// bangumi 信息
url: "api.bilibili.com/pgc/player/web/v2/playurl",
on: (userResponse, vipResponse) => {
userResponse.result = vipResponse.result;
return userResponse;
}
}
];
const __vite_glob_0_2 = () => {
proxy(
{
//请求发起前进入
onRequest: (config, handler) => {
reloadByLogin(config.url);
listenLogout(config.url);
handler.next(config);
},
//请求发生错误时进入,比如超时;注意,不包括http状态码错误,如404仍然会认为请求成功
onError: (err, handler) => {
handler.next(err);
},
//请求成功后进入
onResponse: async (response, handler) => {
const requestUrl = response.config.url;
for (const { url, on } of handlers) {
if (requestUrl.includes(url)) {
const vipResponse = await request(response.config);
const userResponse = JSON.parse(response.response);
if (vipResponse) {
response.response = on(
structuredClone(userResponse),
structuredClone(vipResponse)
);
return handler.resolve(response);
}
}
}
handler.next(response);
}
},
_unsafeWindow
);
};
const __vite_glob_0_3 = async () => {
let qualityCookie = (await cookie.get({ name: "CURRENT_QUALITY" }))[0];
if (!qualityCookie) {
qualityCookie = {
domain: ".bilibili.com",
hostOnly: false,
httpOnly: false,
name: "CURRENT_QUALITY",
path: "/",
sameSite: "unspecified",
secure: false,
session: false,
value: "120"
};
} else {
qualityCookie.value = "120";
}
_GM_cookie.set(qualityCookie);
Object.defineProperty(_unsafeWindow, "__playinfo__", {
configurable: true,
set() {
},
get() {
}
});
};
const __vite_glob_0_4 = () => {
window.addEventListener("DOMContentLoaded", () => {
var _a;
const tips = document.querySelector(".adblock-tips");
(_a = tips == null ? void 0 : tips.parentElement) == null ? void 0 : _a.removeChild(tips);
});
};
const __vite_glob_0_5 = () => {
const { vipCookie, userCookie } = store.getAll();
if (!vipCookie || !userCookie) return;
if (window.location.pathname.includes("bangumi")) {
_GM_getTab(async (tab) => {
if (tab.dirty) {
await cookie.set(userCookie);
tab.dirty = false;
_GM_saveTab(tab);
} else {
await cookie.set(vipCookie);
tab.dirty = true;
_GM_saveTab(tab);
window.location.reload();
}
});
}
};
async function main() {
const components = /* @__PURE__ */ Object.assign({
"./components/avatar.ts": __vite_glob_0_0,
"./components/initialize.ts": __vite_glob_0_1,
"./components/listenerAjax.ts": __vite_glob_0_2,
"./components/quality.ts": __vite_glob_0_3,
"./components/removeTips.ts": __vite_glob_0_4,
"./components/unlockVideo.ts": __vite_glob_0_5
});
for (const script of Object.values(components)) {
script();
}
message("所有组件加载完成");
}
main();
})();