Tellonym.me Guest

Load tellonym.me Tells without Login

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name            Tellonym.me Guest
// @name:de         Tellonym.me Gast
// @version         1.1.0
// @description     Load tellonym.me Tells without Login
// @description:de  Lade tellonym.me Tells ohne Anmeldung
// @icon            https://www2.tellonym.me/assets/img/icon64x64.png
// @author          TalkLounge (https://github.com/TalkLounge)
// @namespace       https://github.com/TalkLounge/tellonym.me-guest
// @supportURL      https://github.com/TalkLounge/tellonym.me-guest/issues
// @license         MIT
// @match           https://tellonym.me/*
// @require         https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js
// @require         https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js
// @grant           none
// ==/UserScript==

/*
Text Examples:

Context, Comments & Sender: https://tellonym.me/avgx.wvmx/answer/4468890875
Image: https://tellonym.me/avgx.wvmx/answer/4196788015
*/

(function () {
    'use strict';
    let initInterval, ul, user, pos, scrollLoading, initTimeout, scrollEnded, url;

    async function loadTells() {
        let data = await axios.get(`https://api.tellonym.me/profiles/name/${user}?limit=25&pos=${pos}`);
        data = data.data;
        const answers = data.answers;

        if (!answers.length) {
            scrollEnded = true;
            return;
        }

        for (let i = 0; i < answers.length; i++) {
            if (answers[i].type == "AD") { // Do not display ads
                continue;
            }

            console.log("[Tellonym.me Guest]", answers[i]);

            pos++;
            ul.insertAdjacentHTML("beforeend", `<div style="background-color: white; padding: 16px; border-radius: 8px; margin-bottom: 8px" id="${answers[i].id}">
                <a style="float: right; text-decoration: none; color: black" href="https://tellonym.me/${user}/answer/${answers[i].id}" target="_blank">
                    <i class="icon-share"></i>
                </a>
                <div style="display: flex; align-items: center">
                    <div>
                        <img style="height: 38px; border-radius: 8px" src="https://userimg.tellonym.me/xs-v2/${data.avatarFileName}">
                    </div>
                    <div style="margin-left: 12px">
                        <span style="font-weight: bold; font-size: 14px">${user}</span>
                        ${(() => { // Verified
                    if (data.isVerified) {
                        return `<img style="filter: invert(39%) sepia(88%) saturate(1949%) hue-rotate(191deg) brightness(100%) contrast(105%); height: 12px" src="https://www2.tellonym.me/assets/img/verified.png">`;
                    }

                    return "";
                })()}
                        <br>
                        <span style="color: grey; font-size: 12px">${luxon.DateTime.fromISO(answers[i].createdAt).toRelative()}</span>
                    </div>
                </div>
                ${(() => { // Context
                    if (answers[i].parent) {
                        return `<div style="margin-top: 12px" class="context">
                        <a style="background-color: rgb(243, 243, 243); border-radius: 10px; padding: 2px 10px; font-size: 12px; text-decoration: none; color: black; display: block; max-width: 150px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; width: min-content" href="https://tellonym.me/${user}/answer/${answers[i].parent.id}" target="_blank">${answers[i].parent.content}</a>
                    </div>`;
                    }

                    return "";
                })()}
                <div style="border-left: 3px solid rgb(136, 137, 143); margin-top: 12px">
                    <div style="margin-left: 12px; display: flex">
                        ${(() => { // Sender
                    if (answers[i].sender?.username) {
                        return `<a style="text-decoration: none; color: black; margin-top: 1px" href="https://tellonym.me/${answers[i].sender.username}" target="_blank">
                                <div style="display: inline-block">
                                    <img style="height: 16px; border-radius: 4px; margin-right: 4px" src="https://userimg.tellonym.me/xs-v2/${answers[i].sender.avatarFileName}">
                                </div>
                                <span style="font-weight: bold; font-size: 14px; margin-right: 4px; vertical-align: top">${answers[i].sender.username}</span>
                            </a>`;
                    }

                    return "";
                })()}
                        <span>${answers[i].tell}</span>
                    </div>
                </div>
                <div style="margin-top: 12px">
                    <span>${answers[i].answer}</span>
                </div>
                ${(() => { // Media
                    let inject = "";

                    for (let j = 0; j < answers[i].media.length; j++) {
                        if (answers[i].media[j].type == 0) {
                            inject += `<div style="margin-top: 12px">
                            <a href="${answers[i].media[j].url}" target="_blank">
                                <img src="${answers[i].media[j].thumbUrl}">
                            </a>
                        </div>`;
                        }

                        if (answers[i].media[j].type != 0 || !answers[i].media[j].url.endsWith(".jpg")) {
                            alert("[Tellonym.me Guest Userscript]\n\nCongratulations, you have found a tell with media files that the userscript doesn't currently support.\nWith your help I can implement this in the userscript.\nTherefore I kindly ask you to report this URL\n\nhttps://tellonym.me/${user}/answer/${answers[i].id}\n\nto one of these:\n\nhttps://github.com/TalkLounge/tellonym.me-guest/issues\n\nhttps://greasyfork.org/de/scripts/438008-tellonym-me-guest/feedback\n\nMail to [email protected]\n\n\nThank you so much!");
                        }
                    }

                    return inject;
                })()}
                <div style="margin-top: 12px">
                    <div style="width: 32px; display: inline-block">
                        <img style="height: 22px" src="https://www2.tellonym.me/assets/img/reactions/heart_unfilled.png">
                    </div>
                    <div style="width: 32px; display: inline-block">
                        <img style="height: 22px" src="https://www2.tellonym.me/assets/img/reactions/crying_unfilled.png">
                    </div>
                    <div style="width: 32px; display: inline-block">
                        <img style="height: 22px" src="https://www2.tellonym.me/assets/img/reactions/laugh_unfilled.png">
                    </div>
                </div>
                ${(() => { // Comments
                    let comments = "";

                    if (answers[i].comments?.previews?.length) {
                        for (let j = 0; j < answers[i].comments.previews.length; j++) {
                            comments += `<div style="margin-top: 12px; display: flex; align-items: center">
                            <a style="text-decoration: none; color: black; display: flex; margin-top: 1px" href="https://tellonym.me/${answers[i].comments.previews[j].user.username}" target="_blank">
                                <div style="height: 22px">
                                    <img style="height: 22px; border-radius: 4px; margin-right: 8px" src="https://userimg.tellonym.me/xs-v2/${answers[i].comments.previews[j].user.avatarFileName}">
                                </div>
                                <span style="font-weight: bold; font-size: 14px; align-self: center">${answers[i].comments.previews[j].user.username}</span>
                            </a>
                            <span style="margin-left: 4px">${answers[i].comments.previews[j].content}</span>
                        </div>`;
                        }
                    }

                    return comments;
                })()}
            </div>`);

            [...document.querySelectorAll(`.context a[href^="https://tellonym.me/${user}/answer/${answers[i].id}"]`)].forEach(item => { item.href = `#${answers[i].id}`; item.target = ""; }); // Skip to context instead of opening, when loaded already

            if (answers[i].likesCount || answers[i].likes?.count) {
                alert(`[Tellonym.me Guest Userscript]\n\nCongratulations, you have found a tell with likes that the userscript doesn't currently support.\nWith your help I can implement this in the userscript.\nTherefore I kindly ask you to report this URL\n\nhttps://tellonym.me/${user}/answer/${answers[i].id}\n\nto one of these:\n\nhttps://github.com/TalkLounge/tellonym.me-guest/issues\n\nhttps://greasyfork.org/de/scripts/438008-tellonym-me-guest/feedback\n\nMail to [email protected]\n\n\nThank you so much!`);
            }
        }
    }

    async function onScroll() { // Load new tells, if near page end
        const last10 = ul.childNodes[ul.childNodes.length - 10]; // 10th last child
        if (last10.getBoundingClientRect().top <= document.body.clientHeight && !scrollLoading && !scrollEnded) {
            scrollLoading = true;

            await loadTells();

            scrollLoading = undefined;
        }
    }

    async function init() {
        ul = [...document.querySelectorAll("img[src^='https://user']")].reverse()[0]; // Last custom profile picture in tell
        ul = ul || [...document.querySelectorAll("svg[height='38']")].reverse()[0]?.parentNode; // Last generic profile picture in tell

        if (!ul) {
            initTimeout++;

            if (initTimeout >= 20) { // Timeout after 5 seconds (4 per second * 5 = 20)
                console.log("[Tellonym.me Guest]", "Page Timeout");
                window.clearInterval(initInterval);
            }

            return;
        }

        window.clearInterval(initInterval);

        ul = ul.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;
        console.log(ul);

        await new Promise(r => setTimeout(r, 250)); // Thanks to https://stackoverflow.com/a/39914235
        [...ul.childNodes].splice(1).forEach(item => item.remove()); // Remove initial loaded tells

        user = window.location.pathname.split("/")[1];

        await loadTells();

        window.addEventListener("scroll", onScroll);

        for (let i = 0; i < 20; i++) {
            document.querySelector("img[src*=appstore]")?.parentNode.parentNode.parentNode.parentNode.parentNode.remove(); // Remove Appstore Banner
            await new Promise(r => setTimeout(r, 500));
        }
    }

    function checkNavigate() {
        if (url == window.location.origin + window.location.pathname) { // Not navigated
            return;
        }

        url = window.location.origin + window.location.pathname;

        if (["/search", "/login"].includes(window.location.pathname)) { // Not a user profile
            return;
        }

        // Reset variables
        pos = 0;
        scrollLoading = undefined;
        initTimeout = 0;
        scrollEnded = undefined;

        initInterval = window.setInterval(init, 250);
    }

    checkNavigate();
    window.setInterval(checkNavigate, 1000);
})();