Amharic/HaHu Pronunciation Tooltip

Displays a tooltip with a pronunciation button for selected Amharic/HaHu characters on any website.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Amharic/HaHu Pronunciation Tooltip
// @description  Displays a tooltip with a pronunciation button for selected Amharic/HaHu characters on any website.
// @match       *://*/*
// @grant        none
// @version      1.6
// @license      MIT
// @author       @skatbr
// @namespace    https://github.com/skatbr
// ==/UserScript==

const amharicToEnglish = {
    ሀ: "ha",
    ሁ: "hu",
    ሂ: "hee",
    ሃ: "ha",
    ሄ: "hae",
    ህ: "heh",
    ሆ: "ho",
    ለ: "le",
    ሉ: "lu",
    ሊ: "lee",
    ላ: "la",
    ሌ: "lay",
    ል: "leh",
    ሎ: "lo",
    ሐ: "ha",
    ሑ: "hu",
    ሒ: "hee",
    ሓ: "ha",
    ሔ: "hae",
    ሕ: "heh",
    ሖ: "ho",
    መ: "muh",
    ሙ: "moo",
    ሚ: "mee",
    ማ: "ma",
    ሜ: "mae",
    ም: "mih",
    ሞ: "mo",
    ሠ: "seh",
    ሡ: "soo",
    ሢ: "see",
    ሣ: "sa",
    ሤ: "sae",
    ሥ: "sih",
    ሦ: "so",
    ረ: "reh",
    ሩ: "roo",
    ሪ: "ree",
    ራ: "ra",
    ሬ: "rae",
    ር: "rih",
    ሮ: "ro",
    ሰ: "seh",
    ሱ: "soo",
    ሲ: "see",
    ሳ: "sa",
    ሴ: "sae",
    ስ: "sih",
    ሶ: "so",
    ሸ: "sheh",
    ሹ: "shoo",
    ሺ: "shee",
    ሻ: "sha",
    ሼ: "shae",
    ሽ: "shih",
    ሾ: "sho",
    ቀ: "qeh",
    ቁ: "qoo",
    ቂ: "qee",
    ቃ: "qa",
    ቄ: "qae",
    ቅ: "qih",
    ቆ: "qo",
    በ: "beh",
    ቡ: "boo",
    ቢ: "bee",
    ባ: "ba",
    ቤ: "bae",
    ብ: "bih",
    ቦ: "bo",
    ቨ: "veh",
    ቩ: "voo",
    ቪ: "vee",
    ቫ: "va",
    ቬ: "vae",
    ቭ: "vih",
    ቮ: "vo",
    ተ: "teh",
    ቱ: "too",
    ቲ: "tee",
    ታ: "ta",
    ቴ: "tae",
    ት: "tih",
    ቶ: "to",
    ቸ: "cheh",
    ቹ: "choo",
    ቺ: "chee",
    ቻ: "cha",
    ቼ: "chae",
    ች: "chih",
    ቾ: "cho",
    ኀ: "ha",
    ኁ: "hu",
    ኂ: "hee",
    ኃ: "ha",
    ኄ: "hae",
    ኅ: "heh",
    ኆ: "ho",
    ነ: "neh",
    ኑ: "noo",
    ኒ: "nee",
    ና: "na",
    ኔ: "nae",
    ን: "nih",
    ኖ: "no",
    ኘ: "gneh",
    ኙ: "gnoo",
    ኚ: "gnee",
    ኛ: "gna",
    ኜ: "gnae",
    ኝ: "gnih",
    ኞ: "gno",
    አ: "aa",
    ኡ: "oo",
    ኢ: "ee",
    ኣ: "aa",
    ኤ: "ae",
    እ: "ih",
    ኦ: "o",
    ከ: "keh",
    ኩ: "koo",
    ኪ: "kee",
    ካ: "ka",
    ኬ: "kae",
    ክ: "kih",
    ኮ: "ko",
    ኸ: "huh",
    ኹ: "hu",
    ኺ: "hee",
    ኻ: "ha",
    ኼ: "hae",
    ኽ: "heh",
    ኾ: "ho",
    ወ: "weh",
    ዉ: "woo",
    ዊ: "wee",
    ዋ: "wa",
    ዌ: "wae",
    ው: "wih",
    ዎ: "wo",
    ዐ: "aa",
    ዑ: "oo",
    ዒ: "ee",
    ዓ: "aa",
    ዔ: "ae",
    ዕ: "ih",
    ዖ: "o",
    ዘ: "ze",
    ዙ: "zu",
    ዚ: "zee",
    ዛ: "zaa",
    ዜ: "zae",
    ዝ: "zih",
    ዞ: "zo",
    ዠ: "zjeh",
    ዡ: "zjoo",
    ዢ: "zjee",
    ዣ: "zjaa",
    ዤ: "zjae",
    ዥ: "zjih",
    ዦ: "zjo",
    የ: "ye",
    ዩ: "yu",
    ዪ: "yee",
    ያ: "yaa",
    ዬ: "yae",
    ይ: "yih",
    ዮ: "yo",
    ደ: "duh",
    ዱ: "doo",
    ዲ: "dee",
    ዳ: "daa",
    ዴ: "dae",
    ድ: "dih",
    ዶ: "do",
    ጀ: "je",
    ጁ: "joo",
    ጂ: "jee",
    ጃ: "jaa",
    ጄ: "jae",
    ጅ: "jih",
    ጆ: "jo",
    ገ: "guh",
    ጉ: "goo",
    ጊ: "gee",
    ጋ: "ga",
    ጌ: "gae",
    ግ: "gih",
    ጎ: "go",
    ጠ: "tte",
    ጡ: "ttu",
    ጢ: "ttee",
    ጣ: "ttaa",
    ጤ: "ttae",
    ጥ: "ttih",
    ጦ: "tto",
    ጨ: "chhe",
    ጩ: "chhoo",
    ጪ: "chhee",
    ጫ: "chhaa",
    ጬ: "chhae",
    ጭ: "chhih",
    ጮ: "cho",
    ጰ: "ppuh",
    ጱ: "ppoo",
    ጲ: "ppee",
    ጳ: "ppaa",
    ጴ: "ppae",
    ጵ: "ppih",
    ጶ: "ppo",
    ጸ: "tse",
    ጹ: "tsoo",
    ጺ: "tsee",
    ጻ: "tsaa",
    ጼ: "tsae",
    ጽ: "tsih",
    ጾ: "tso",
    ፀ: "tse",
    ፁ: "tsoo",
    ፂ: "tsee",
    ፃ: "tsaa",
    ፄ: "tsae",
    ፅ: "tsih",
    ፆ: "tso",
    ፈ: "fuh",
    ፉ: "foo",
    ፊ: "fee",
    ፋ: "faa",
    ፌ: "fae",
    ፍ: "fih",
    ፎ: "fo",
    ፐ: "peh",
    ፑ: "poo",
    ፒ: "pee",
    ፓ: "paa",
    ፔ: "pae",
    ፕ: "pih",
    ፖ: "po",
};

let button = null;
let tooltip = null;

const createButton = (text) => {
    const btn = document.createElement("button");
    btn.classList.add("mdl-button", "mdl-js-button", "mdl-button--fab", "mdl-js-ripple-effect", "mdl-button--colored");
    btn.innerHTML = `<i class="material-icons">volume_up</i>`;
    return btn;
};

const createTooltip = (text) => {
    const tip = document.createElement("div");
    tip.classList.add("mdl-tooltip");
    tip.setAttribute("data-mdl-for", `amharic-tooltip-button`);
    tip.innerHTML = text;
    tip.style.zIndex = "99999999";
    return tip;
};
let playbackSpeed = 1; // Default playback speed

// Function to create a dropdown menu for selecting playback speed
const createPlaybackSpeedMenu = () => {
    const menu = document.createElement("div");
    menu.classList.add("playback-speed-menu");
    menu.style.cssText = `
        position: fixed !important;
        z-index: 99999999 !important;
        top: ${window.pageYOffset + window.innerHeight - 50}px !important;
        left:${window.pageXOffset + window.innerWidth - 100}px !important;
        background-color:white !important;
        border-radius:5px !important;
        padding:5px !important;
        font-size:12px !important;
        font-weight:bold !important;
        box-shadow :0 0 10px rgba(0,0,0,0.2) !important;
        `;

    const label = document.createElement("span");
    label.classList.add("playback-speed-label");
    label.textContent = `Speed : `;
    menu.appendChild(label);

    const select = document.createElement("select");
    select.classList.add("playback-speed-select");
    const speeds = ["0.5x", "1x", "1.5x", "2x", "2.5x", "3x", "3.5x", "4x", "4.5x", "5x"];
    speeds.forEach((speed) => {
        const option = document.createElement("option");
        option.value = speed;
        option.textContent = speed;
        if (parseFloat(speed) === playbackSpeed) {
            option.selected = true;
        }
        select.appendChild(option);
    });
    select.addEventListener("change", (event) => {
        playbackSpeed = parseFloat(event.target.value);
    });
    menu.appendChild(select);

    return menu;
};

// if not playback-speed-menu found, create one
var playbackSpeedMenu = null;
if (!document.getElementById("playback-speed-menu")) {
    playbackSpeedMenu = createPlaybackSpeedMenu();
    document.body.appendChild(playbackSpeedMenu);
}

let audio = null; // Declare the audio variable outside of the playAudio function

document.addEventListener("click", (event) => {
    const selectedText = window.getSelection().toString().trim();
    const characters = selectedText.split("");

    if (characters.length > 0) {
        let audioIndex = 0;
        const playAudio = () => {
            const englishName = amharicToEnglish[characters[audioIndex]];
            if (!englishName) {
                audioIndex++;
                if (audioIndex < characters.length) {
                    setTimeout(() => {
                        playAudio();
                    }, 0); // delay between each audio clip
                }
                return;
            }

            const audioUrl = `https://s3.amazonaws.com/i.litcdn.com/dict/sounds/mp3/${englishName.toLowerCase()}.mp3`;
            if (audio) {
                audio.pause(); // Stop the previous audio clip
                audio.currentTime = 0; // Reset the current time of the audio clip
            }
            audio = new Audio(audioUrl);
            audio.playbackRate = playbackSpeed; // Set the playback speed
            audio.play();

            audio.addEventListener("ended", () => {
                audioIndex++;
                if (audioIndex < characters.length) {
                    setTimeout(() => {
                        playAudio();
                    }, 0); // delay between each audio clip
                }
            });

            if (button) {
                button.remove();
                tooltip?.remove();
            }

            button = createButton(characters[audioIndex]);
            button.setAttribute("id", `amharic-tooltip-button`);
            const range = window.getSelection().getRangeAt(0);
            const rect = range.getBoundingClientRect();
            button.style.top = `${rect.top + window.pageYOffset - 10}px`;
            button.style.left = `${rect.left + window.pageXOffset + rect.width}px`;

            document.body.appendChild(button);

            button.addEventListener("click", (event) => {
                event.stopPropagation();

                if (tooltip) {
                    tooltip.remove();
                }

                tooltip = createTooltip(englishName);
                const buttonRect = button.getBoundingClientRect();
                tooltip.style.top = `${buttonRect.top + window.pageYOffset + buttonRect.height / 2 - tooltip.offsetHeight / 2}px`;
                tooltip.style.left = `${buttonRect.left + window.pageXOffset + buttonRect.width}px`;

                document.body.appendChild(tooltip);
                componentHandler.upgradeElement(tooltip); // Upgrade the tooltip element to use Material Design
                audio.play();
            });
        };

        playAudio();
    } else {
        if (button) {
            button.style.display = "none";
            tooltip?.remove();
        }
    }
});

document.addEventListener("mousedown", (event) => {
    if (button && !button.contains(event.target)) {
        button.style.display = "none";
        tooltip?.remove();
    }
});