bangumi 好友统计

显示好友的最近一条Timeline时间,显示总好友数、活跃好友数,3天内有更新Timeline的:Active,100天内有更新Timeline的:Alive,100天以上没更新Timeline的:M.I.T(Missing In Time);显示好友的注册(不可用)时间,08-10:Senior,11-13:Junior,14-16:Sophomore,17-:Freshman;显示好友与自己的共同爱好数量和同步率,根据一定的公式计算出高同步率的好友。

  1. // ==UserScript==
  2. // @name bangumi 好友统计
  3. // @namespace https://bgm.tv/user/liaune
  4. // @version 0.3
  5. // @description 显示好友的最近一条Timeline时间,显示总好友数、活跃好友数,3天内有更新Timeline的:Active,100天内有更新Timeline的:Alive,100天以上没更新Timeline的:M.I.T(Missing In Time);显示好友的注册(不可用)时间,08-10:Senior,11-13:Junior,14-16:Sophomore,17-:Freshman;显示好友与自己的共同爱好数量和同步率,根据一定的公式计算出高同步率的好友。
  6. // @author Liaune
  7. // @include /^https?://(bgm\.tv|chii\.in|bangumi\.tv)\/user\/.*\/(friends|rev_friends)
  8. // @grant GM_addStyle
  9. // ==/UserScript==
  10. (function() {
  11. GM_addStyle(`
  12. .dead{
  13. background-color: rgba(11, 12, 12, 0.8)!important;
  14. color:white;
  15. }
  16. .alive{
  17. background-color: rgba(234, 195, 53, 0.8)!important;
  18. color:red;
  19. }
  20. .active{
  21. background-color: rgba(26, 244, 43, 0.8)!important;
  22. color:white;
  23. }
  24. .senior{
  25. background-color: rgba(253, 62, 80, 0.8)!important;
  26. color:blue;
  27. }
  28. .junior{
  29. background-color: rgba(138, 149, 254, 0.8)!important;
  30. color:blue;
  31. }
  32. .sophomore{
  33. background-color: rgba(138, 254, 185, 0.8)!important;
  34. color:blue;
  35. }
  36. .freshman{
  37. background-color: rgba(255, 214, 218, 0.8)!important;
  38. color:blue;
  39. }
  40. `);
  41. let active_friends=0, alive_friends=0, dead_friends=0, similar_friends=0,count_simi=0,senior=0,junior=0,sophomore=0,freshman=0,sortstyle=1,update=0,count=0,args=0;
  42. const itemsList = document.querySelectorAll('#memberUserList li.user');
  43. document.querySelector('#friend_flag').innerHTML =itemsList.length+"个好友   ";
  44. //统计好友活跃状态
  45. const showBtn = document.createElement('a');
  46. showBtn.addEventListener('click', ShowTime.bind(), false);
  47. showBtn.className = 'chiiBtn';
  48. showBtn.href='javascript:;';
  49. showBtn.textContent = '活跃状态';
  50. document.querySelector('#friend_flag').append(showBtn);
  51. //统计好友注册(不可用)时间
  52. const showBtn1 = document.createElement('a');
  53. showBtn1.addEventListener('click', showsignup.bind(), false);
  54. showBtn1.className = 'chiiBtn';
  55. showBtn1.href='javascript:;';
  56. showBtn1.textContent = '注册(不可用)时间';
  57. document.querySelector('#friend_flag').append(showBtn1);
  58. //统计好友与自己的同步率
  59. const showBtn2 = document.createElement('a');
  60. showBtn2.addEventListener('click', showSimilar.bind(), false);
  61. showBtn2.className = 'chiiBtn';
  62. showBtn2.href='javascript:;';
  63. showBtn2.textContent = '与我的同步率';
  64. document.querySelector('#friend_flag').append(showBtn2);
  65. //排序
  66. const showBtn3 = document.createElement('a');
  67. showBtn3.addEventListener('click', mySort);
  68. showBtn3.className = 'chiiBtn';
  69. showBtn3.href='javascript:;';
  70. showBtn3.textContent = '排序';
  71. //更新缓存数据
  72. const showBtn4 = document.createElement('a');
  73. showBtn4.addEventListener('click', Update);
  74. showBtn4.className = 'chiiBtn';
  75. showBtn4.href='javascript:;';
  76. showBtn4.textContent = '更新';
  77.  
  78. function Update(){
  79. update=1;
  80. active_friends=0; alive_friends=0;dead_friends=0;similar_friends=0;count_simi=0;senior=0;junior=0;sophomore=0;freshman=0;
  81. if(args==1) ShowTime();
  82. else if(args==2) showsignup();
  83. else if(args==3) showSimilar();
  84.  
  85. }
  86.  
  87. function mySort() {
  88. sortstyle = (sortstyle==1)? -1 :1;
  89. showBtn3.textContent = (showBtn3.textContent=='倒序') ? '正序':'倒序';
  90. var container = document.querySelector('ul#memberUserList');
  91. if (container) container.style.cssText = 'display: flex; flex-flow: row wrap;';
  92.  
  93. function myParseDate (dateString) {
  94. if(dateString.match(/\d{4}/)){
  95. let date = new Date(dateString);
  96. let now = new Date();
  97. return now.getTime()-date.getTime();}
  98. else if(dateString.match(/%/)){
  99. let Percent = dateString.match(/(\d{1,2}\.\d{1,2})%/)[1];
  100. let Similar = dateString.match(/(\d+)/)[1];
  101. let Similarity = Percent / (170*Math.pow(Similar,-0.35));
  102. return parseInt(Similarity*100);}
  103. else{
  104. let d = dateString.match(/(\d{1,2})d/)?dateString.match(/(\d{1,2})d/)[1]:0;
  105. let h = dateString.match(/(\d{1,2})h/)?dateString.match(/(\d{1,2})h/)[1]:0;
  106. let m = dateString.match(/(\d{1,2})m/)?dateString.match(/(\d{1,2})m/)[1]:0;
  107. let time=d*24*60*60*1000+h*60*60*1000+m*60*1000;
  108. return time;
  109. }
  110. }
  111. [].slice.call(document.querySelectorAll('li.user span.rank:last-child small'), 0)
  112. .map(x => [x.textContent, x])
  113. .sort((x,y) => (myParseDate(x[0]) - myParseDate(y[0]))*sortstyle)
  114. .forEach((x,n) => x[1].parentNode.parentNode.parentNode.style.order = n);
  115. }
  116.  
  117. function showsignup(){
  118. showBtn1.style.display="none";
  119. showBtn3.style.display="none";
  120. args=2;
  121. if(!update) showBtn4.style.display="none";
  122. itemsList.forEach( (elem, index) => {
  123. let href = elem.querySelector('a.avatar').href;
  124. let ID = href.split('/user/')[1];
  125. if(localStorage.getItem('User'+ID+'Signtime') && !update)
  126. Displaysignup(localStorage.getItem('User'+ID+'Signtime'));
  127. else{
  128. fetch(href,{credentials: "include"})
  129. .then( data => data.text() )
  130. .then(targetStr => {
  131. let myMatch = targetStr.match(/Bangumi<\/span> <span class="tip">(\d{4}-\d{1,2}-\d{1,2}) 加入<\/span><\/li>/);
  132. let signtime = myMatch ? myMatch[1].toString() : null;
  133. if(signtime) localStorage.setItem('User'+ID+'Signtime',signtime);
  134. if(!update) Displaysignup(signtime);
  135. else{
  136. count+=1;
  137. showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')';
  138. if(count==itemsList.length){ location.reload(); showBtn4.textContent='更新完毕!';}
  139. }
  140.  
  141. });
  142. }
  143. function Displaysignup(signtime){
  144. let signuptime = document.createElement('span');
  145. signuptime.className = 'rank';
  146.  
  147. let year = signtime.match(/\d{4}/);
  148. if(year<=2010){signuptime.classList.add('senior');senior+=1;}
  149. else if(year<=2013){signuptime.classList.add('junior');junior+=1;}
  150. else if(year<=2016){signuptime.classList.add('sophomore');sophomore+=1;}
  151. else {signuptime.classList.add('freshman');freshman+=1;}
  152.  
  153. signuptime.innerHTML = `<p></p><small>${signtime}</small>`;
  154. document.querySelector('#friend_flag').childNodes[0].nodeValue =itemsList.length+"个好友 "+" Senior:"+senior+" Junior:"+junior+" Sophomore:"+sophomore+" Freshman:"+freshman+" ";
  155. document.querySelectorAll('#memberUserList li.user div.userContainer')[index].append(signuptime);
  156. if((senior+junior+sophomore+freshman)==itemsList.length){
  157. showBtn3.textContent = '排序';
  158. showBtn3.style.display="inline-block";
  159. document.querySelector('#friend_flag').append(showBtn3);
  160. showBtn4.style.display="inline-block";
  161. document.querySelector('#friend_flag').append(showBtn4);}
  162. }
  163.  
  164. });
  165.  
  166. }
  167.  
  168. function ShowTime(){
  169. showBtn.style.display="none";
  170. showBtn3.style.display="none";
  171. args=1;
  172. if(!update) showBtn4.style.display="none";
  173. itemsList.forEach( (elem, index) => {
  174. let href = elem.querySelector('a.avatar').href;
  175. let ID = href.split('/user/')[1];
  176. if(localStorage.getItem('User'+ID+'Lasttime') && !update)
  177. DisplayTime(localStorage.getItem('User'+ID+'Lasttime'));
  178. else{
  179. fetch(href,{credentials: "include"})
  180. .then( data => data.text() )
  181. .then(targetStr => {
  182. let myMatch = targetStr.match(/small class="time">(.+?)<\/small><\/li>/);
  183. let lasttime = myMatch ? myMatch[1] : null;
  184. if(lasttime) localStorage.setItem('User'+ID+'Lasttime',lasttime);
  185. if(!update) DisplayTime(lasttime);
  186.  
  187. else{
  188. count+=1;
  189. showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')';
  190. if(count==itemsList.length){ location.reload(); showBtn4.textContent='更新完毕!';}
  191. }
  192.  
  193. });
  194. }
  195. function DisplayTime(lasttime){
  196. let myMatch2 = lasttime.match(/\d{4}/);
  197. let activtime = document.createElement('span');
  198. activtime.className = 'rank';
  199. if (myMatch2) {
  200. let date = new Date(lasttime);
  201. let now = new Date();
  202. let durtime = parseInt((now.getTime() - date.getTime())/(24 * 60 * 60 * 1000));
  203. if(durtime>=100){ activtime.classList.add('dead'); dead_friends+=1;}
  204. else { activtime.classList.add('alive'); alive_friends+=1;}
  205. }
  206. else {
  207. activtime.classList.add('active');
  208. active_friends+=1;
  209. }
  210. if(!lasttime) {
  211. activtime.classList.add('dead');
  212. dead_friends+=1;
  213. }
  214. activtime.innerHTML = `<p></p><small>${lasttime}</small>`;
  215. document.querySelector('#friend_flag').childNodes[0].nodeValue =itemsList.length+"个好友 "+" Active:"+active_friends+" Alive:"+alive_friends+" M.I.T:"+dead_friends+" ";
  216. document.querySelectorAll('#memberUserList li.user div.userContainer')[index].append(activtime);
  217. if((dead_friends+alive_friends+active_friends)==itemsList.length){
  218. showBtn3.textContent = '排序';
  219. showBtn3.style.display="inline-block";
  220. document.querySelector('#friend_flag').append(showBtn3);
  221. showBtn4.style.display="inline-block";
  222. document.querySelector('#friend_flag').append(showBtn4);}
  223. }
  224. });
  225. }
  226.  
  227. function showSimilar(){
  228. showBtn2.style.display="none";
  229. showBtn3.style.display="none";
  230. args=3;
  231. if(!update) showBtn4.style.display="none";
  232. itemsList.forEach( (elem, index) => {
  233. let href = elem.querySelector('a.avatar').href;
  234. let ID = href.split('/user/')[1];
  235. if(localStorage.getItem('User'+ID+'Similarity') && !update)
  236. DisplaySimilar(localStorage.getItem('User'+ID+'Similarity'),localStorage.getItem('User'+ID+'Similarity_percent'));
  237. else{
  238. fetch(href,{credentials: "include"})
  239. .then(data => {
  240. return new Promise(function (resovle, reject) {
  241. let targetStr = data.text();
  242. resovle(targetStr);
  243. });
  244. })
  245. .then(targetStr => {
  246. let Similar = targetStr.match(/<small class="hot">\/ (\d{1,3})个共同喜好<\/small>/);
  247. let Similarity = Similar ? Similar[1]: null;
  248. if(Similarity) localStorage.setItem('User'+ID+'Similarity',Similarity);
  249. let Similar_percent = targetStr.match(/<span class="percent_text rr">((-?\d+)(\.\d+)?)%<\/span>/);
  250. let Similarity_percent = Similar_percent ? Similar_percent[1] : null;
  251. if(Similarity_percent) localStorage.setItem('User'+ID+'Similarity_percent',Similarity_percent);
  252. if(!update) DisplaySimilar(Similarity,Similarity_percent);
  253. else{
  254. count+=1;
  255. showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')';
  256. if(count==itemsList.length){ location.reload(); showBtn4.textContent='更新完毕!';}
  257. }
  258.  
  259. });}
  260. function DisplaySimilar(Similarity,Similarity_percent){
  261. let show_similar = document.createElement('span');
  262. show_similar.className = 'rank';
  263. if(Similarity>=20 && Similarity_percent >= 170*Math.pow(Similarity,-0.35)) {
  264. show_similar.style.color='blue';
  265. show_similar.style.fontWeight='bold';
  266. similar_friends+=1;
  267. }
  268. let show_similarity = ''+Similarity+' / '+Similarity_percent+'%';
  269. show_similar.innerHTML = `<p></p><small>${show_similarity}</small>`;
  270. document.querySelector('#friend_flag').childNodes[0].nodeValue =itemsList.length+"个好友 "+" 和我同步率高的好友:"+similar_friends;
  271. document.querySelectorAll('#memberUserList li.user div.userContainer')[index].append(show_similar);
  272. count_simi+=1;
  273. if(count_simi==itemsList.length){
  274. showBtn3.textContent = '排序';
  275. showBtn3.style.display="inline-block";
  276. document.querySelector('#friend_flag').append(showBtn3);
  277. showBtn4.style.display="inline-block";
  278. document.querySelector('#friend_flag').append(showBtn4);}
  279. }
  280. });
  281. }
  282. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址