在有条目列表的页面,显示条目的排名,站内评分和评分人数,好友评分和评分人数,并提供排序功能,鼠标移到排名处可查看历史记录
// ==UserScript== // @name bangumi列表显示增强 // @namespace https://github.com/bangumi/scripts/liaune // @version 0.6.6 // @description 在有条目列表的页面,显示条目的排名,站内评分和评分人数,好友评分和评分人数,并提供排序功能,鼠标移到排名处可查看历史记录 // @author Yonjar,Liaune // @include /^https?://(bangumi\.tv|bgm\.tv|chii\.in)/(.+?/list|.+?/tag|.+?/browser|subject_search|index)(/|\?).+$/ // @grant GM_addStyle // ==/UserScript== (function() { GM_addStyle(` .yonjar_bgm_userjs_rank_excellent{ background-color: #0033CC!important; } .yonjar_bgm_userjs_rank_recommended{ background-color: #3ed715!important; } .yonjar_bgm_userjs_rank_justsoso{ background-color: #FF6600!important; } .yonjar_bgm_userjs_rank_refuse{ background-color: #f2050587!important; } .yonjar_bgm_userjs_rank_undefined{ background-color: #0000001a!important; } .friend_vote{ font-size: 10px; color:#4260cb; } .yonjar_bgm_userjs_vote_0{ background-color: rgba(11, 12, 12, 0)!important; color:black; } .yonjar_bgm_userjs_vote_500{ background-color: rgba(128, 255, 255, 0)!important; color:#eca609; } .yonjar_bgm_userjs_vote_1000{ background-color: rgba(128, 144, 255, 0)!important; color:#18a099; } .yonjar_bgm_userjs_vote_2000{ background-color: rgba(209, 80, 205, 0)!important; color:blue; } .yonjar_bgm_userjs_vote_4000{ background-color: rgba(253, 62, 80, 0)!important; color:red; } .yonjar_bgm_userjs_rank_btn{ display: inline-block; color: #666; text-shadow: 0px 1px 2px #FFF; text-decoration: none; line-height: 20px; margin: 0 5px 5px 0; padding: 0 12px; border: 1px solid #DDD; background: -webkit-gradient(linear,left top,left bottom,from(#FCFCFC),to(#F1F1F1)); background: -moz-linear-gradient(top,#FCFCFC,#F1F1F1); background: -o-linear-gradient(top,#FCFCFC,#F1F1F1); -webkit-box-shadow: 0 1px 2px #EEE,inset 0 1px 1px #FFF; -moz-box-shadow: 0 1px 2px #EEE,inset 0 1px 1px #FFF; box-shadow: 0 1px 2px #EEE,inset 0 1px 1px #FFF; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px } .yonjar_bgm_userjs_rank_btn:hover { color: #FFF; text-shadow: none; background: #4F93CF; background: -moz-linear-gradient(top,#6BA6D8,#4F93CF); background: -o-linear-gradient(top,#6BA6D8,#4F93CF); background: -webkit-gradient(linear,left top,left bottom,from(#5FA3DB),to(#72B6E3)); -webkit-box-shadow: 0 0 3px #EEE,inset 0 -1px 5px rgba(0,0,0,0.1); -moz-box-shadow: 0 0 3px #EEE,inset 0 -1px 5px rgba(0,0,0,0.1); box-shadow: 0 0 3px #EEE,inset 0 -1px 5px rgba(0,0,0,0.1) } `); let itemsList = document.querySelectorAll('#browserItemList li.item'); let sortstyle = -1, sortstyle1 = 1,sortstyle2 = 1,sortstyle3 = -1,count=0,update=0; //按排名排序 const showBtn = document.createElement('a'); showBtn.addEventListener('click', SortByRank); showBtn.className = 'chiiBtn'; showBtn.href='javascript:;'; showBtn.textContent = '排名排序'; //按评分人数排序 const showBtn1 = document.createElement('a'); showBtn1.addEventListener('click', SortByVote); showBtn1.className = 'chiiBtn'; showBtn1.href='javascript:;'; showBtn1.textContent = '人数排序'; //按好友评价排序 const showBtn2 = document.createElement('a'); showBtn2.addEventListener('click', SortByFriend); showBtn2.className = 'chiiBtn'; showBtn2.href='javascript:;'; showBtn2.textContent = '好友评价'; //按时间排序 const showBtn3 = document.createElement('a'); showBtn3.addEventListener('click', SortByTime); showBtn3.className = 'chiiBtn'; showBtn3.href='javascript:;'; showBtn3.textContent = '时间排序'; if(document.querySelector('#indexCatBox ul.cat')) document.querySelector('#indexCatBox ul.cat').append(showBtn3); //更新缓存数据 const showBtn4 = document.createElement('a'); showBtn4.addEventListener('click', Update); showBtn4.className = 'chiiBtn'; showBtn4.href='javascript:;'; showBtn4.textContent = '更新'; //更新缓存数据 const showBtn0 = document.createElement('a'); showBtn0.addEventListener('click', ShowProcess); showBtn0.className = 'chiiBtn'; showBtn0.href='javascript:;'; showBtn0.textContent = 'Show'; const You=document.querySelectorAll('#headerNeue2 .idBadgerNeue a.avatar')[0].href.split('/user/')[1]; const User =window.location.href.match(/\/list\/(\S+)\//)? window.location.href.match(/\/list\/(\S+)\//)[1]: null; if(window.location.href.match(/\/index\//)) Process(); else {document.querySelector('#browserTools').append(showBtn0);} function ShowProcess(){ itemsList = document.querySelectorAll('#browserItemList li.item'); showBtn0.style.display='none'; Process(); } //Main Program function Process(){ itemsList.forEach( (elem, index) => { let href = elem.querySelector('a.subjectCover').href; let ID = href.split('/subject/')[1]; //为每个条目添加单独刷新 let showBtn5 = document.createElement('a'); showBtn5.className = 'l'; showBtn5.href='javascript:;'; showBtn5.textContent = '↺'; showBtn5.addEventListener('click', FetchStatus.bind(this,href,index),false); elem.querySelector('.inner h3').appendChild(showBtn5); //获取用户评分 let User_rate=User ? elem.querySelectorAll('.inner .collectInfo span')[0].className: null; let User_Point=User_rate ? (User_rate.match(/sstars(\d+)/)?User_rate.match(/sstars(\d+)/)[1]:null):null; if(User==You && User_Point) localStorage.setItem(You+'Point'+ID,User_Point); if(localStorage.getItem(ID+'Point')){ let info = {"rankNum": localStorage.getItem(ID+'Rank'),"Point": localStorage.getItem(ID+'Point'),"votes": localStorage.getItem(ID+'Votes'),"Point_f": localStorage.getItem(ID+'Point_f'),"Votes_f": localStorage.getItem(ID+'Votes_f')}; DisplayStatus(ID,index,info); } else FetchStatus(href,index); }); } function Update(){ update=1; count=0; itemsList.forEach( (elem, index) => { let href = elem.querySelector('a.subjectCover').href; let ID = href.split('/subject/')[1]; //同一天只更新一次 let date = new Date(); let time = date.getFullYear()+"-" + (date.getMonth()+1) + "-" + date.getDate(); let lastime = localStorage.getItem(ID+'Lastime'); if(time != lastime) FetchStatus(href,index); else { count+=1; showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')'; if(count==itemsList.length){ location.reload(); showBtn4.textContent='更新完毕!';}} }); } function FetchStatus(href,index){ fetch(href,{credentials: "include"}) .then(data => { return new Promise(function (resovle, reject) { let targetStr = data.text(); resovle(targetStr); }); }) .then(targetStr => { let ID = href.split('/subject/')[1]; //获取排名 let canMatch = targetStr.match(/<small class="alarm">#(\S+?)<\/small>/); let rankNum = canMatch ? parseInt(canMatch[1], 10) : null; if(canMatch) localStorage.setItem(ID+'Rank',rankNum); //获取站内评分和评分人数 let Match1 = targetStr.match(/<span class="number" property="v:average">(\S+?)<\/span>/); let Point = Match1? parseFloat(Match1[1]) : null; if(Match1) localStorage.setItem(ID+'Point',Point); let Match2 = targetStr.match(/<span property="v:votes">(\S+?)<\/span>/); let votes = Match2? parseInt(Match2[1]) : null; if(Match2) localStorage.setItem(ID+'Votes',votes); //获取好友评分和评分人数 let Match3 = targetStr.match(/<span class="num">(\S+?)<\/span>/); let Point_f = Match3? parseFloat(Match3[1]).toFixed(1) : null; if(Match3) localStorage.setItem(ID+'Point_f',Point_f); let Match4 = targetStr.match(/class="l">(\S+?) 人评分<\/a>/); let Votes_f = Match4? parseFloat(Match4[1]) : null; if(Match4) localStorage.setItem(ID+'Votes_f',Votes_f); //加入历史记录 let date = new Date(); let time = date.getFullYear()+"-" + (date.getMonth()+1) + "-" + date.getDate(); let lastime = localStorage.getItem(ID+'Lastime'); let Record = time + ' Rank #' + rankNum + ' 评分:'+ Point + ' '+ votes + ' 人评分'+ '\r\n'; let History = localStorage.getItem(ID+'Records'); if(History) Record = History + Record; if(Match1 && time!=lastime){ localStorage.setItem(ID+'Lastime',time); localStorage.setItem(ID+'Records',Record);} let info = {"rankNum": rankNum,"Point": Point,"votes": votes,"Point_f": Point_f,"Votes_f": Votes_f}; if(!update) DisplayStatus(ID,index,info); else{ count+=1; showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')'; if(count==itemsList.length){ location.reload(); showBtn4.textContent='更新完毕!';} } }); } function DisplayStatus(ID,index,info){ let rankNum=info.rankNum,Point=info.Point,votes=info.votes,Point_f=info.Point_f,Votes_f=info.Votes_f; //显示排名 let rankSp = document.createElement('span'); rankSp.className = 'rank'; if (rankNum >= 3000) { rankSp.classList.add('yonjar_bgm_userjs_rank_refuse'); } else if (rankNum >= 2000) { rankSp.classList.add('yonjar_bgm_userjs_rank_justsoso'); } else if (rankNum >= 1000) { } else if (rankNum >= 100) { rankSp.classList.add('yonjar_bgm_userjs_rank_recommended'); } else if ( rankNum >0) { rankSp.classList.add('yonjar_bgm_userjs_rank_excellent'); } else { rankSp.classList.add('yonjar_bgm_userjs_rank_undefined'); } rankSp.innerHTML = `<small>Rank </small>${rankNum}`; let note = localStorage.getItem(ID+'Records'); rankSp.setAttribute('title', note); if(window.location.href.match(/\/(list|index)\//)) document.querySelectorAll('#browserItemList .item .inner')[index].insertBefore(rankSp, document.querySelectorAll('#browserItemList .item .inner .info.tip')[index]); //显示站内评分和评分人数 let rateInfo = document.createElement('p'); rateInfo.setAttribute("class","rateInfo"); let PointSm = document.createElement('small'); PointSm.innerHTML = Point; PointSm.setAttribute("class","fade"); let sstars = document.createElement('span'); let Point1 = Point ? parseInt(Point) : null; if(Point1) sstars.setAttribute("class","sstars"+ Point1+ " starsinfo"); let tip_j = document.createElement('span'); tip_j.setAttribute("class","tip_j"); tip_j.innerHTML = "("+ votes +"人评分)"; if(votes>=4000) tip_j.classList.add('yonjar_bgm_userjs_vote_4000'); else if(votes>=2000) tip_j.classList.add('yonjar_bgm_userjs_vote_2000'); else if(votes>=1000) tip_j.classList.add('yonjar_bgm_userjs_vote_1000'); else if(votes>=500) tip_j.classList.add('yonjar_bgm_userjs_vote_500'); if(votes<500) tip_j.classList.add('yonjar_bgm_userjs_vote_0'); if(window.location.href.match(/\/(list|index)\//)){ document.querySelectorAll('#browserItemList .item .inner')[index].insertBefore(rateInfo, document.querySelectorAll('#browserItemList .item .inner .info.tip')[index]); rateInfo.appendChild(sstars); rateInfo.appendChild(PointSm); rateInfo.appendChild(tip_j);} else rateInfo = document.querySelectorAll('#browserItemList .item .inner .rateInfo')[index]; //显示好友评分和评分人数 let Pointfr = document.createElement('small'); Point_f = Point_f ? Point_f : '-'; Votes_f = Votes_f ? Votes_f :'-'; let Point_My = localStorage.getItem(You+'Point'+ID); let Point_M = Point_My ? "我的评分:"+Point_My :''; Pointfr.innerHTML = "好友评分:"+Point_f+" "+Votes_f+"人评分"+" "+Point_M; Pointfr.setAttribute("class","friend_vote"); rateInfo.appendChild(Pointfr); //显示排序按钮 count+=1; if(count==itemsList.length && document.querySelector('#indexCatBox ul.cat')){ document.querySelector('#indexCatBox ul.cat').append(showBtn); document.querySelector('#indexCatBox ul.cat').append(showBtn1); document.querySelector('#indexCatBox ul.cat').append(showBtn2); document.querySelector('#indexCatBox ul.cat').append(showBtn4); $('.chiiBtn').css({padding:'0 5px'}); $('ul.cat li').css({padding:'0 5px 0 0'}); } else if(count==itemsList.length && document.querySelector('#browserTools')){ document.querySelector('#browserTools').append(showBtn); document.querySelector('#browserTools').append(showBtn1); document.querySelector('#browserTools').append(showBtn2); document.querySelector('#browserTools').append(showBtn4); } } function SortByRank() { sortstyle = (sortstyle==1)? -1 :1; showBtn.textContent = (showBtn.textContent=='排名排序↑') ? '排名排序↓':'排名排序↑'; let container = document.querySelector('ul#browserItemList'); function ParseRank(rankstring){ let rank = rankstring.match(/Rank (\d{1,4})/)? rankstring.match(/Rank (\d{1,4})/)[1]: 9999; return rank; } if (container) container.style.cssText = 'display: flex; flex-flow: row wrap;'; [].slice.call(document.querySelectorAll('#browserItemList .item .inner .rank'), 0) .map(x => [x.textContent, x]) .sort((x,y) => (ParseRank(x[0]) - ParseRank(y[0]))*sortstyle) .forEach((x,n) => {x[1].parentNode.parentNode.style.order = n; x[1].parentNode.parentNode.style.width = '100%';}); } function SortByVote() { sortstyle1 = (sortstyle1==-1)? 1 :-1; showBtn1.textContent = (showBtn1.textContent=='人数排序↓') ? '人数排序↑':'人数排序↓'; let container = document.querySelector('ul#browserItemList'); function ParseVote(votestring){ let vote = votestring.match(/(\d{1,5})人评分/)? votestring.match(/(\d{1,5})人评分/)[1]: 0; return vote; } if (container) container.style.cssText = 'display: flex; flex-flow: row wrap;'; [].slice.call(document.querySelectorAll('#browserItemList .item .inner .rateInfo .tip_j'), 0) .map(x => [x.textContent, x]) .sort((x,y) => (ParseVote(x[0]) - ParseVote(y[0]))*sortstyle1) .forEach((x,n) => {x[1].parentNode.parentNode.parentNode.style.order = n; x[1].parentNode.parentNode.parentNode.style.width = '100%';}); } function SortByFriend() { sortstyle2 = (sortstyle2==-1)? 1 :-1; showBtn2.textContent = (showBtn2.textContent=='好友评价↓') ? '好友评价↑':'好友评价↓'; let container = document.querySelector('ul#browserItemList'); function ParseFriendRank(rankstring){ let rank = rankstring.match(/(\d+\.\d+?)/)? rankstring.match(/(\d+\.\d+?)/)[1]: 0; let votes = rankstring.match(/(\d+?)人/)? rankstring.match(/(\d+?)人/)[1]: 0; rank = parseFloat(rank); votes = parseInt(votes); let fixed = rank ? (votes / (votes+10))* rank + (10 / (votes+10)) * 6: 0; return parseInt(fixed*10); } if (container) container.style.cssText = 'display: flex; flex-flow: row wrap;'; [].slice.call(document.querySelectorAll('#browserItemList .item .inner .rateInfo .friend_vote'), 0) .map(x => [x.textContent, x]) .sort((x,y) => (ParseFriendRank(x[0]) - ParseFriendRank(y[0]))*sortstyle2) .forEach((x,n) => {x[1].parentNode.parentNode.parentNode.style.order = n; x[1].parentNode.parentNode.parentNode.style.width = '100%';}); } function SortByTime() { sortstyle3 = (sortstyle3==-1)? 1 :-1; showBtn3.textContent = (showBtn3.textContent=='时间排序↓') ? '时间排序↑':'时间排序↓'; let container = document.querySelector('ul#browserItemList'); function ParseDate(Datestring){ let yy=Datestring.match(/(\d{4})/)? Datestring.match(/(\d{4})/)[1].toString():'1000'; let year = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[1].toString(): yy; let month = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[3].toString(): '01'; let day = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)?Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[5].toString(): '01'; let date= new Date(year+'/'+month+'/'+day); let now = new Date(); return now.getTime()-date.getTime(); } if (container) container.style.cssText = 'display: flex; flex-flow: row wrap;'; [].slice.call(document.querySelectorAll('#browserItemList .item .inner .info'), 0) .map(x => [x.textContent, x]) .sort((x,y) => (ParseDate(x[0]) - ParseDate(y[0]))*sortstyle3) .forEach((x,n) => {x[1].parentNode.parentNode.style.order = n; x[1].parentNode.parentNode.style.width = '100%';}); } })();