old-twitter-image-search/src/index.tsx

182 lines
5.6 KiB
TypeScript

import { OTISSettingsPage } from "./settings";
import { GrapeSearch } from "./GrapeSearch";
import css from "./style.css";
import { DanboIcon } from "./Icons";
import { DANBOORU_API, danbo_artist, danbo_artist_search } from "./api";
import { createSignal, Show, For } from "solid-js";
import { click_out_directive, delay } from "./helper";
import { GM_addStyle } from 'vite-plugin-monkey/dist/client';
const clickOutside = click_out_directive
type UserSearchParams = {
username: string,
user_id: string,
is_tweet_page: bool
}
function ArtistSearch({username,user_id, is_tweet_page}:UserSearchParams) {
//const DanboIcon = ({onClick}:any) => <img onClick={onClick} src={danbo_icon} class={"otis-danbo-icon"} />
let danboIcon;
const [Artist,setArtist] = createSignal<danbo_artist>();
const [ShowUrls, setShowUrls] = createSignal<boolean>(false);
const ArtistSearchClicked = async (e:MouseEvent) => {
const ico = danboIcon as HTMLImageElement;
ico.classList.add('otis-icon-loading');
ico.classList.remove('otis-icon-noresult');
const res = await danbo_artist_search(username)
console.debug(res || "not found")
ico.classList.remove('otis-icon-loading');
if ( !res ) {
ico.classList.add('otis-icon-noresult');
ico.title = "No artist tag found on Danbooru"
return console.debug("artist: none")
}
setArtist(res);
if ( res.urls.length >= 1 ) setShowUrls(true)
}
return (
<span class={"danbo-artist-name tweet-button"} onClick={ArtistSearchClicked} classList={{"danbo-artist-name-tweetpage": is_tweet_page}}>
<DanboIcon
ref={danboIcon}
title="Perform manual artist search on Danbooru"
/>
<Show
when={Artist()}
fallback={ is_tweet_page ? "Artist Search": ""} >
<a
onmouseover={() => setShowUrls(true)}
href={ !(Artist().is_banned)
? `${DANBOORU_API}/posts?tags=${Artist().name}`
: `${DANBOORU_API}/artists/${Artist().id}`}
classList={{"danbo-artist-banned": Artist().is_banned}}
target="_blank" >
{Artist().name}
</a>
<div
class={"dropdown-menu"}
hidden={!ShowUrls()}
onmouseleave={() => setShowUrls(false)}
use:clickOutside={() => setShowUrls(false)}>
<For each={Artist().urls} >
{ ({url}) =>
<a href={url} target="_blank"> {url} </a>
}
</For>
</div>
</Show>
</span>
)
}
async function main() {
// check current page. Switch to Settings page instead
const settings_page = document.URL.endsWith("/old/settings");
if ( settings_page ) return OTISSettingsPage()
const callback : MutationCallback = (mutationList, observer) => {
for (const mutation of mutationList) {
if (mutation.type !== "childList") return;
mutation.addedNodes.forEach( (node) => {
const tweet = node as HTMLElement;
const media = tweet.getElementsByClassName('tweet-media').item(0);
if ( !media ) return;
const imgs = media.getElementsByTagName('img');
if ( !imgs ) return;
const vids = media.getElementsByTagName('video');
console.debug(vids);
if ( vids.length ) return;
const twt_interact = tweet.getElementsByClassName('tweet-interact').item(0);
const twt_avatar = tweet.getElementsByClassName('tweet-avatar-link').item(0) as HTMLAnchorElement;
const twt_child_elipsis = twt_interact?.getElementsByClassName('tweet-interact-more').item(0);
const twt_time = tweet.getElementsByClassName('tweet-time').item(0);
const twt_body = tweet.getElementsByClassName('tweet-body-main').item(0);
const tweet_id = tweet.dataset.tweetId || "0"
const tweet_user = twt_avatar.href.split('/').pop() || "*"
//console.debug({tweet_id: tweet_id, media:imgs?.length || 0});
//console.debug({tweet_user:tweet_user});
let img_urls = []
for ( const img of imgs ) {
img_urls.push(img.src)
}
//console.debug({media:img_urls, id:tweet_id, user:tweet_user});
const grape = () => <GrapeSearch media_url={img_urls} id={tweet_id} username={tweet_user}/>;
const artist = () => <ArtistSearch username={tweet_user} user_id={tweet_id} is_tweet_page={Boolean(twt_body)}/>
if ( !twt_body ) twt_time?.after(artist());
else twt_body?.prepend(artist());
twt_child_elipsis?.before(...grape());
// TODO: Implement OTIS buttons
})
}
};
const tweet_observer = new MutationObserver(callback);
const timeline = document.getElementById('timeline');
if ( !timeline ) return;
const config: MutationObserverInit = {
subtree:false,
childList:true,
attributes:false
}
tweet_observer.observe(timeline, config);
}
const init:any = async (limit=0) => {
/* We need to do this hack because Old Twitter Extension
would just dump entire Twitter's page including userscripts
and replace it with OT's custom page instead of replacing
Twitter's Document Body page
*/
if ( limit >= 5 ) return console.error("OTIS: Old Twitter Extension not detected, userscript won't run")
const element = document.getElementById('center-cell');
if (element) {
console.debug("Old Twitter detected");
const w = GM_addStyle(css);
return main();
}
else {
console.debug("can't find it");
await delay(1000);
return init(limit += 1);
}
}
//
init()
// const element = document.getElementById('center-cell');
// if (element) {
// console.debug("Old Twitter Extension detected");
// main();
// }
// else {
// console.debug("can't find it");
// }