sn-translator/sn-translator.js

118 lines
3.7 KiB
JavaScript
Raw Normal View History

2022-12-24 22:43:53 +00:00
// ==UserScript==
// @name SN translator
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Translate posts on SN
2022-12-25 03:51:01 +00:00
// @author ekzyis
2022-12-24 22:43:53 +00:00
// @match https://stacker.news/*
2022-12-25 03:51:01 +00:00
// @icon https://img.freepik.com/free-vector/lightning-bolt-coloured-outline_78370-517.jpg?w=826&t=st=1671940131~exp=1671940731~hmac=d04f3bd1468f1d362a864b4a25e367aef4d1941991161aa008684c5a4089cf0b
2022-12-24 22:43:53 +00:00
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
2022-12-24 22:43:53 +00:00
// ==/UserScript==
const headers = {
2022-12-25 01:38:03 +00:00
origin: 'https://libretranslate.com',
accept: '*/*',
'accept-language': 'de-DE,de;q=0.9,ru-DE;q=0.8,ru;q=0.7,en-US;q=0.6,en;q=0.5',
'sec-ch-ua': '"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"Linux"',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
2022-12-25 01:41:26 +00:00
};
2022-12-24 22:43:53 +00:00
function translate(text, source, target) {
2022-12-25 01:41:26 +00:00
const formData = new FormData();
formData.append('q', text);
formData.append('source', source);
formData.append('target', target);
2022-12-24 22:43:53 +00:00
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
2022-12-25 01:38:03 +00:00
method: 'POST',
url: 'https://libretranslate.com/translate',
2022-12-24 22:43:53 +00:00
data: formData,
headers,
synchronous: true,
onload: function (res) {
2022-12-25 01:41:26 +00:00
const body = JSON.parse(res.responseText);
if (res.status !== 200) return reject(body);
return resolve(body.translatedText);
2022-12-24 22:43:53 +00:00
},
2022-12-25 01:41:26 +00:00
});
});
2022-12-24 22:43:53 +00:00
}
2022-12-25 01:41:26 +00:00
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
2022-12-24 22:43:53 +00:00
2022-12-25 01:58:47 +00:00
const log = (msg) => console.log(`sn-translator:`, msg);
2022-12-25 01:57:20 +00:00
2022-12-25 03:39:14 +00:00
function createButton(textNode) {
2022-12-25 02:06:04 +00:00
const btn = document.createElement('button');
btn.innerText = 'translate';
2022-12-25 02:06:04 +00:00
btn.onclick = async (e) => {
2022-12-25 03:39:14 +00:00
const hasTranslation = !!textNode.querySelector('hr');
if (hasTranslation) return;
2022-12-25 03:53:50 +00:00
// TODO: let user choose target language
2022-12-25 03:39:14 +00:00
const t = await translate(textNode.innerText, 'auto', 'en').catch(console.error);
if (t) {
const divider = document.createElement('hr');
textNode.appendChild(divider);
const em = document.createElement('em');
const p = document.createElement('p');
p.innerText = 'Translation:';
const p2 = document.createElement('p');
p2.innerText = t;
em.appendChild(p);
em.appendChild(p2);
textNode.appendChild(em);
}
2022-12-25 02:06:04 +00:00
};
btn.classList.add('translate');
2022-12-25 02:06:04 +00:00
return btn;
}
2022-12-25 01:35:05 +00:00
function addButtons() {
2022-12-25 01:41:26 +00:00
const commentSection = document.querySelector('.item_comments__cN57K');
if (!commentSection) return;
2022-12-25 01:41:26 +00:00
const comments = commentSection.querySelectorAll('.comment_comment__5uvl3');
2022-12-25 01:57:20 +00:00
log(`Found ${comments.length} comment(s)`);
log(`Adding translate button to every comment ...`);
2022-12-24 22:43:53 +00:00
for (const comment of comments) {
2022-12-25 01:41:26 +00:00
const topBar = comment.querySelector('.item_other__qNlji');
2022-12-25 03:39:14 +00:00
const textNode = comment.querySelector('.comment_text__nHI0E > .text_text__fuZIZ');
const btn = createButton(textNode);
2022-12-25 01:41:26 +00:00
topBar.appendChild(btn);
2022-12-24 22:43:53 +00:00
}
2022-12-25 01:57:20 +00:00
log(`Done`);
2022-12-25 01:35:05 +00:00
}
2022-12-25 01:41:26 +00:00
(async function () {
2022-12-25 01:56:39 +00:00
// Sleep before running script on page load
// since else we might get overwritten by loading content.
const initialSleep = 1000;
await sleep(initialSleep);
GM_addStyle(`
.translate {
color: var(--theme-grey);
border: none;
cursor: pointer;
background: rgba(0,0,0,0);
}
`);
2022-12-25 01:56:39 +00:00
let pathname = window.location.pathname;
2022-12-25 01:57:20 +00:00
log(`Current location: ${pathname}`);
2022-12-25 01:41:26 +00:00
addButtons();
2022-12-25 01:56:39 +00:00
// Check if URL changed and rerun script
const scriptInterval = 1000;
setInterval(() => {
if (window.location.pathname !== pathname) {
pathname = window.location.pathname;
2022-12-25 01:57:20 +00:00
log(`New location detected: ${pathname}`);
2022-12-25 01:56:39 +00:00
addButtons();
}
}, scriptInterval);
2022-12-25 01:41:26 +00:00
})();