Narou Ranking NG

小説家になろう(厳密には小説を読もう)ランキングでのNGフィルタリング機能を提供

  1. // ==UserScript==
  2. // @name Narou Ranking NG
  3. // @namespace https://gf.qytechs.cn/ja/users/17828-amaicoffee
  4. // @version 1.7
  5. // @description 小説家になろう(厳密には小説を読もう)ランキングでのNGフィルタリング機能を提供
  6. // @author amaicoffee
  7. // @license MIT license
  8. // @match https://yomou.syosetu.com/rank/genrelist/type/*
  9. // @match https://yomou.syosetu.com/rank/list/type/*
  10. // @grant GM_addStyle
  11. // @grant GM_deleteValue
  12. // @grant GM_getValue
  13. // @grant GM_listValues
  14. // @grant GM_setValue
  15. // ==/UserScript==
  16.  
  17.  
  18. /*
  19. 更新履歴
  20. v1.7
  21. 予定している新機能追加に向け、機能そのままに手直し。
  22.  
  23. v1.6
  24. ノードの設定ミスで正しく非表示にできていない問題の修正
  25.  
  26. ver 1.5
  27. GM_addStyleを使って短く。
  28. 可読性向上(順序入れ替え、注釈など)
  29.  
  30. ver 1.4
  31. スクリプトの名前をNarou ranking ngからNarou Ranking NGに変更
  32.  
  33. ver 1.3
  34. メニュー作成を目指してとりあえずNGセーブデータのエクスポート機能を実装。
  35. NGセーブデータボタン横にエクスポートボタンを追加。
  36. なおこれは暫定的な配置です。良くない配置のUIなのでメニュー実装までのつなぎです。
  37. エクスポートボタンを押すとコンソールにNGセーブデータが表示されます。
  38. コンソールはF12を押すことで見られます。後は適宜保存するなどお願いします。
  39. */
  40.  
  41.  
  42. /*
  43. ユーザースクリプトの説明
  44. 注意!このスクリプトはJavaScript練習を兼ねたものです!
  45. 小説を読もう!の「ジャンル別ランキング」「総合ランキング」ページで動作するスクリプトで、
  46. ランキング内、小説タイトル横に追加する「表示/非表示」ボタンを押すと、その小説はNGに登録され説明文が折りたたまれます。
  47. NG登録はGM setValueで保存され、ページ遷移に耐えます。
  48. 登録したNGを消す方法は画面右下のフローティングボタン「delete ng data」を押して下さい。
  49. */
  50.  
  51.  
  52. console.log(GM_listValues())
  53.  
  54.  
  55. // セーブデータ・読込キー
  56. // 現行
  57. const NAROU_NG_IDS_KEY = 'narou_ng_ids';
  58. /*
  59. // 下記に更新予定
  60. const NG_NOVEL_KEY = 'nrng_novel_ids;
  61. const NG_AUTHOR_KEY = 'nrng_author_ids;
  62. const NG_TAG_KEY = 'nrng_tags;
  63. */
  64.  
  65.  
  66. // セーブデータ・ロード関数
  67. function load_savedata(key) {
  68. const DATA = GM_getValue(key);
  69. return DATA ? DATA.split(' ') : [];// 良くない書き方?
  70. }
  71.  
  72.  
  73. // セーブデータ・セーブ関数
  74. function save_savedata(key, array) {
  75. GM_setValue(key, array.join(' '));
  76. }
  77.  
  78.  
  79. function delete_savedata(key) {
  80. switch (key) {
  81. case NAROU_NG_IDS_KEY:
  82. if (window.confirm('NG小説IDを全削除しますか?')) {
  83. GM_deleteValue(key);
  84. window.alert('NG小説IDを全削除しました');
  85. }
  86. break;
  87.  
  88. default:
  89. break;
  90. }
  91.  
  92. }
  93.  
  94.  
  95. // ランキング内の小説をノードリストとして所得
  96. var ranking_list_nodelist = document.querySelectorAll('.ranking_list');
  97.  
  98.  
  99. // ランキング内小説ID配列とNG小説ID配列
  100. var ranked_id_arr = Array.from(document.querySelectorAll('.tl'), a => a.href.substring(26, 33));
  101. var ng_novel_ids_array = load_savedata(NAROU_NG_IDS_KEY)
  102.  
  103.  
  104. // スクリプトでNG小説を隠すのに使うCSS要素を作成して追加
  105. GM_addStyle('.censored { display: none; }')
  106.  
  107.  
  108. function toggle(num) {
  109. var target_classList = ranking_list_nodelist[num].childNodes[3].classList;
  110. var target_id = ranked_id_arr[num];
  111. if (target_classList.contains('censored')) {
  112. target_classList.remove('censored');
  113. ng_novel_ids_array = ng_novel_ids_array.filter(id => id != target_id);
  114. } else {
  115. target_classList.add('censored');
  116. ng_novel_ids_array.push(target_id);
  117. }
  118. console.log('NG小説ID一覧が更新されました。');
  119. console.log(ng_novel_ids_array);
  120. save_savedata(NAROU_NG_IDS_KEY, ng_novel_ids_array);
  121. }
  122.  
  123.  
  124. // NG登録ボタンを↑のリスト個数分つくって配列に追加
  125. var button_array = [];
  126. for (let i = 0; i < ranking_list_nodelist.length; i++) {
  127. button_array[i] = document.createElement('button');
  128. button_array[i].innerText = '非表示';
  129. button_array[i].addEventListener('click', function () { toggle(i); });// ループ内関数宣言は駄目らしい? 動いているが…
  130. ranking_list_nodelist[i].firstElementChild.appendChild(button_array[i]);
  131. }
  132.  
  133.  
  134. // メイン部分。ここどうにかならないものか
  135. // NG小説IDが見つかったとき
  136. if (ng_novel_ids_array.length > 0) {
  137. console.log('保存されたNG小説IDが見つかりました。');
  138. console.log(ng_novel_ids_array.join(' '));
  139. let key_array = ng_novel_ids_array.slice();
  140. for (let i = 0; i < ranked_id_arr.length; i++) {
  141. for (let j = 0; j < key_array.length; j++) {
  142.  
  143. let soeji = ranked_id_arr.indexOf(key_array[j]);
  144. if (soeji != -1) {
  145. ranking_list_nodelist[soeji].lastElementChild.classList.add('censored');
  146. key_array.splice(j, 1);
  147. }
  148. }
  149. }
  150. } else {
  151. console.log('保存されたNG小説IDは見つかりませんでした。');
  152. }
  153.  
  154.  
  155. // フロートNGメニュー
  156. GM_addStyle('.floated { position: fixed; right: 0; bottom: 0; }')
  157.  
  158. const FLOAT_NG_MENU = document.createElement('div');
  159. FLOAT_NG_MENU.classList.add('floated');
  160. document.body.appendChild(FLOAT_NG_MENU);
  161.  
  162.  
  163. const EXPORT_BUTTON = document.createElement('button');
  164. EXPORT_BUTTON.innerText = 'NGをエクスポート';
  165. EXPORT_BUTTON.addEventListener('click', function () {
  166. if (ng_novel_ids_array.length > 0) {
  167. console.log('下記がNG小説ID一覧です。')
  168. console.log(ng_novel_ids_array.join(' '));
  169. window.alert('NG小説ID一覧がエクスポートされました。')
  170. } else {
  171. window.alert('NG小説IDが見つかりません。')
  172. }
  173. });
  174. document.querySelector('.floated').appendChild(EXPORT_BUTTON);
  175.  
  176. function hogehoge() {
  177. window.alert('hogehoge')
  178. }
  179.  
  180.  
  181. const DELETE_SAVE_DATA_BUTTON = document.createElement('button');
  182. DELETE_SAVE_DATA_BUTTON.innerText = 'NG全削除';
  183. DELETE_SAVE_DATA_BUTTON.addEventListener('click', function () { delete_savedata(NAROU_NG_IDS_KEY); });
  184. document.querySelector('.floated').appendChild(DELETE_SAVE_DATA_BUTTON);

QingJ © 2025

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