2025/04/05

Initial base

Signed-off-by: Drunkoatmeal <no@thanks.com>
This commit is contained in:
Drunkoatmeal
2025-04-05 01:32:22 +07:00
parent bd52d178bc
commit 80ddc9133c
5 changed files with 214 additions and 54 deletions

View File

@ -1,7 +1,7 @@
{
"tasks": {
"dev": "deno run -A --node-modules-dir npm:vite build --watch",
"build": "deno run -A --node-modules-dir npm:vite build --mode production",
"build": "deno run -A --node-modules-dir npm:vite build --mode prod",
"preview": "deno run -A --node-modules-dir npm:vite preview",
"serve": "deno run --allow-net --allow-read jsr:@std/http@1/file-server dist/"
},

4
src/ArtistFilter.ts Normal file
View File

@ -0,0 +1,4 @@
export type Artist = {
name: string,
userid: string
}

View File

@ -1,12 +1,11 @@
import type { AjaxSearchResponse } from './AjaxSearchResponse.ts';
import type { Artist } from './ArtistFilter.ts';
import { TrashIcon } from './trashIcon.ts';
const { fetch: originalFetch } = unsafeWindow;
type Artist = {
name: string,
userid: string
}
let ArtistIdList: Artist[] = loadArtistList()
let ArtistIdList: string[] = artist_list_load().map(x => x.userid)
unsafeWindow.fetch = async (...args) => {
const [resource, config] = args;
@ -14,7 +13,7 @@ unsafeWindow.fetch = async (...args) => {
const path : string = resource;
if ( path.startsWith('/ajax/search') ) {
if ( path.startsWith('/ajax/search/') ) {
// tampering search results with artist filter
const json = () =>
response
@ -23,15 +22,14 @@ unsafeWindow.fetch = async (...args) => {
.then((data:AjaxSearchResponse) => {
console.debug({
request: resource,
response: data
response: data,
ArtistIdList
})
// test filter artist id 106029976
if (path.startsWith('/ajax/search/illustrations')) {
data.body.illust.data = data.body.illust.data.filter( ({userId}) => !ArtistIdList.includes(userId) );
}
else if ( path.startsWith('/ajax/search/top')) {
else if ( path.startsWith('/ajax/search/top') || path.startsWith('/ajax/search/artworks')) {
data.body.illustManga.data = data.body.illustManga.data.filter( ({userId}) => !ArtistIdList.includes(userId) );
}
@ -43,12 +41,140 @@ unsafeWindow.fetch = async (...args) => {
return response;
};
function loadArtistList() {
function artist_list_load() : Artist[] {
return JSON.parse( GM_getValue('ArtistList', '[]') );
}
function artist_list_update(list: Artist[]) {
GM_setValue('ArtistList', JSON.stringify(list));
ArtistIdList = artist_list_load().map(x => x.userid)
}
function addArtist(name:string,id:string) {
const list = artist_list_load();
if ( list.findIndex( x=> x.userid === id ) === -1) {
list.push({name,userid:id})
artist_list_update(list);
}
console.debug({name,id, list: artist_list_load()})
}
function delArtist(userid:string) {
const list = artist_list_load().filter( x => x.userid !== userid );
artist_list_update(list);
}
function AttachSettings(NavNode:HTMLElement) {
if ( NavNode.pxv_settings_but ) return;
NavNode.pxv_settings_but = true
const button = document.createElement('button');
button.id = 'pxv-artist-filter';
button.classList.add('pxv-but','pxv-settings-but');
button.textContent = 'Artist Filter';
const FilterListElement = () => {
const template = document.createElement('template');
let list: Artist[] = artist_list_load();
//list = list.concat(list).concat(list).concat(list);
const el_list: Element[] = [];
for ( const { name, userid } of list) {
const item = document.createElement('div');
const artist_name = document.createElement('a');
artist_name.target = '_blank'
artist_name.href = `/users/${userid}`
artist_name.text = name;
const del_but = document.createElement('button');
del_but.innerHTML = TrashIcon;
del_but.onclick = () => {
delArtist(userid);
item.parentNode?.removeChild(item);
}
item.append(del_but,artist_name);
el_list.push(item);
}
template.append(...el_list);
console.debug({template})
return template.childNodes;
}
button.onclick = () => {
button.blur();
const template = document.createElement('template');
template.innerHTML = `
<div class='pxv-screen'>
<dialog class='pxv-dialog' open>
<h1 class="pxv-title">Artist Filter List</h1>
<div class="pxv-artist-grid">
<div>One</div>
<div>Two</div>
<div>Three</div>
<div>Four</div>
<div>Five</div>
</div>
<form method="dialog">
<button class='pxv-but'>Close</button>
</form>
</dialog>
</div>
`;
const node = template.content.firstElementChild;
const grid = node?.getElementsByClassName('pxv-artist-grid').item(0) as HTMLDivElement;
grid.replaceChildren(...FilterListElement())
const submit = node?.getElementsByClassName('pxv-but').item(0) as HTMLButtonElement;
submit.onclick = () => document.body.removeChild(node);
document.body.appendChild(node);
}
NavNode.parentNode.insertBefore(button,NavNode.nextSibling);
}
function AttachFilterButton(ModalNode:Node) {
if ( ModalNode.pxv_fil_but ) return ;
ModalNode.pxv_fil_but = true;
const info = ModalNode.parentElement?.querySelector('div a[data-gtm-value]:not(:has(*))') as HTMLAnchorElement;
console.debug({
name: info.text,
userid: info.getAttribute('data-gtm-value')
})
const button = document.createElement('button');
button.id = 'pxv-artist-filter';
button.classList.add('pxv-but','pxv-modal-filter-but');
button.textContent = 'Filter';
button.onclick = () => {
if ( confirm(`Do you want to filter ${info.text}'s posts ?`)) {
const name = info.text;
const userid = info.getAttribute('data-gtm-value') || '-1';
addArtist(name,userid);
alert(`${info.text} has been added to the filter list.`);
}
}
ModalNode.appendChild(button);
console.debug({ModalNode})
}
function init() {
GM_addStyle(`
.pxv-but {
color: rgb(245, 245, 245);
@ -62,10 +188,16 @@ function AttachSettings(NavNode:HTMLElement) {
font-weight: bold;
cursor: pointer;
}
.artist-filter-but {
.pxv-settings-but {
margin-left: auto;
margin-right: 12px;
}
.pxv-modal-filter-but {
margin: 5px auto;
padding: 5px 24px;
}
.pxv-but:focus {
outline:none;
@ -92,56 +224,70 @@ function AttachSettings(NavNode:HTMLElement) {
width: 400px;
height: 400px;
background-color: rgb(31, 31, 31);
display:flex;
flex-direction: column;
}
.pxv-dialog .pxv-but {
display: block;
margin: 10px auto;
}
.pxv-title {
font-size: 16px;
text-align: center;
}
.pxv-artist-grid {
display: grid;
grid-template-columns: 1fr 1fr;
max-height: 310px;
overflow-y: scroll;
margin-bottom: auto;
}
.pxv-artist-grid > div {
padding:10px 0;
font-size: 14px;
transition: background-color 0.2s;
display:flex;
}
.pxv-artist-grid > div:hover {
background-color: #3a3a3a;
}
.pxv-artist-grid > div > button {
margin: 0 5px;
padding: 0px;
border: medium;
outline: none;
background: transparent;
cursor: pointer;
color: rgb(133, 133, 133);
}
.pxv-artist-grid > div > a {
flex-grow:1;
margin: auto 0;
}
`)
const button = document.createElement('button');
button.id = 'pxv-artist-filter';
button.classList.add('pxv-but','artist-filter-but');
button.textContent = 'Artist Filter';
button.onclick = () => {
button.blur();
const template = document.createElement('template');
template.innerHTML = `
<div class='pxv-screen'>
<dialog class='pxv-dialog' open>
<h1 class="pxv-title">Artist Filter List</h1>
<form method="dialog">
<button class='pxv-but'>Close</button>
</form>
</dialog>
</div>
`;
const node = template.content.firstElementChild;
const submit = node.getElementsByTagName('button').item(0);
submit.onclick = () => document.body.removeChild(node);
document.body.appendChild(node);
}
NavNode.parentNode.insertBefore(button,NavNode.nextSibling);
}
function init() {
const pixivgohomeyoudrunk = setInterval(() => {
const attach_settings = setInterval(() => {
const navNode = document.getElementsByTagName('nav').item(0);
if (navNode){
clearInterval(pixivgohomeyoudrunk);
AttachSettings(navNode)
}
},1000)
const pixiv_attach_artist = setInterval( () => {
const profileModalsearch = document.evaluate("//*/div[@open='']", document,null, XPathResult.FIRST_ORDERED_NODE_TYPE);
//const profileModalsearch = document.evaluate("//*/a[contains(text(),'View Profile')]", document,null, XPathResult.FIRST_ORDERED_NODE_TYPE);
if ( profileModalsearch.singleNodeValue ) {
AttachFilterButton(profileModalsearch.singleNodeValue)
}
},1000)
}
init()
init()

3
src/trashIcon.ts Normal file
View File

@ -0,0 +1,3 @@
export const TrashIcon = `<svg viewBox="0 0 24 24" size="24" class="sc-11csm01-0 fivNSm"><path d="M9 4H15V5H17.5C18.0523 5 18.5 5.44772 18.5 6C18.5 6.55228 18.0523 7 17.5 7H6.5
C5.94772 7 5.5 6.55228 5.5 6C5.5 5.44772 5.94772 5 6.5 5H9V4Z"></path><path d="M7.01047 8C6.45412 8 6.00473 8.45409 6.01053 9.01042L6.11469 19.0104
C6.1204 19.5586 6.56641 20 7.11464 20H17C17.5523 20 18 19.5523 18 19V9C18 8.44772 17.5523 8 17 8H7.01047Z"></path></svg>`

View File

@ -3,7 +3,13 @@ import Userscript from 'vite-userscript-plugin'
import { name, description, version } from './package.json';
// https://vite.dev/config/
export default defineConfig({
export default defineConfig( ({mode}) => {
return {
esbuild: {
pure: mode === 'prod' ? ['console.debug'] : [],
drop: mode === 'prod' ? ['console'] : []
},
plugins: [
Userscript({
entry: 'src/main.ts',
@ -14,12 +20,13 @@ export default defineConfig({
namespace: 'noproompter',
match: 'https://www.pixiv.net/*/tags/*',
noframes:true,
"run-at": "document-end",
"run-at": "document-start",
grant: ['GM.setValue', 'GM.addStyle', 'GM.getValue', 'GM.addElement']
},
server: {
port: 3000
}
})
],
]
}
})