Last active
April 10, 2019 23:46
-
-
Save tjbrockmeyer/5ecea0c150e30df968b5568e396cebee to your computer and use it in GitHub Desktop.
Add video search links to your Kitsu library page for quick lookups of the shows/manga you watch/read
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.tb-watch-link { | |
padding: 4px; | |
border-radius: 50px; | |
color: white; | |
margin-left: 15px; | |
margin-top: 10px; | |
margin-bottom: 5px; | |
} | |
.tb-watch-links { | |
margin-top: 3px; | |
border-style: ridge; | |
border-width: 1px; | |
border-radius: 10px; | |
} | |
.tb-poster-watch-links { | |
margin-left: 2px; | |
margin-top: -220px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Inject this javascript into the Kitsu library page: kitsu.io/users/*/library | |
// Place your links here. | |
// Item 1: Name of link. | |
// Item 2: Url of link. | |
// (optional) Item 3: POST form parameter name | |
// OR query format updater function | |
const myLinks = { | |
manga: [ | |
['Webtoons', 'https://www.webtoons.com/search?keyword='], | |
['MangaRock', 'https://mangarock.com/search?q='], | |
['MangaDex', 'https://mangadex.org/search?title='], | |
['ReadMangaToday', 'https://www.readmng.com/search', 'query'], | |
['MangaKakalot', 'https://mangakakalot.com/search/', q => q.replace(/[^a-zA-Z0-9_]+/g, '_')], | |
], | |
anime: [ | |
['CrunchyRoll', 'https://www.crunchyroll.com/search?q='], | |
['Funimation', 'https://www.funimation.com/search/?q='], | |
['GoGoAnime', 'https://www.gogoanime1.com/?s='], | |
['9Anime', 'https://www3.9anime.to/search?keyword='], | |
['OtakuStream', 'https://otakustream.unblocker.cc/?s='], | |
['KissAnime', 'https://kissanime.ru/search/anime', 'keyword'], | |
] | |
} | |
function findChildren(node) { | |
nodes = []; | |
Array.from(arguments).splice(1).forEach(name => { | |
const next = Array.from(node.childNodes).find(x => x.localName === name || x.className === name); | |
if(next !== undefined) { | |
nodes.push(next); | |
node = next; | |
} | |
}); | |
return nodes; | |
} | |
function getTooltip() { | |
return document.getElementsByClassName('library-grid-popover media-tooltip ember-tether')[0]; | |
} | |
function createLink(text, url, title) { | |
const link = document.createElement('a'); | |
link.setAttribute('class', 'tb-watch-link'); | |
link.setAttribute('href', url + title); | |
link.setAttribute('target', '_blank'); | |
const linkText = document.createTextNode(text); | |
link.appendChild(linkText); | |
return link; | |
} | |
function createPostLink(text, url, key, title) { | |
const form = document.createElement('form'); | |
form.setAttribute('method', 'post'); | |
form.setAttribute('action', url); | |
form.setAttribute('target', '_blank'); | |
const input = document.createElement('input'); | |
input.setAttribute('type', 'hidden'); | |
input.setAttribute('name', key); | |
input.setAttribute('value', title); | |
form.appendChild(input); | |
const link = document.createElement('a'); | |
link.setAttribute('class', 'tb-watch-link'); | |
link.setAttribute('href', '#'); | |
link.setAttribute('onclick', 'return false;'); | |
const linkText = document.createTextNode(text); | |
link.appendChild(linkText); | |
link.appendChild(form); | |
link.addEventListener('click', () => form.submit()); | |
return link; | |
} | |
function appendLinks(node, title, isPoster, isManga) { | |
const links = []; | |
const list = isManga ? myLinks.manga : myLinks.anime; | |
list.forEach(x => { | |
if(x.length === 3 && typeof x[2] === 'string') { | |
links.push(createPostLink(x[0], x[1], x[2], title)); | |
} else { | |
if(x.length === 3) { | |
title = x[2](title); | |
} | |
links.push(createLink(x[0], x[1], title)); | |
} | |
}); | |
if(isPoster) { | |
links.forEach(x => x.setAttribute('class', 'grid-reaction--add')); | |
} | |
links.forEach(x => node.appendChild(x)); | |
} | |
function createWatchLinks(isManga) { | |
const table = document.getElementsByClassName('table table-responsive library-list')[0]; | |
if(!table) { | |
return; | |
} | |
const [thead] = findChildren(table, 'thead'); | |
const [tbody] = findChildren(table, 'tbody'); | |
tbody.childNodes.forEach(row => { | |
if(row.localName !== 'div') { | |
return; | |
} | |
const [tr, mediaCell, cellTitle, titleWrapper, titleA] = | |
findChildren(row, 'tr', 'media-cell', 'cell-title', 'title-wrapper', 'a'); | |
const [entryIcons] = findChildren(cellTitle, 'entry-icons'); | |
const title = titleA.innerText; | |
if(!findChildren(entryIcons, 'tb-watch-links').length) { | |
const links = document.createElement('div'); | |
links.setAttribute('class', 'tb-watch-links'); | |
links.style.display = 'none'; | |
appendLinks(links, title, false, isManga); | |
entryIcons.appendChild(links); | |
mediaCell.addEventListener('mouseenter', () => links.style.display = 'block'); | |
mediaCell.addEventListener('mouseleave', () => links.style.display = 'none'); | |
} | |
}); | |
} | |
function createPosterWatchLinks(isManga) { | |
const posters = document.getElementsByClassName('media-grid container')[0]; | |
if(!posters) { | |
return; | |
} | |
const [row] = findChildren(posters, 'row'); | |
row.childNodes.forEach(poster => { | |
if(poster.localName !== 'div') { | |
return; | |
} | |
const [div1, div2, posterOverlay] = findChildren(poster, 'div', 'div', 'poster-overlay'); | |
const [gridReaction, gridReactionP, gridReactionA] = findChildren(posterOverlay, 'grid-reaction', 'p', 'a'); | |
if(gridReactionA && gridReactionA.innerText !== 'VIEW/EDIT REACTION') { | |
gridReactionA.innerText = 'VIEW/EDIT REACTION'; | |
} | |
if(!findChildren(posterOverlay, 'tb-poster-watch-links').length) { | |
const links = document.createElement('div'); | |
links.setAttribute('class', 'tb-poster-watch-links'); | |
posterOverlay.appendChild(links); | |
let enterEvent; | |
const handleMouseenter = () => { | |
enterEvent = setTimeout(() => { | |
const tooltip = getTooltip(); | |
if(!tooltip) { | |
handleMouseenter(); | |
return; | |
} | |
const [div3, div4, mediaTitle] = findChildren(tooltip, 'div', 'div', 'media-title'); | |
const title = mediaTitle.innerText; | |
appendLinks(links, title, true, isManga); | |
posterOverlay.removeEventListener('mouseenter', handleMouseenter); | |
posterOverlay.removeEventListener('mouseleave', handleMouseleave); | |
}, 50); | |
}; | |
const handleMouseleave = () => { | |
if(enterEvent !== undefined) { | |
clearTimeout(enterEvent); | |
enterEvent = undefined; | |
} | |
}; | |
posterOverlay.addEventListener('mouseenter', handleMouseenter); | |
posterOverlay.addEventListener('mouseleave', handleMouseleave); | |
} | |
}); | |
} | |
function run() { | |
const selector = document.getElementsByClassName('ember-power-select-selected-item'); | |
if(!selector || selector.length !== 2) { | |
return; | |
} | |
const isManga = selector[1].innerText.includes('Manga'); | |
try { | |
createWatchLinks(isManga); | |
createPosterWatchLinks(isManga); | |
} catch(error) { | |
// console.error(error); | |
} | |
} | |
setInterval(run, 500); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To see how it looks, click here!