Last active
December 17, 2023 03:24
-
-
Save whiteball/5a936e89a40b07b625be27e534b8874c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name AIのべりすと 作品リストに絞り込みのためのタグリストを追加 | |
// @namespace https://ai-novelist-share.geo.jp/ | |
// @version 0.1.2 | |
// @description 作品タイトルに含まれる"[...]"の部分をタグと見なして、作品リストページにタグ一覧を追加します。タグ名をクリックすると、そのタグを検索欄にセットして作品を絞り込み表示します。 | |
// @author しらたま | |
// @match https://ai-novel.com/works.php | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=ai-novel.com | |
// @updateURL https://gist.github.com/whiteball/5a936e89a40b07b625be27e534b8874c/raw/ai_novelist_tag_list_for_works.user.js | |
// @downloadURL https://gist.github.com/whiteball/5a936e89a40b07b625be27e534b8874c/raw/ai_novelist_tag_list_for_works.user.js | |
// @supportURL https://gist.github.com/whiteball/5a936e89a40b07b625be27e534b8874c | |
// @grant none | |
// ==/UserScript== | |
/* | |
更新履歴 | |
2023/12/17 0.1.2 | |
リモート表示の時にグリッドリスト以外だとタグ一覧が表示されない不具合を修正。 | |
表示を切り替えたときにソート順が逆転する不具合を修正。 | |
表示を切り替えてもソート順が辞書昇順に戻らないように変更。 | |
2023/12/01 0.1.1 | |
タグメイトタグ名の間をクリックした時にnullと表示されるのを修正。 | |
検索クリアボタンを追加。 | |
*/ | |
(function() { | |
'use strict'; | |
const works_find = document.getElementById('works_find') | |
if (!works_find) { | |
console.log('a') | |
return | |
} | |
document.head.insertAdjacentHTML('beforeend',`<style> | |
#mod-title-tag-list { | |
margin-top: 10px; | |
margin-left: auto; | |
margin-right: auto; | |
width: 80vw; | |
font-size: 80%; | |
} | |
#mod-title-tag-list p { | |
font-size: 95%; | |
padding: 0 10px; | |
margin-top: 0.25rem; | |
margin-bottom: 0; | |
} | |
#mod-title-tag-list p.reset { | |
font-size: 95%; | |
padding: 0 20px; | |
margin-top: 0.25rem; | |
margin-bottom: 0.5rem; | |
} | |
#mod-title-tag-list ul { | |
list-style: none; | |
padding: 0 20px; | |
margin-top: 0.25rem; | |
margin-bottom: 0; | |
} | |
#mod-title-tag-list li { | |
display: inline; | |
padding-right: 10px; | |
} | |
</style>`) | |
works_find.insertAdjacentHTML('beforebegin', `<div id="mod-title-tag-list"> | |
<details><summary>タグリスト開閉</summary> | |
<p><a href="javascript:;" id="mod-tag-list-sort-dic">辞書順</a> / <a href="javascript:;" id="mod-tag-list-sort-count">件数順</a></p> | |
<ul id="mod-title-tag-list-inner"></ul> | |
<p class="reset"><a href="javascript:;" id="mod-tag-list-search-reset">検索クリア</a></p> | |
</details> | |
</div>`) | |
const maxId = Number(localStorage.max_works_id) | |
const reg = new RegExp(/\[([^\]]+)\]/g) | |
const tags = new Map() | |
// 一覧の作成 | |
const buildList = function (type) { | |
tags.clear() | |
// tags.set('タグ無し', 0) | |
if (type === 'remote') { | |
let titleList = [...document.querySelectorAll('#works_remote .works_title')].map(e => e.innerText) | |
if (titleList.length === 0) { | |
titleList = [...document.querySelectorAll('#works_remote input.btn-square')].map(e => e.value) | |
} | |
for (const title of titleList) { | |
if (title) { | |
const matches = [...title.matchAll(reg)] | |
if (matches.length !== 0) { | |
for (const tag of matches) { | |
if (tags.has(tag[1])) { | |
tags.set(tag[1], tags.get(tag[1]) + 1) | |
} else { | |
tags.set(tag[1], 1) | |
} | |
} | |
} else { | |
// tags.set('タグ無し', tags.get('タグ無し') + 1) | |
} | |
} | |
} | |
} else { | |
for (let id = 0; id <= maxId; id++) { | |
const key = `works${id}` | |
const item = localStorage.getItem(key) | |
if (item !== null) { | |
const itemList = item.split('<|endofsection|>') | |
const title = itemList[6] | |
const matches = [...title.matchAll(reg)] | |
if (matches.length !== 0) { | |
for (const tag of matches) { | |
if (tags.has(tag[1])) { | |
tags.set(tag[1], tags.get(tag[1]) + 1) | |
} else { | |
tags.set(tag[1], 1) | |
} | |
} | |
} else { | |
// tags.set('タグ無し', tags.get('タグ無し') + 1) | |
} | |
} | |
} | |
} | |
let buffer = '' | |
for (const item of tags) { | |
buffer += `<li data-key="${item[0]}" data-count="${item[1]}"><a href="javascript:;">${item[0]}(${item[1]})</a></li>` | |
} | |
const ul = document.getElementById('mod-title-tag-list-inner') | |
if (ul) { | |
ul.innerHTML = buffer | |
for (const element of document.querySelectorAll('#mod-title-tag-list ul li a')) { | |
element.addEventListener('click', function (event) { | |
const works_find_text = document.getElementById('works_find_text') | |
if (works_find_text) { | |
works_find_text.value = '[' + event.target.parentElement.getAttribute('data-key') + ']' | |
works_find_text.dispatchEvent(new Event('input')) | |
} | |
}) | |
} | |
} | |
} | |
// ソート処理 | |
const sortEvent = function (key, asNum = false, reverse = false) { | |
const list = [...document.querySelectorAll('#mod-title-tag-list ul li')] | |
if (list.length === 0) { | |
return | |
} | |
const ul = list[0].parentElement | |
if (key === '') { | |
key = ul.getAttribute('data-sort') | |
if (!key) { | |
key = 'data-key' | |
} | |
const order = ul.getAttribute('data-order') | |
if (order === 'desc') { | |
reverse = true | |
} else { | |
reverse = false | |
} | |
} else if (ul.getAttribute('data-sort') && ul.getAttribute('data-order') === (reverse ? 'desc' : 'asc')) { | |
reverse = ! reverse | |
} | |
const mapped = list.map((v, i) => { | |
return { i, value: asNum ? Number(v.getAttribute(key)) : v.getAttribute(key) } | |
}) | |
mapped.sort((a, b) => { | |
if (a.value > b.value) { | |
return reverse ? -1 : 1; | |
} | |
if (a.value < b.value) { | |
return reverse ? 1 : -1; | |
} | |
return 0; | |
}); | |
const result = mapped.map((v) => list[v.i]); | |
for (const e of result) { | |
ul.append(e) | |
} | |
ul.setAttribute('data-sort', key) | |
ul.setAttribute('data-order', reverse ? 'desc' : 'asc') | |
} | |
const linkDic = document.getElementById('mod-tag-list-sort-dic') | |
if (linkDic) { | |
linkDic.addEventListener('click', function () { | |
sortEvent('data-key') | |
}) | |
} | |
const linkCount = document.getElementById('mod-tag-list-sort-count') | |
if (linkCount) { | |
linkCount.addEventListener('click', function () { | |
sortEvent('data-count', true, true) | |
}) | |
} | |
const linkReset = document.getElementById('mod-tag-list-search-reset') | |
if (linkReset) { | |
linkReset.addEventListener('click', function () { | |
const works_find_text = document.getElementById('works_find_text') | |
if (works_find_text) { | |
works_find_text.value = '' | |
works_find_text.dispatchEvent(new Event('input')) | |
} | |
}) | |
} | |
// ローカルリモート切り替えにフック | |
const refreshlist_remote_orig = window.refreshlist_remote | |
window.refreshlist_remote = function (iterpos = 0, force_refresh = false) { | |
refreshlist_remote_orig(iterpos, force_refresh) | |
buildList('remote') | |
sortEvent('') | |
} | |
const refreshlist_orig = window.refreshlist | |
window.refreshlist = function () { | |
refreshlist_orig() | |
buildList('local') | |
sortEvent('') | |
} | |
// 初期表示 | |
buildList('local') | |
sortEvent('data-key') | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment