BiliBili+

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

目前為 2017-06-21 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        BiliBili+
// @namespace   [email protected]
// @include     /https?:\/\/www\.bilibili\.com\/account\/dynamic/
// @version     2017-6-21a
// @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 = new URLSearchParams({
		aid: av,
		jsonp: "jsonp",
		csrf: GetCookieValue('bili_jct')
	});
	
	try{
		result = await (await fetch(url, {method: "POST", credentials: "include", body: params})).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() : '';
}