// ==UserScript==
// @name bilibili网页端添加APP首页推荐
// @namespace indefined
// @version 0.6.0
// @description 网页端首页添加APP首页推荐、全站排行、可选提交不喜欢的视频
// @author indefined
// @supportURL https://github.com/indefined/UserScripts/issues
// @match *://www.bilibili.com/*
// @license MIT
// @connect app.bilibili.com
// @connect api.bilibili.com
// @connect passport.bilibili.com
// @connect link.acg.tv
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @run-at document-idle
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
const style = ``;
//APP首页推荐
function InitRecommend () {
//初始化标题栏并注入推荐下方
element.mainDiv.id = 'recommend';
let scrollBox;
if(element.isNew){
element._s(element.mainDiv.querySelector('.storey-title'),{
innerHTML:style,
childs:[
'
{
try {
const rep = JSON.parse(res.response);
if (rep.code!=0){
loadingDiv.firstChild.innerText = `请求app首页失败 code ${rep.code}msg ${rep.message}`;
return console.error('请求app首页失败',rep);
}
setting.pushHistory(rep.data);
updateRecommend(rep.data);
loadingDiv.style.display = 'none';
} catch (e){
loadingDiv.firstChild.innerText = `请求app首页发生错误 ${e}`;
console.error(e,'请求app首页发生错误');
}
},
onerror: e=>{
loadingDiv.firstChild.innerText = `请求app首页发生错误 ${e}`;
console.error(e,'请求app首页发生错误');
}
});
}
//旧版创建视频卡
function createOldRecommend(data) {
return element._c({
nodeType:'div',
className:'spread-module',
childs:[{
nodeType:'a',target:'_blank',
href:data.goto=='av'?`/video/av${data.param}`:data.uri,
dataset:{
tag_id:data.tag?data.tag.tag_id:'',
id:data.param,goto:data.goto,mid:data.mid,rid:data.tid
},
childs:[
{
nodeType:'div',className:'pic',
childs:[
``,
`${data.tname||data.badge}`,
data.duration&&`${tools.formatNumber(data.duration,'time')}`||'',
data.goto=='av'?{
nodeType:'div',
dataset:{aid:data.param},title:'稍后再看',
className:'watch-later-trigger w-later',
onclick:tools.watchLater
}:'',
(data.dislike_reasons&&setting.accessKey)?{
nodeType:'div',innerText:'X',
className:'dislike-botton',
childs:[{
nodeType:'div',
className:'dislike-list',
childs:data.dislike_reasons.map(reason=>({
nodeType:'div',
dataset:{reason_id:reason.reason_id},
innerText:reason.reason_name,
title:`提交因为【${reason.reason_name}】不喜欢`,
onclick:dislike,
}))
}]
}:''
]
},
`${data.title}
`,
`${tools.formatNumber(data.play)}`
+`${tools.formatNumber(data.danmaku)}`
]
}]
})
}
//新版创建视频卡
function createNewRecommend(data) {
return element._c({
nodeType:'div',style:'display:block',
className:'video-card-common',
childs:[
{
nodeType:'div',className:'card-pic',
dataset:{
tag_id:data.tag?data.tag.tag_id:'',
id:data.param,goto:data.goto,mid:data.mid,rid:data.tid
},
childs:[
``
+ `
`
+ `
${tools.formatNumber(data.play)}`
+(data.like&&`${data.like}
`||'
')
+ `${data.duration&&tools.formatNumber(data.duration,'time')||''}
`,
`${data.tname||data.badge}`,
data.goto=='av'?{
nodeType:'div',
dataset:{aid:data.param},title:'稍后再看',
className:'watch-later-video van-watchlater black',
onclick:tools.watchLater
}:'',
(data.dislike_reasons&&setting.accessKey)?{
nodeType:'div',innerText:'X',
className:'dislike-botton',
childs:[{
nodeType:'div',
className:'dislike-list',
childs:data.dislike_reasons.map(reason=>({
nodeType:'div',
dataset:{reason_id:reason.reason_id},
innerText:reason.reason_name,
title:`提交因为【${reason.reason_name}】不喜欢`,
onclick:dislike,
}))
}]
}:''
]
},
`${data.title}`,
`${data.name||data.badge}`,
]
})
}
//显示推荐视频
function updateRecommend (datas){
const point = listBox.firstChild;
datas.forEach(data=>{
const recommend = element.isNew?createNewRecommend(data):createOldRecommend(data);
recommends.push(point.insertAdjacentElement('beforeBegin',recommend));
});
//移除多余的显示内容
while(setting.pageLimit && recommends.length>setting.pageLimit) listBox.removeChild(recommends.shift());
listBox.scrollTop = 0;
scrollBox.scrollTop = 0;
}
//提交不喜欢视频,视频数据提前绑定在页面元素上
function dislike (ev) {
let target=ev.target,parent=target.parentNode;
let cancel;
let url = `https://app.bilibili.com/x/feed/dislike`;
if (parent.className!='dislike-list'){
cancel = true;
let deep = 1;
while(!parent.dataset.id&&deep++<4){
target = parent;
parent=target.parentNode;
}
if (!parent.dataset.id){
tools.toast('请求撤销稍后再看失败:页面元素异常',ev);
return false;
}
url += `/cancel`;
}else{
parent = parent.parentNode.parentNode;
if(!element.isNew) parent = parent.parentNode;
}
url += `?goto=${parent.dataset.goto}&id=${parent.dataset.id}&mid=${parent.dataset.mid}`
+`&reason_id=${target.dataset.reason_id}&rid=${parent.dataset.rid}&tag_id=${parent.dataset.tag_id}`;
if (setting.accessKey) url += '&access_key='+ setting.accessKey;
const handleCover = ()=>{
if (cancel){
parent.removeChild(target);
}else{
const cover = document.createElement('div');
cover.className = 'dislike-cover';
cover.dataset.reason_id = target.dataset.reason_id;
cover.innerHTML = `
提交成功,但愿服务器以后少给点这种东西。
点击撤销操作`;
cover.onclick = dislike;
parent.appendChild(cover);
}
};
//console.log(url);
GM_xmlhttpRequest({
method: 'GET',url,
onload: res=>{
try {
const par = JSON.parse(res.response);
if (par.code == 0){
handleCover();
}else if((par.code==-101 && par.message=='账号未登录') || par.code==-400){
setting.storageAccessKey(undefined);
tools.toast(`未获取授权或者授权失效,请点击设置重新获取授权`);
}
else{
tools.toast(`请求不喜欢错误 code ${par.code}msg ${par.message}`,{par,url});
}
} catch (e){
tools.toast(`请求不喜欢发生错错误${e}`,e);
}
},
onerror: e=>{
tools.toast(`请求不喜欢发生错误`,e);
}
});
return false;
}
}
//全站排行榜
function InitRanking(){
let rankingAll;
if(element.isNew) {
//……直接把旧版的排行修一修搬过来用吧
rankingAll = element.mainDiv.querySelector('.rank-list');
element._s(rankingAll,{
className:'sec-rank report-wrap-module zone-rank rank-list',
innerHTML:`
查看更多`
});
}
else {
rankingAll = element.mainDiv.querySelector('#ranking_douga');
}
rankingAll.id = 'ranking-all';
const rankingHead = rankingAll.querySelector('.rank-head');
rankingHead.firstChild.innerText = '全站排行';
const tab = rankingHead.querySelector('.bili-tab.rank-tab');
const dropDown = rankingHead.querySelector('.bili-dropdown.rank-dropdown');
const warp = rankingAll.querySelector('.rank-list-wrap');
let type = 1,day = setting.rankingDay;
const data = {1:{},2:{}};
const loading = element.getLoadingDiv();
const detail = {};
dropDown.firstChild.innerText = setting.rankingDays[day];
element._s(dropDown.lastChild,{
innerHTML:'',
childs:Object.entries(setting.rankingDays).map(([value,text])=>({
nodeType:'li',innerText:text,
dataset:{day:value},
className:'dropdown-item'
}))
});
//创建一个显示详情的浮窗
detail.div = element._c({
nodeType:'div',style:'display:none',
className:'video-info-module',
onmouseenter: ()=> (detail.div.style.display = 'block'),
onmouseleave: ()=> (detail.div.style.display = 'none'),
childs:[
'