小説家になろう(厳密には小説を読もう)ランキングでのNGフィルタリング機能を提供
Ekde
// ==UserScript==
// @name Narou Ranking NG
// @namespace https://greasyfork.org/ja/users/17828-amaicoffee
// @version 1.6
// @description 小説家になろう(厳密には小説を読もう)ランキングでのNGフィルタリング機能を提供
// @author amaicoffee
// @license MIT license
// @match https://yomou.syosetu.com/rank/genrelist/type/*
// @match https://yomou.syosetu.com/rank/list/type/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
/*
更新履歴
v1.6
ノードの設定ミスで正しく非表示にできていない問題の修正
ver 1.5
GM_addStyleを使って短く。
可読性向上(順序入れ替え、注釈など)
ver 1.4
スクリプトの名前をNarou ranking ngからNarou Ranking NGに変更
ver 1.3
メニュー作成を目指してとりあえずNGセーブデータのエクスポート機能を実装。
NGセーブデータボタン横にエクスポートボタンを追加。
なおこれは暫定的な配置です。良くない配置のUIなのでメニュー実装までのつなぎです。
エクスポートボタンを押すとコンソールにNGセーブデータが表示されます。
コンソールはF12を押すことで見られます。後は適宜保存するなどお願いします。
*/
/*
ユーザースクリプトの説明
注意!このスクリプトはJavaScript練習を兼ねたものです!
小説を読もう!の「ジャンル別ランキング」「総合ランキング」ページで動作するスクリプトで、
ランキング内、小説タイトル横に追加する「表示/非表示」ボタンを押すと、その小説はNGに登録され説明文が折りたたまれます。
NG登録はGM setValueで保存され、ページ遷移に耐えます。
登録したNGを消す方法は画面右下のフローティングボタン「delete ng data」を押して下さい。
*/
// セーブデータ・読込キー
const NAROU_NG_IDS_KEY = 'narou_ng_ids';
// セーブデータ・ロード関数
function load_ng_ids() {
const DATA = GM_getValue(NAROU_NG_IDS_KEY);
return DATA ? DATA.split(' ') : [];// 良くない書き方?
}
// セーブデータ・セーブ関数
function save_ng_ids(array) {
GM_setValue(NAROU_NG_IDS_KEY, array.join(' '));
}
// ランキング内の小説をノードリストとして所得
var ranking_list_list = document.querySelectorAll('.ranking_list');
// ランキング内小説ID配列とNG小説ID配列
var ranked_id_arr = Array.from(document.querySelectorAll('.tl'), a => a.href.substring(26, 33));
var ng_id_arr = load_ng_ids();
// スクリプトでNG小説を隠すのに使うCSS要素を作成して追加
GM_addStyle(".censored { display: none; }");
function toggle(num) {
var target_classList = ranking_list_list[num].childNodes[3].classList;
var target_id = ranked_id_arr[num];
if (target_classList.contains('censored')) {
target_classList.remove('censored');
ng_id_arr = ng_id_arr.filter(id => id != target_id);
} else {
target_classList.add('censored');
ng_id_arr.push(target_id);
}
console.log('NG小説ID一覧が更新されました。');
console.log(ng_id_arr);
save_ng_ids(ng_id_arr);
}
// NG登録ボタンを↑のリスト個数分つくって配列に追加
var button_array = [];
for (let i = 0; i < ranking_list_list.length; i++) {
button_array[i] = document.createElement('button');
button_array[i].innerText = '非表示';
button_array[i].classList.add('ngbtn');// 苦肉の策
button_array[i].addEventListener('click', function () { toggle(i); });// ループ内関数宣言は駄目らしい? 動いているが…
ranking_list_list[i].firstElementChild.appendChild(button_array[i]);
}
// メイン部分。ここどうにかならないものか
if (ng_id_arr.length > 0) {
console.log('保存されたNG小説IDが見つかりました。');
console.log(ng_id_arr.join(' '));
let key_array = ng_id_arr.slice();
for (let i = 0; i < ranked_id_arr.length; i++) {
for (let j = 0; j < key_array.length; j++) {
let soeji = ranked_id_arr.indexOf(key_array[j]);
if (soeji != -1) {
ranking_list_list[soeji].lastElementChild.classList.add('censored');
key_array.splice(j, 1);
}
}
}
} else {
console.log('保存されたNG小説IDは見つかりませんでした。');
}
// フロートNGメニュー
GM_addStyle(".floated { position: fixed; right: 0; bottom: 0; }");
const FLOAT_NG_MENU = document.createElement('div');
FLOAT_NG_MENU.classList.add('floated');
document.body.appendChild(FLOAT_NG_MENU);
const EXPORT_BUTTON = document.createElement('button');
EXPORT_BUTTON.innerText = 'NGをエクスポート';
EXPORT_BUTTON.addEventListener('click', function () {
console.log('下記がNG小説ID一覧です。')
console.log(ng_id_arr.join(' '));
window.alert('NG小説ID一覧がエクスポートされました。')
});
document.querySelector('.floated').appendChild(EXPORT_BUTTON);
const DELETE_SAVE_DATA_BUTTON = document.createElement('button');
DELETE_SAVE_DATA_BUTTON.innerText = 'NG全削除';
DELETE_SAVE_DATA_BUTTON.addEventListener('click', delete_save_data);
document.querySelector('.floated').appendChild(DELETE_SAVE_DATA_BUTTON);
function delete_save_data() {
const blank_data = '';
GM_setValue(NAROU_NG_IDS_KEY, blank_data);
window.alert('NG小説IDが全削除されました。ページを更新してください。');
}