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

233 lines
7.4 KiB
TypeScript

import { Component, createSignal, For, Show } from "solid-js";
import { click_out_directive } from "./helper";
import { DANBOORU_API, booru_post, iqdb_search, saucenao_search, tweet_search } from "./api";
import { OTISSettingsPage } from "./settings";
import iqdb_icon from "./assets/iqdb.ico";
import sauce_icon from './assets/saucenao.ico';
import grape_icon from './assets/grapecat.png';
import danbo_icon from './assets/danbo.png';
import "./style.css";
// Typescript strips this directive if we don't
// force call it in this module
const clickOutside = click_out_directive
type GrapeSearchParams = {
media_url:string[],
id:string,
username: string
}
const GrapeCatIcon = ({onClick}:any) => <img onClick={onClick} src={grape_icon} class={"otis-icon"} title="Tweet Search" style={{"width":"20px", "margin-bottom":"2px"}} />
const IqdbIcon = ({onClick}:any) => <img onClick={onClick} src={iqdb_icon } class={"otis-icon"} title="Danbooru IQDB Search" />
const SauceIcon = ({onClick}:any) => <img onClick={onClick} src={sauce_icon} class={"otis-icon"} title="SauceNAO Search" style={{"margin-right":"unset"}} />
const DanboIcon = ({onClick}:any) => <img onClick={onClick} src={danbo_icon} class={"otis-danbo-icon"} />
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 GrapeSearch : Component<GrapeSearchParams> = ({media_url,id, username}) => {
const [showTooltip, setShowTooltip] = createSignal(false);
const [ShowDanboResult, setShowDanboResult] = createSignal(false);
const [danboPostID, setPostID ] = createSignal(0);
const [posts, setPosts] = createSignal<Array<booru_post>>([])
const booru_check = async (e:MouseEvent) => {
//console.debug({id,username})
//console.debug({event:e});
const ico = e.target as HTMLImageElement;
ico.classList.add('otis-icon-loading');
ico.classList.remove('otis-icon-noresult');
const res = await tweet_search(id,username)
ico.classList.remove('otis-icon-loading');
if ( res.length == 0 ) {
ico.classList.add('otis-icon-noresult');
ico.title = "Can't find any post based on Tweet ID."
return console.debug("grape: none")
}
setPosts(res)
if ( res.length === 1 ) setShowDanboResult(true)
else setShowTooltip(true)
}
const iqdb_check = async (e:MouseEvent) => {
const ico = e.target as HTMLImageElement;
ico.classList.add('otis-icon-loading');
ico.classList.remove('otis-icon-noresult');
// TODO: handle which image to check
const res = await iqdb_search(media_url[0])
ico.classList.remove('otis-icon-loading');
if ( res.length == 0 ) {
ico.classList.add('otis-icon-noresult');
ico.title = "No relevant image search results from IQDB"
return console.debug("iqdb: none");
}
setPosts(res)
if ( res.length === 1 ) setShowDanboResult(true)
else setShowTooltip(true)
}
const sauce_check = async (e:MouseEvent) => {
const ico = e.target as HTMLImageElement;
ico.classList.add('otis-icon-loading');
ico.classList.remove('otis-icon-noresult');
// TODO: handle which image to check
const res = await saucenao_search(media_url[0]);
ico.classList.remove('otis-icon-loading');
if ( res.length == 0 ) {
ico.classList.add('otis-icon-noresult');
ico.title = "No relevant image search results from IQDB"
return console.debug("sauce: none");
}
setPosts(res)
if ( res.length === 1 ) setShowDanboResult(true)
else setShowTooltip(true)
}
const DanboPostsResult = () => (
<>
<DanboIcon />
<a
rel="noopener"
target="_blank"
class={"danbo-text-link"}
href={`${DANBOORU_API}/posts/${posts()[0]?.id}`}
onmouseover={() => setShowTooltip(true)}>
{`#${posts()[0]?.id}`}
</a>
</>
)
return ( <>
<span>
<Show
when={!ShowDanboResult()}
fallback={<DanboPostsResult /> }>
<GrapeCatIcon onClick={booru_check} />
<IqdbIcon onClick={iqdb_check} />
<SauceIcon onClick={sauce_check} />
</Show>
</span>
<div class={"dropdown-menu danbo-more-results"} use:clickOutside={() => setShowTooltip(false)} hidden={!showTooltip()}>
<For each={posts()}>
{ (post) =>
<span
class={"danbo-item"}
onClick={() => window.open(`${DANBOORU_API}/posts/${post.id}`,'_blank')}>
<img src={post.thumbnail} width="80px"/>
<div>
<div> #{post.id} </div>
<div> {post.source_domain} </div>
<div> { post.img_width >= 0 ? `${post.img_width} x ${post.img_height}` : ""} </div>
</div>
</span>
}
</For>
</div>
</>
)
}
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 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 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}/>;
twt_child_elipsis?.before(...grape as any);
// 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 >= 10 ) 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");
// 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");
}