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

180 lines
5.6 KiB
TypeScript

import { OTISSettingsPage } from "./settings";
import { GrapeSearch } from "./GrapeSearch";
import "./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 } from "./helper";
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");
// 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");
}