BiliBili+

在B站个人动态的视频列表里直接加入稍后看按钮

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name        BiliBili+
// @namespace   [email protected]
// @include     /https?:\/\/www\.bilibili\.com\/account\/dynamic/
// @version     2017-6-21b
// @grant       none
// jshint esversion:6
// @description 在B站个人动态的视频列表里直接加入稍后看按钮
// ==/UserScript==

const WATCH_LATER_TEXT = "  【稍候再看】  ";
const REMOVE_WATCH_LATER_TEXT = "  【移除稍候再看】  ";
const WATCH_LATER_BG_COLOR = "#1672A4";

// 观察者,执行“添加稍后看按钮”
let observer = new MutationObserver(AddWatchLaterButton);
// 视频列表
let vidsList = document.querySelector(".stm-lst");
if(vidsList){
	observer.observe( vidsList, { childList: true } );
} else {
	alert("[Bili+]: Vids list not exist");
}

// 添加稍候看按钮
async function AddWatchLaterButton(recs){
	// console.log("[Bili+]: recs %o", recs); // DEBUG
	
	// 先获取稍后看列表
	let addedVids = await GettingAddedWatchList();
	
	// console.log("[Bili+]: addedVids %o", addedVids); // DEBUG
	for(let rec of recs){
		rec.addedNodes.forEach(vidRow => {
			// 如果是视频,加个按钮
			if(vidRow.className == "stm-lst-item"){
				
				let vid = vidRow.querySelector(".hint>a");
				let av = vid.href;
				av = av.match(/\d+/)[0];
				
				// console.log("[Bili+]: av " + av); // DEBUG
				if(!vid.parentNode.querySelector(".watch-later-btn")){
					let watchLaterBtn = document.createElement("button");
					watchLaterBtn.className = "watch-later-btn";
					watchLaterBtn.style.trasition = "0.5s";
					
					if(!addedVids.includes(parseInt(av))){
						// 不在稍后看里,只改提示
						watchLaterBtn.innerText = WATCH_LATER_TEXT;
					} else {
						// 已在稍后看里,改为移除按钮样式
						watchLaterBtn.innerText = REMOVE_WATCH_LATER_TEXT;
						watchLaterBtn.style.backgroundColor = WATCH_LATER_BG_COLOR;
					}
					
					// 挂添加/移除事件处理
					watchLaterBtn.onclick = ()=>{ ToggleWatchLater(av, watchLaterBtn); };
					
					// 加在链接后面
					vid.parentNode.appendChild(document.createElement("br"));
					vid.parentNode.appendChild(watchLaterBtn);
				}
			}
		});
	}
}

// 获取稍后看列表
async function GettingAddedWatchList(){
	return new Promise(async (resolve, reject)=>{
		let r = null;
		
		let url = new URL(location.protocol + "//api.bilibili.com/x/v2/history/toview/web");
		let params = {
			jsonp: "jsonp",
			sid: GetCookieValue('sid'), // 大概是用户id
			csrf: GetCookieValue('bili_jct') // 并不清楚这是啥
		}
		Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
		
		try{
			r = await (await fetch(url, {method: "GET", credentials: "include"})).json();
		} catch (ex) {
			r = null;
		}
		// console.log("[Bili+]: fetch result %o", r); // DEBUG
		
		if(r && r.data && r.data.list){
			resolve(r.data.list.map(vid=>vid.aid));
		} else {
			reject([])
		}
	});
}

// 切换稍后看状态
async function ToggleWatchLater(av, btn){
	// console.log("[Bili+]: Toggle av %o", av); // DEBUG
	
	// 先获取稍后看列表
	let addedVids = await GettingAddedWatchList();
	
	let isWatchLater = addedVids.includes(parseInt(av));
	// console.log("[Bili+]: " + (isWatchLater ? "Removing from watch later" : "Adding to watch later")); // DEBUG
	
	let result = null;
	let url = new URL(location.protocol + "//api.bilibili.com/x/v2/history/toview/" + (isWatchLater ? "del" : "add"));

	let params = {
		aid: av,
		jsonp: "jsonp",
		csrf: GetCookieValue('bili_jct') // 并不清楚这是啥
	}
	Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
	
	try{
		result = await (await fetch(url, {method: "POST", credentials: "include"})).json();
	} catch (ex) {
		// 一般来说是网络错误
		result = ex;
		btn.innerText = "  【操作失败,请重试】 ";
	}
	
	if(result.code == "0"){
		// 添加/移除成功
		btn.innerText = (isWatchLater ? WATCH_LATER_TEXT : REMOVE_WATCH_LATER_TEXT);
		btn.style.backgroundColor = (isWatchLater ? "" : WATCH_LATER_BG_COLOR);
		if(MessageBox){(new MessageBox).show(btn, "已" + (isWatchLater ? "移除" : "添加"), 700, "info")};
	} else {
		// 服务器返回失败
		if(MessageBox){(new MessageBox).show(btn, "粗错啦:\n" + result.message, 3000, "error")};
		btn.innerText = result.message;
	}
}

// 获取cookie
function GetCookieValue(name) {
	var valueMatch = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
	return valueMatch ? valueMatch.pop() : '';
}