Skip to content

Instantly share code, notes, and snippets.

@tachibanayui
Last active March 5, 2023 13:31
Show Gist options
  • Save tachibanayui/636009165e8fdd4a2ee93542b486a614 to your computer and use it in GitHub Desktop.
Save tachibanayui/636009165e8fdd4a2ee93542b486a614 to your computer and use it in GitHub Desktop.
Jisho + sharpi Lyrics
// ==UserScript==
// @name Jisho.org + sharpi Lyrics
// @namespace http://tampermonkey.net/
// @copyright MIT
// @version 0.1
// @description Allow multiline input and output of japanese text and add romaji support
// @author sharpi (Tachibana Yui)
// @match https://jisho.org/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=google.com
// @grant none
// @require https://unpkg.com/wanakana@5.1.0/wanakana.min.js
// ==/UserScript==
(() => {
// const keyword = decodeURI(window.location.pathname.split("/").last());
const swanakana = document.createElement("script");
swanakana.src = "https://unpkg.com/wanakana@5.1.0/wanakana.min.js";
document.head.appendChild(swanakana);
const css = `
#zen_bar {
max-height: 500px;
}
h1.logo a {
display: inline-block;
}
`;
const style = document.createElement("style");
style.innerHTML = css;
document.head.appendChild(style);
const style2 = document.createElement("style");
document.head.appendChild(style2);
// Branding
const brand = document.createElement("a");
brand.href = "https://github.com/tachibanayui";
brand.innerText = " + sharpi Lyrics";
brand.style.background = "none";
brand.style.display = "inline";
brand.style.fontSize = "2rem";
brand.style.color = "white";
brand.style.textDecoration = "none";
brand.classList.add("sharpi_lyrics");
document.querySelector("h1.logo").appendChild(brand);
// ---
// Analytics (remove if you're not comfortable with this)
const gtag1 = document.createElement("script");
gtag1.async = true;
gtag1.src = "https://www.googletagmanager.com/gtag/js?id=G-W9S48X5HJV";
const gtag2 = document.createElement("script");
gtag2.innerHTML = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-W9S48X5HJV');
`;
document.head.prepend(gtag1, gtag2);
// ---
const oldKw = document.getElementById("keyword");
const keyword = oldKw.getAttribute("value").replaceAll(" ", "\n");
const newKw = createSearchKw();
newKw.value = keyword;
const parent = oldKw.parentElement;
parent.insertBefore(newKw, oldKw);
parent.removeChild(oldKw);
const search = document.getElementById("search");
search.style.display = "contents";
document.querySelector("#page_container div").prepend(createControls());
const words = document.querySelectorAll("#zen_bar li");
let iWord = -1;
let current;
const romajis = [];
for (const line of keyword.split("\n")) {
if (!line.trim()) {
(current ?? words.item(iWord))
.insertAdjacentElement("afterend", document.createElement("br"));
continue;
}
const lastChar = line.trim().last();
let num = line
.chars()
.filter((x) => x === lastChar)
.count();
let g;
while (num > 0) {
g = words.item(++iWord);
const newg = g.cloneNode();
newg.classList.add("visRomaji");
g.classList.add("visJapanese");
const text = g.querySelector(
"span.japanese_word__text_wrapper"
).innerText;
let furi = g.querySelector(
"span.japanese_word__furigana_wrapper"
).innerText;
furi = furi ? furi : text;
const [fr, er] = createRomaji(furi, g.getAttribute("data-pos"));
newg.appendChild(fr);
newg.appendChild(er);
romajis.push(newg);
for (const letter of text) {
if (letter === lastChar) {
num--;
}
}
}
current = createSeperator();
g.insertAdjacentElement("afterend", current);
for (const romaji of romajis) {
current.insertAdjacentElement("afterend", romaji);
current = romaji;
}
romajis.length = 0;
current.insertAdjacentElement("afterend", document.createElement("br"));
}
function createSearchKw() {
const newKw = document.createElement("textarea");
newKw.setAttribute("class", "keyword japanese_gothic");
newKw.setAttribute("name", "keyword");
newKw.setAttribute("id", "keyword");
newKw.setAttribute("tabindex", "1");
newKw.setAttribute("lang", "ja");
newKw.setAttribute("autocapitalize", "off");
newKw.setAttribute("autocomplete", "off");
newKw.setAttribute("autocorrect", "off");
newKw.setAttribute(
"placeholder",
"English, Japanese, Romaji, words or text"
);
newKw.setAttribute("style", "height: 200px; color: white;");
return newKw;
}
function createSeperator() {
const sep = document.createElement("br");
// sep.innerText = " / ";
// sep.style.fontSize = "2rem";
return sep;
}
function createRomaji(word, type) {
const romaji = toRomaji(word, type);
const fr = document.createElement("span");
fr.classList.add("japanese_word__furigana_wrapper");
const frc = document.createElement("span");
frc.classList.add("japanese_word__furigana");
frc.innerText = word === romaji ? "" : word;
fr.appendChild(frc);
const er = document.createElement('span');
er.classList.add("japanese_word__text_wrapper");
const erc = document.createElement("a");
er.appendChild(erc);
const ercc = document.createElement("span");
ercc.classList.add("japanese_word__text_with_furigana");
ercc.innerText = romaji;
erc.appendChild(ercc);
return [fr, er];
}
function toRomaji(word, type) {
// special cases
if (type === "Particle") {
switch (word.trim()) {
case "は":
return "wa";
case "を":
return "o";
case "へ":
return "e";
}
}
return wanakana.toRomaji(word);
}
let showJapanese = true;
let showRomaji = true;
function createControls() {
const pdiv = document.createElement("div");
const checkJp = document.createElement("input");
checkJp.type = "checkbox";
checkJp.checked = true;
checkJp.addEventListener("change", e => {
showJapanese = e.target.checked;
style2.innerHTML = createControlStyles();
})
const checkRj = document.createElement("input");
checkRj.checked = true;
checkRj.type = "checkbox";
checkRj.addEventListener("change", (e) => {
showRomaji = e.target.checked;
style2.innerHTML = createControlStyles();
});
pdiv.append(checkJp, "Show Japanese", document.createElement("br"), checkRj, "Show Romaji");
return pdiv;
}
function createControlStyles() {
return `
.visJapanese {
display: ${showJapanese ? "inline-block" : "none"} !important;
}
.visRomaji {
display: ${showRomaji ? "inline-block" : "none"} !important;
}
`;
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment