X.com Timeline Auto-Load with Uninterrupted Reading

Automatically loads new posts on X.com while keeping the reading position intact. Sets a virtual marker at the last visible handler (e.g., @username) before loading new posts and restores the view to this marker.

目前为 2024-11-18 提交的版本。查看 最新版本

// ==UserScript==
// @namespace          http://tampermonkey.net/
// @version            2024.12.18
// @name               X.com Timeline Auto-Load with Uninterrupted Reading
// @name:de            X.com Timeline Auto-Load mit unterbrechungsfreiem Lesen
// @name:fr            X.com Timeline Auto-Load avec lecture ininterrompue
// @name:es            Carga automática de la línea de tiempo de X.com con lectura sin interrupciones
// @name:it            Caricamento automatico della timeline di X.com con lettura ininterrotta
// @name:zh            X.com 时间线自动加载,无缝阅读
// @name:ja            X.com タイムライン自動読み込みと中断のない読書
// @description        Automatically loads new posts on X.com while keeping the reading position intact. Sets a virtual marker at the last visible handler (e.g., @username) before loading new posts and restores the view to this marker.
// @description:de     Lädt automatisch neue Beiträge auf X.com, ohne die Leseposition zu verlieren. Setzt eine virtuelle Markierung am letzten sichtbaren Handler (z. B. @Benutzername) vor dem Laden neuer Beiträge und stellt die Ansicht zu dieser Markierung wieder her.
// @description:fr     Charge automatiquement les nouveaux messages sur X.com tout en conservant la position de lecture. Place un marqueur virtuel au dernier handle visible (par exemple, @nomutilisateur) avant de charger les nouveaux messages et restaure la vue à ce marqueur.
// @description:es     Carga automáticamente nuevos posts en X.com mientras mantiene la posición de lectura intacta. Coloca un marcador virtual en el último manejador visible (por ejemplo, @nombredeusuario) antes de cargar nuevos posts y restaura la vista a ese marcador.
// @description:it     Carica automaticamente nuovi post su X.com mantenendo intatta la posizione di lettura. Imposta un segnalibro virtuale sull'ultimo handle visibile (es. @nomeutente) prima di caricare nuovi post e ripristina la vista su quel segnalibro.
// @description:zh     在X.com上自动加载新帖子,同时保持阅读位置不变。在加载新帖子之前,在最后一个可见的处理器(例如@用户名)处设置一个虚拟标记,并将视图恢复到该标记。
// @description:ja     X.comで新しい投稿を自動的に読み込み、読書位置をそのまま保持します。新しい投稿を読み込む前に、最後に見えるハンドル(例:@ユーザー名)に仮想マーカーを設定し、このマーカーにビューを復元します。
// @icon               https://cdn-icons-png.flaticon.com/128/14417/14417460.png
// @author             Copiis
// @match              https://x.com/*
// @grant              GM_setValue
// @grant              GM_getValue
// @grant              GM_registerMenuCommand
// @license            MIT
// @contributionURL    https://paypal.me/Coopiis?country.x=DE&locale.x=de_DE
// @contributionAmount $5
// ==/UserScript==

(function () {
    'use strict';

    let markerId = "last-visible-handler-marker";

    // Funktion: Markierung beim letzten sichtbaren Handler setzen
    function setMarker() {
        const handlers = Array.from(document.querySelectorAll('span')).filter(
            (span) => span.textContent.startsWith("@")
        );

        if (handlers.length > 0) {
            const lastHandler = handlers[handlers.length - 1]; // Letzter sichtbarer Handler

            // Existierende Markierung entfernen
            removeMarker();

            // Markierung erstellen
            const marker = document.createElement('div');
            marker.id = markerId;

            const rect = lastHandler.getBoundingClientRect();
            const markerTop = window.scrollY + rect.bottom; // Unterhalb des letzten Handlers

            marker.style.position = 'absolute';
            marker.style.top = `${markerTop}px`;
            marker.style.width = '1px';
            marker.style.height = '1px';
            marker.style.backgroundColor = 'transparent'; // Unsichtbar
            marker.style.zIndex = '-1';
            document.body.appendChild(marker);

            console.log(`Markierung gesetzt bei Y-Position: ${markerTop}`);
        } else {
            console.warn("Kein sichtbarer Handler gefunden, Markierung konnte nicht gesetzt werden.");
        }
    }

    // Funktion: Markierung entfernen
    function removeMarker() {
        const existingMarker = document.getElementById(markerId);
        if (existingMarker) {
            existingMarker.remove();
            console.log("Markierung entfernt.");
        }
    }

    // Funktion: Zur Markierung scrollen
    function scrollToMarker() {
        const marker = document.getElementById(markerId);
        if (marker) {
            const markerTop = parseInt(marker.style.top, 10); // Y-Position der Markierung
            window.scrollTo({
                top: markerTop,
                behavior: 'smooth' // Sanft scrollen
            });

            // Verifiziere das Scrollen
            setTimeout(() => {
                if (Math.abs(window.scrollY - markerTop) <= 5) {
                    console.log("Erfolgreich zur Markierung gescrollt:", markerTop);
                } else {
                    console.warn(
                        `Scrollen zur Markierung ungenau. Erwartet: ${markerTop}, Tatsächlich: ${window.scrollY}`
                    );
                }
            }, 500); // Warte kurz, um die Scrollposition zu überprüfen

            removeMarker(); // Markierung nach Verwendung löschen
        } else {
            console.warn("Keine Markierung gefunden, konnte nicht scrollen.");
        }
    }

    // Funktion: Klick auf die "Neue Beiträge anzeigen"-Schaltfläche
    function clickNewPostsButton() {
        const button = Array.from(document.querySelectorAll('span')).find(
            (span) => span.textContent.includes("neue Posts anzeigen") || span.textContent.includes("Post anzeigen")
        );

        if (button) {
            const parentButton = button.closest('button');
            if (parentButton) {
                console.log(`Schaltfläche "${button.textContent}" gefunden, wird geklickt...`);
                setMarker(); // Markierung setzen vor dem Laden neuer Beiträge
                parentButton.click();

                // Starte Scrollen nach einer kurzen Verzögerung
                setTimeout(scrollToMarker, 1000);
            } else {
                console.warn("Elternelement der Schaltfläche nicht gefunden.");
            }
        } else {
            console.warn("Keine Schaltfläche für neue Beiträge gefunden.");
        }
    }

    // Funktion: DOM-Änderungen überwachen
    function observeNewPostsButton() {
        const targetNode = document.body;
        const config = { childList: true, subtree: true };

        const callback = function (mutationsList) {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    clickNewPostsButton(); // Versuche die Schaltfläche zu klicken
                }
            }
        };

        const observer = new MutationObserver(callback);
        observer.observe(targetNode, config);

        console.log("MutationObserver gestartet, um die Schaltfläche zu überwachen.");
    }

    // Initialisieren
    function init() {
        console.log("Skript zur Überprüfung neuer Beiträge aktiviert...");
        observeNewPostsButton();
    }

    init();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址