// ==UserScript== // @name bilibili网页端添加APP首页推荐 // @namespace indefined // @version 0.3.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== let accessKey = GM_getValue('biliAppHomeKey'); const storageAccessKey = key => key?GM_setValue('biliAppHomeKey',key):GM_deleteValue('biliAppHomeKey'); const token = (()=>{ try{ return document.cookie.match(/bili_jct=([0-9a-fA-F]{32})/)[1]; }catch(e){ console.error('添加APP首页推荐找不到token,请检查是否登录'); return undefined; } })(); const recommend = (()=>{ try{ return document.querySelector('#bili_douga').cloneNode(true); }catch(e){ console.error('添加APP首页推荐找不到动画版块,可能是网页加载延迟或者b站改版了,请重试或等待更新'); return undefined; } })(); const imgType = (()=>{ try{ return 0==document.createElement('canvas').toDataURL("image/webp").indexOf("data:image/webp")?'webp':'jpg'; }catch(e){ return 'jpg'; } })(); if (recommend){ CreateCss(); InitRecommend(); InitRanking(); } function CreateCss(){ const css = document.createElement('style'); css.type = 'text/css'; css.innerHTML = ` .dislike-botton,.tname { position: absolute; top: 2px; opacity: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; text-align: right; font-weight: bold; -webkit-transition: all .3s; -o-transition: all .3s; transition: all .3s; text-shadow: 0 1px black, 1px 0 black, -1px 0 black, 0 -1px black; color: white; } .spread-module .tname { left: 6px; } .spread-module .dislike-botton { right: 6px; font-size: 14px; } .dislike-list { display:none; } .dislike-list>div:hover { text-decoration: line-through; } .spread-module:hover .pic .tname ,.spread-module .pic:hover .dislike-botton{ opacity: 1; } .dislike-botton:hover .dislike-list{ display:unset; } .dislike-cover { position: absolute; top: 0px; width: 100%; height: 100%; background:hsla(0,0%,100%,.9); text-align: center; font-size: 15px; z-index: 2; } .toast { position: fixed; padding: 12px 24px; font-size: 14px; border-radius: 8px; left:50%; top:50%; width: 240px; margin-left: -120px; color: #fff; background-color: #ffb243; box-shadow: 0 0.2em 0.1em 0.1em rgba(255,190,68,0.2); transition: transform 0.4s cubic-bezier(0.22, 0.58, 0.12, 0.98); animation: link-msg-move-in-top cubic-bezier(0.22, 0.58, 0.12, 0.98) 0.4s; z-index: 10000; }`; document.head.appendChild(css); } function InitRecommend () { recommend.id = 'recommend'; recommend.querySelector('div.zone-title').innerHTML = `
猜你喜欢
换一批
`; const popular = document.querySelector('#home_popularize'); const listBox = recommend.querySelector('div.storey-box.clearfix'); popular.parentElement.insertBefore(recommend,popular.nextSibling); recommend.querySelector('.read-push').onclick = UpdateRecommend; UpdateRecommend(); function UpdateRecommend () { while(listBox.firstChild) listBox.removeChild(listBox.firstChild); const status = getLoadingDiv(); listBox.appendChild(status); GM_xmlhttpRequest({ method: 'GET', url: `https://app.bilibili.com/x/feed/index?build=1&mobi_app=android&idx=${(Date.now()/1000).toFixed(0)}${accessKey?'&access_key='+accessKey:''}`, onload: res=>{ try { const rep = JSON.parse(res.response); if (rep.code!=0){ status.firstChild.innerText = `请求app首页失败 code ${rep.code} msg ${rep.message} 请检查问题重试或打开调试终端查看更多信息`; return console.log('请求app首页失败',rep); } listBox.removeChild(status); rep.data.forEach(data=>{ const item = CreateItem(data); listBox.appendChild(item); }); } catch (e){ status.firstChild.innerText = `请求app首页发生错误 ${e} 请检查问题重试或打开调试终端查看更多信息`; console.error(e,'请求app首页发生错误'); } } }); } recommend.querySelector('div.link-more').onclick = function () { const settingDiv = document.createElement('div'); settingDiv.id = 'biliAppHomeSetting'; settingDiv.style = 'position: fixed;top: 0;bottom: 0;left: 0;right: 0;background: rgba(0,0,0,0.4);z-index: 10000;'; settingDiv.innerHTML = `

APP首页推荐设置

目前获取根据个人观看喜好的APP首页数据和提交定制不喜欢的视频需要获取授权key。

点击获取授权将登录bilibili用户反馈论坛从官方授权接口获取一个授权key,获取的key保存在脚本管理器内。

如果不想使用反馈论坛可不用获取授权,脚本仍然能从官方接口获取随机推荐视频,但内容可能不再根据个人喜好且无法提交不喜欢内容。

点击删除授权可从脚本管理器中删除已获取授权key,脚本将按照没有获取授权的情况执行。

脚本发布页 github问题反馈 当前版本:${GM_info.script.version}
`; const actionButton = settingDiv.querySelector('#biliAppKeyAction'); document.body.appendChild(settingDiv); if (accessKey) { actionButton.innerText = '删除授权'; } actionButton.onclick = ()=>{ if (actionButton.innerText === '删除授权') { storageAccessKey(accessKey = undefined); actionButton.innerText = '获取授权'; return; } else { const timeout = setTimeout(()=>showError('获取授权超时'),2000); const getKey = url => GM_xmlhttpRequest({ method: 'GET', url, onload: res=> { clearTimeout(timeout); const key = res.finalUrl.match(/access_key=([0-9a-z]{32})/); if (key) { storageAccessKey(accessKey = key[1]); actionButton.innerText = '删除授权'; } }, onerror: error=> { clearTimeout(timeout); showError('获取授权失败',error); console.error(error); } }); GM_xmlhttpRequest({ method: 'GET', url:`https://passport.bilibili.com/login/app/third?appkey=27eb53fc9058f8c3&api=http%3A%2F%2Flink.acg.tv%2Fsearch.php%3Fmod%3Dforum&sign=3c7f7018a38a3e674a8a778c97d44e67`, onload: res=> { try { const data = JSON.parse(res.response); getKey(data.data.confirm_uri); }catch(error){ clearTimeout(timeout); showError('获取授权失败',error); console.error(error); } }, onerror: error=> { clearTimeout(timeout); showError('获取授权失败',error); console.error(error); } }); } } } function CreateItem (data){ const item = document.createElement('div'); item.className = 'spread-module'; item.innerHTML = `
${data.title}
${data.tname} ${formatNumber(data.duration,'time')}

${data.title}

${formatNumber(data.play)} ${formatNumber(data.danmaku)}

`; item.querySelector('.watch-later-trigger').onclick = WatchLater; if (data.dislike_reasons&&accessKey){ const dislikeList = item.querySelector('.dislike-list'); for (const reason of data.dislike_reasons){ const dislikeItem = document.createElement('div'); dislikeItem.dataset.reason_id = reason.reason_id; dislikeItem.innerText = reason.reason_name; dislikeItem.title = `标记因为【${reason.reason_name}】不喜欢`; dislikeItem.onclick = DisLike; dislikeList.appendChild(dislikeItem); } }else { item.querySelector('.dislike-botton').style = 'display:none'; } return item; } function DisLike (ev) { let target=ev.target,parent=target.parentNode; let cancel; let url = `${document.location.protocol}//app.bilibili.com/x/feed/dislike`; if (parent.className!='dislike-list'){ cancel = true; let deep = 1; while(parent.nodeName!='A'&&deep++<4){ target = parent; parent=target.parentNode; } if (parent.nodeName!='A'){ showError('请求撤销稍后再看失败:找不到父节点,查看调试终端获取更多信息'); console.log('请求撤销稍后再看找不到父节点',ev); return false; } url += `/cancel`; }else{ parent = parent.parentNode.parentNode.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 (accessKey) url += '&access_key='+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){ showError(`请求不喜欢错误 code ${par.code} msg ${par.message} 请检查问题重试或打开调试终端查看更多信息`); console.log('请求不喜欢发生错误',par,url); }else{ handleCover(); } } catch (e){ showError(`请求不喜欢发生错误,请检查问题重试或打开调试终端查看更多信息`); console.error(e,'请求不喜欢发生错误'); } } }); return false; } } function InitRanking(){ const rankingAll = recommend.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; let day = 3; const data = {1:{},2:{}}; const status = getLoadingDiv(); const UpdateItems = target =>{ target.removeChild(status); for (let i = 0;i<7;i++){ const itemData = data[type][day][i]; const item = document.createElement('li'); item.className = 'rank-item'; if (i<3) item.classList.add('highlight'); item.innerHTML = `${i+1}

${itemData.title}

综合评分:${formatNumber(itemData.pts)}

`; if (i==0){ item.className = 'rank-item show-detail first highlight'; const a = item.querySelector('a'); a.innerHTML = `
${itemData.title}

${itemData.title}

综合评分:${formatNumber(itemData.pts)}

`; a.lastChild.onclick = WatchLater; } target.appendChild(item); } }; const UpdateRanking = ()=>{ const target = type==1?warp.firstChild:warp.lastChild; while(target.firstChild) target.removeChild(target.firstChild); status.firstChild.innerText = '正在加载...'; target.appendChild(status); rankingAll.lastChild.href = `/ranking/${type==1?'all':'origin'}/0/0/${day}/`; if (!data[type][day]){ GM_xmlhttpRequest({ method: 'GET', url: `${document.location.protocol}//api.bilibili.com/x/web-interface/ranking?rid=0&day=${day}&type=${type}&arc_type=0`, onload: res=>{ try { const rep = JSON.parse(res.response); if (rep.code!=0){ status.firstChild.innerText = `请求排行榜失败 code ${rep.code} msg ${rep.message} 请检查问题重试或打开调试终端查看更多信息`; return console.log('请求app首页失败',rep); } data[type][day] = rep.data.list; UpdateItems(target); } catch (e){ status.firstChild.innerText = `请求排行榜发生错误 ${e} 请检查问题重试或打开调试终端查看更多信息`; console.error(e,'请求排行榜发生错误'); } } }); }else UpdateItems(target); }; const UpdateStatus = ev=>{ if (ev.target.className =='dropdown-item'){ dropDown.firstChild.innerText = ev.target.innerText; [].forEach.call(dropDown.lastChild.childNodes,c => {c.style.display=c.style.display=='none'?'unset':'none';}); day = ev.target.innerText=='三日'?3:7; }else{ [].forEach.call(tab.childNodes,c=>{ if (c==ev.target) c.removeEventListener('mouseover',UpdateStatus); else c.addEventListener('mouseover',UpdateStatus); c.classList.toggle('on'); }); type = ev.target.innerText=='全部'?1:2; warp.classList.toggle('show-origin'); } UpdateRanking(); }; [].forEach.call(dropDown.lastChild.childNodes,c => {c.onclick = UpdateStatus;}); tab.lastChild.addEventListener('mouseover',UpdateStatus); UpdateRanking(); } function WatchLater (ev){ const target = ev.target; const req = new XMLHttpRequest(); const action = target.classList.contains('added')?'del':'add'; req.open('POST','//api.bilibili.com/x/v2/history/toview/'+action); req.withCredentials = true; req.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8'); req.onload = res=>{ try{ var list = JSON.parse(res.target.response); if (list.code!=0){ showError(`请求稍后再看错误 code ${list.code} msg ${list.message} 请检查问题重试或打开调试终端查看更多信息`); console.log('请求稍后再看发生错误',list,target); return; } target.classList.toggle('added'); target.title = target.classList.contains('added')?'移除稍后再看':'稍后再看'; }catch(e){ showError(`请求稍后再看发生错误,请检查问题重试或打开调试终端查看更多信息`); console.error(e,'请求稍后再看发生错误'); } }; req.send(`aid=${target.dataset.aid}&csrf=${token}`); return false; } function formatNumber (input,format='number'){ if (format=='time'){ let second = input%60; let minute = Math.floor(input/60); let hour; if (minute>60){ hour = Math.floor(minute/60); minute = minute%60; } if (second<10) second='0'+second; if (minute<10) minute='0'+minute; return hour?`${hour}:${minute}:${second}`:`${minute}:${second}`; }else{ return input>9999?`${(input/10000).toFixed(1)}万`:input||0; } } function getLoadingDiv(){ const loading = document.createElement('div'); loading.className = 'load-state'; loading.innerHTML = '正在加载...'; return loading; } function showError(msg){ const toast = document.createElement('div'); toast.innerHTML = `
${msg}
`; document.body.appendChild(toast); setTimeout(()=>document.body.removeChild(toast),4000); return false; }