您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hide old comments on Orbitar. donations: https://orbitar.space/u/pazoozoo
// ==UserScript== // @name Hide-Older-Comments // @namespace https://orbitar.space/ // @version 1.8.8 // @description Hide old comments on Orbitar. donations: https://orbitar.space/u/pazoozoo // @match https://*.orbitar.space/* // @match https://*.orbitar.local/* // @grant GM.getValue // @grant GM.setValue // @grant GM_getValue // @grant GM_setValue // @author pazoozoo // @homepageURL https://orbitar.space/u/pazoozoo // @license MIT // ==/UserScript== (function () { 'use strict'; console.log("✅ Comment filtering script is running..."); let observer; // Global observer to allow disconnecting on URL change const SELECTORS = { linksSection: '[class^="PostPage_postButtons__"]', comment: '.comment', commentContent: '[class^="CommentComponent_content__"]', signature: '[class^="SignatureComponent_signature__"]' }; const COLORS = ['gray', 'pink', 'blue', 'skyblue', 'salmon']; const TIME_ADJUSTMENTS = [ { text: "3 часа", adjust: (date) => date.setHours(date.getHours() - 3) }, { text: "12 часов", adjust: (date) => date.setHours(date.getHours() - 12) }, { text: "сутки", adjust: (date) => date.setDate(date.getDate() - 1) }, { text: "3 дня", adjust: (date) => date.setDate(date.getDate() - 3) }, { text: "неделя", adjust: (date) => date.setDate(date.getDate() - 7) } ]; // Default color that will be used if no saved preference exists const DEFAULT_BG_COLOR = 'lightskyblue'; // Will store the actual background color (loaded from GM or default) let parentCommentBgColor; // Function to load the saved color preference async function loadSavedColor() { try { const savedColor = await GM.getValue('parentCommentBgColor', DEFAULT_BG_COLOR); return savedColor || DEFAULT_BG_COLOR; // Fallback if saved color is null/undefined } catch (error) { console.error("Error loading saved color:", error); return DEFAULT_BG_COLOR; } } // Function to save the color preference async function saveColor(color) { try { await GM.setValue('parentCommentBgColor', color); console.log("Color preference saved:", color); } catch (error) { console.error("Error saving color preference:", error); } } // Initialize the color at startup (async function initializeColor() { parentCommentBgColor = await loadSavedColor(); console.log("Using background color:", parentCommentBgColor); })(); function isPostPage() { return /^https:\/\/([^\.]*\.)?orbitar\.space\/(p\d+|s\/[^\/]+\/p\d+)([\?].*|[\#].*)?$/.test(window.location.href); } function observeForLinksSection() { if (observer) { observer.disconnect(); // Disconnect previous observer if it exists } observer = new MutationObserver(() => { let linksSection = document.querySelector(SELECTORS.linksSection); if (linksSection && !document.getElementById("comment-filter-container")) { createUI(linksSection); } }); observer.observe(document.body, { childList: true, subtree: true }); } function createUI(linksSection) { if (document.getElementById("comment-filter-container")) return; let container = document.createElement("span"); container.id = "comment-filter-container"; container.appendChild(document.createTextNode(" • ")); let showFilterLink = createLink("фильтровать по дате", "#fr", (event) => { event.preventDefault(); filterUI.style.display = "inline"; showFilterLink.style.display = "none"; }); let filterUI = document.createElement("span"); filterUI.style.display = "none"; filterUI.style.marginLeft = "10px"; let dateInput = createDateInput("comment-filter-date"); let filterLink = createLink("фильтровать", "#ff", (event) => { event.preventDefault(); filterComments(); }); let clearLink = createLink("очистить", "#fr", (event) => { event.preventDefault(); clearFilter(); }); let quickLinks = document.createElement("div"); quickLinks.style.marginTop = "10px"; TIME_ADJUSTMENTS.forEach(({ text, adjust }, index) => { let timeAdjustLink = createLink(text, "#ft", (event) => { event.preventDefault(); adjustDate(adjust); }); quickLinks.appendChild(timeAdjustLink); if (index < TIME_ADJUSTMENTS.length - 1) quickLinks.appendChild(document.createTextNode(" | ")); }); COLORS.forEach((color, index) => { quickLinks.appendChild(document.createTextNode(" | ")); let colorLink = createLink(color, "#fc", (event) => { event.preventDefault(); changeParentCommentBgColor("light" + color); }); quickLinks.appendChild(colorLink); }); filterUI.appendChild(dateInput); filterUI.appendChild(filterLink); filterUI.appendChild(clearLink); filterUI.appendChild(quickLinks); container.appendChild(showFilterLink); container.appendChild(filterUI); linksSection.appendChild(container); } function createLink(text, href, onClick) { let link = document.createElement("a"); link.href = href; link.innerText = text; link.style.marginRight = "5px"; link.onclick = onClick; return link; } function createDateInput(id) { let input = document.createElement("input"); input.type = "datetime-local"; input.id = id; input.style.marginRight = "5px"; return input; } function changeParentCommentBgColor(color) { parentCommentBgColor = color; // Save the color preference saveColor(color); let comments = document.querySelectorAll(SELECTORS.comment); comments.forEach(comment => { let commentTextContainer = comment.querySelector(SELECTORS.commentContent); if (commentTextContainer && COLORS.map(c => "light" + c).includes(commentTextContainer.style.backgroundColor)) { commentTextContainer.style.backgroundColor = color; } }); } function adjustDate(adjust) { let dateInput = document.getElementById("comment-filter-date"); if (!dateInput) return; let currentDate = new Date(); adjust(currentDate); let localISOTime = new Date(currentDate.getTime() - currentDate.getTimezoneOffset() * 60000) .toISOString() .slice(0, 16); dateInput.value = localISOTime; } function filterComments() { let dateInput = document.getElementById("comment-filter-date"); if (!dateInput) return; let selectedDate = new Date(dateInput.value); if (isNaN(selectedDate)) { console.error("Invalid date selected."); return; } console.log("Filtering comments older than:", selectedDate.toString()); let comments = document.querySelectorAll(SELECTORS.comment); let commentMap = new Map(); comments.forEach(comment => { let dateElement = findDateElement(comment); if (!dateElement) return; let commentDateText = dateElement.innerText.trim(); let commentDate = parseCommentDate(commentDateText); let commentId = comment.dataset.commentId; if (isNaN(commentDate)) return; commentMap.set(commentId, { comment, commentDate, hasNewerChild: false }); }); comments.forEach(comment => { let commentId = comment.dataset.commentId; let commentData = commentMap.get(commentId); if (!commentData) return; let { commentDate } = commentData; let childComments = [...comment.querySelectorAll(SELECTORS.comment)]; let hasNewerChild = childComments.some(child => { let childId = child.dataset.commentId; return commentMap.has(childId) && commentMap.get(childId).commentDate >= selectedDate; }); if (hasNewerChild) { commentData.hasNewerChild = true; } }); comments.forEach(comment => { let commentId = comment.dataset.commentId; let commentData = commentMap.get(commentId); if (!commentData) return; let { commentDate, hasNewerChild } = commentData; let commentTextContainer = comment.querySelector(SELECTORS.commentContent); if (!commentTextContainer) return; if (commentDate >= selectedDate) { comment.style.display = ""; commentTextContainer.style.backgroundColor = ""; } else if (hasNewerChild) { comment.style.display = ""; commentTextContainer.style.padding = "5px"; commentTextContainer.style.backgroundColor = parentCommentBgColor; } else { comment.style.display = "none"; } }); } function clearFilter() { let comments = document.querySelectorAll(SELECTORS.comment); comments.forEach(comment => { comment.style.display = ""; let commentTextContainer = comment.querySelector(SELECTORS.commentContent); if (commentTextContainer) { commentTextContainer.style.backgroundColor = ""; } }); console.log("Filter cleared, all comments visible."); } function findDateElement(comment) { let signature = comment.querySelector(SELECTORS.signature); if (!signature) return null; let dateLinks = signature.querySelectorAll("a"); return dateLinks.length >= 2 ? dateLinks[1] : null; } function parseCommentDate(dateText) { const months = { "января": "January", "февраля": "February", "марта": "March", "апреля": "April", "мая": "May", "июня": "June", "июля": "July", "августа": "August", "сентября": "September", "октября": "October", "ноября": "November", "декабря": "December" }; if (dateText.startsWith("вчера в")) { let match = dateText.match(/вчера в (\d{1,2}):(\d{2})/); if (match) { let yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); yesterday.setHours(parseInt(match[1], 10), parseInt(match[2], 10), 0, 0); return yesterday; } } if (dateText.startsWith("сегодня в")) { let match = dateText.match(/сегодня в (\d{1,2}):(\d{2})/); if (match) { let today = new Date(); today.setHours(parseInt(match[1], 10), parseInt(match[2], 10), 0, 0); return today; } } let oldFormatMatch = dateText.match(/(\d{1,2})\s([а-яА-Я]+)\sв\s(\d{1,2}):(\d{2})/); if (oldFormatMatch) { let [_, day, monthName, hour, minute] = oldFormatMatch; let month = months[monthName]; if (!month) return NaN; let currentYear = new Date().getFullYear(); return new Date(`${day} ${month} ${currentYear} ${hour}:${minute}`); } let newFormatMatch = dateText.match(/(\d{2})\.(\d{2})\.(\d{4})\s(\d{2}):(\d{2})/); if (newFormatMatch) { let [_, day, month, year, hour, minute] = newFormatMatch; return new Date(`${year}-${month}-${day}T${hour}:${minute}:00`); } return NaN; } function runScript() { if (isPostPage()) { let existingContainer = document.getElementById("comment-filter-container"); if (existingContainer) { existingContainer.remove(); } clearFilter(); observeForLinksSection(); } } // Run the script initially if on a post page runScript(); // Listen for URL changes via popstate (back/forward navigation) window.addEventListener('popstate', runScript); // Listen for hash changes if navigation uses URL fragments window.addEventListener('hashchange', runScript); // Override pushState to detect URL changes const originalPushState = history.pushState; history.pushState = function () { originalPushState.apply(this, arguments); runScript(); }; // Override replaceState similarly const originalReplaceState = history.replaceState; history.replaceState = function () { originalReplaceState.apply(this, arguments); runScript(); }; })();