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) => const IqdbIcon = ({onClick}:any) => const SauceIcon = ({onClick}:any) => const DanboIcon = ({onClick}:any) => 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 = ({media_url,id, username}) => { const [showTooltip, setShowTooltip] = createSignal(false); const [ShowDanboResult, setShowDanboResult] = createSignal(false); const [danboPostID, setPostID ] = createSignal(0); const [posts, setPosts] = createSignal>([]) 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 = () => ( <> setShowTooltip(true)}> {`#${posts()[0]?.id}`} ) return ( <> }>
setShowTooltip(false)} hidden={!showTooltip()}> { (post) => window.open(`${DANBOORU_API}/posts/${post.id}`,'_blank')}>
#{post.id}
{post.source_domain}
{ post.img_width >= 0 ? `${post.img_width} x ${post.img_height}` : ""}
}
) } 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 = ; 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"); }