@ -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
4
src/ArtistFilter.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export type Artist = {
|
||||
name: string,
|
||||
userid: string
|
||||
}
|
246
src/main.ts
246
src/main.ts
@ -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
3
src/trashIcon.ts
Normal 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>`
|
@ -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
|
||||
}
|
||||
})
|
||||
],
|
||||
]
|
||||
}
|
||||
})
|
||||
|
Reference in New Issue
Block a user