// ==UserScript==
// @name LZT Summarize
// @namespace lzt-summarize
// @version 1.0.0
// @description Summarize a large topic to find out if you need it
// @author Toil
// @license MIT
// @match https://zelenka.guru/threads/*
// @match https://lolz.live/threads/*
// @match https://lolz.guru/threads/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=zelenka.guru
// @supportURL https://zelenka.guru/toil/
// @grant GM_addStyle
// ==/UserScript==
(function () {
"use strict";
GM_addStyle(`
.LZTSummarizeThreadBar {
background: rgb(39, 39, 39);
padding: 15px 20px;
margin-top: 15px;
border-radius: 10px;
height: auto;
}
.LZTSummarizeThreadBarTitle {
font-weight: bold;
font-size: 18px;
padding: 0;
margin: 0 0 2px;
line-height: 33px;
overflow: hidden;
}
.LZTSummarizeThreadBarContent {
font-size: 14px;
}
.LZTSummarizeThesises {
margin-left: 16px;
}
.LZTSummarizeThesises li {
list-style: decimal;
margin: 2px 0;
line-height: 20px;
}
`);
const SUMMARIZE_URL = "https://summarize.toil.cc/generation";
const SUMMARIZE_TITLE = "<i class='fas fa-sparkles'></i> Суммаризатор тем";
const yandexStatus = {
StatusInProgress: 1,
StatusSuccess: 2,
StatusError: 3,
StatusFetchError: 999,
};
class SummarizeStatus {
static Waiting = new SummarizeStatus("waiting").name;
static Error = new SummarizeStatus("error").name;
static Success = new SummarizeStatus("success").name;
constructor(name) {
this.name = name;
}
}
function checkSummarizeCode(res) {
switch (res.status_code) {
case yandexStatus.StatusInProgress:
return {
status: SummarizeStatus.Waiting,
title: "Суммаризация...",
desc: [
{
id: 0,
content: `Ожидание окончания суммаризации текста`,
},
],
};
case yandexStatus.StatusFetchError:
return {
status: SummarizeStatus.Error,
title: "Ошибка запроса",
desc: [
{
id: 0,
content: `Не удалось совершить запрос к Yandex Summarize API`,
},
],
};
case yandexStatus.StatusError:
return {
status: SummarizeStatus.Error,
title: "Ошибка YandexGPT",
desc: [
{
id: 0,
content: "Возникла ошибка при суммаризации текста",
},
],
};
case yandexStatus.StatusSuccess:
return {
status: SummarizeStatus.Success,
title: "Успех",
desc: res.thesis,
};
default:
return {
status: SummarizeStatus.Error,
title: "Неизвестная ошибка",
desc: [
{
id: 0,
content:
"Во время выполнения что-то пошло не так и из-за этого не удалось определить результат суммаризации",
},
],
};
}
}
async function genSummarize(text, session_id) {
return await fetch(SUMMARIZE_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
text,
session_id,
}),
})
.then((res) => res.json())
.catch((err) => {
console.error(
"[LZT Summarize] Failed to generate a summarize of the text",
err
);
return false;
});
}
function getThreadContent() {
return document
.querySelector(".message.firstPost > .messageInfo article")
?.textContent?.trim();
}
async function getThreadContentByAjax(threadId) {
try {
const res = await XenForo.ajax(`/threads/${threadId}`);
const resHTML = res.templateHtml;
const parser = new DOMParser();
const parsedHTML = parser.parseFromString(resHTML, "text/html");
const text = parsedHTML.querySelector(
".message.firstPost > .messageInfo article"
)?.innerText;
return text;
} catch {
return undefined;
}
}
function clearSummarizeContent(text) {
// replace \n, \t, \r to basic spaces
// replace ip to void (many ips in text = server error)
return text
.replaceAll(/\s/g, " ")
.replaceAll(/((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}/g, "");
}
function createThreadBar(title, content) {
const container = document.createElement("div");
container.classList.add("LZTSummarizeThreadBar");
const titleEl = document.createElement("h2");
titleEl.classList.add("LZTSummarizeThreadBarTitle");
titleEl.innerHTML = title;
container.appendChild(titleEl);
const contentEl = document.createElement("p");
contentEl.classList.add("LZTSummarizeThreadBarContent", "muted");
contentEl.innerHTML = content;
container.appendChild(contentEl);
return {
container,
title: titleEl,
content: contentEl,
};
}
async function summarizeThreadBlock() {
let threadContent = getThreadContent();
const summarizeBlock = createThreadBar(
SUMMARIZE_TITLE,
"Получение данных..."
);
const pageNavLinkGroup = document.querySelector(".pageNavLinkGroup");
pageNavLinkGroup.before(summarizeBlock.container);
if (threadContent == undefined) {
// getting content about a topic if not 1 page is open
const threadId =
Number(window.location.pathname.match(/^\/threads\/([^d]+)\//)?.[1]) ||
undefined;
threadContent = await getThreadContentByAjax(threadId);
}
if (!(threadContent?.length >= 300)) {
summarizeBlock.title.innerHTML = `${SUMMARIZE_TITLE} (Ошибка валидации)`;
summarizeBlock.content.innerText =
"Не удалось выполнить суммаризацию темы. Содержимое темы не найдено или содержит менее 300 символов.";
return false;
}
let summarizeInterval;
let sessionId = "";
threadContent = clearSummarizeContent(threadContent);
summarizeInterval = setInterval(async () => {
const generatedInfo = await genSummarize(threadContent, sessionId);
console.debug("[LZT Summarize] Summarize Generated Info", generatedInfo);
if (!generatedInfo) {
console.error("[LZT Summarize] Clear summarize interval (ext error)");
clearInterval(summarizeInterval);
summarizeBlock.title.innerHTML = `${SUMMARIZE_TITLE} (Внутренняя ошибка)`;
summarizeBlock.content.innerText =
"Не удалось выполнить суммаризацию темы. Произошла внутренняя ошибка при запросе к Summarize API. Для детальной информации смотри консоль.";
return false;
}
sessionId = generatedInfo.session_id;
const result = checkSummarizeCode(generatedInfo);
if (result.status !== SummarizeStatus.Waiting) {
clearInterval(summarizeInterval);
}
const contentEl = document.createElement("ul");
if (result.desc.length > 1) {
contentEl.classList.add("LZTSummarizeThesises");
}
for (const thesis of result.desc) {
const thesisEl = document.createElement("li");
thesisEl.innerText = thesis.content;
contentEl.appendChild(thesisEl);
}
summarizeBlock.title.innerHTML = `${SUMMARIZE_TITLE} (${result.title})`;
summarizeBlock.content.innerHTML = contentEl.outerHTML;
}, 500);
return true;
}
summarizeThreadBlock();
})();