From 82574466eea012abddf1d1c0ebbd0100df39c083 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Sun, 17 May 2026 14:16:13 +0200 Subject: [PATCH] abyss internal link shortening, removal of # for ids and external preview --- public/s/js/comments.js | 9 ++++++- public/s/js/f0ckm.js | 2 +- public/s/js/scroller.js | 20 ++++++++------ public/s/js/sidebar-activity.js | 9 +++++++ src/inc/routes/scroller.mjs | 46 ++++++++++++++++++++++++++++----- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/public/s/js/comments.js b/public/s/js/comments.js index e72aa56..50cd00e 100644 --- a/public/s/js/comments.js +++ b/public/s/js/comments.js @@ -1668,7 +1668,14 @@ class CommentSystem { } ); - // Build regex for allowed media hosters (video/audio) + // Abyss label replacement + md = md.replace( + /]*href="(?:https?:\/\/[^\/]+)?\/abyss(?:#|\/)(\d+)"[^>]*>([\s\S]*?)<\/a>/gi, + (match, abyssId) => { + return ` /abyss/${abyssId}`; + } + ); + const mediaHosts = [escapedSiteHost]; if (window.f0ckAllowedImages && Array.isArray(window.f0ckAllowedImages)) { window.f0ckAllowedImages.forEach(h => { diff --git a/public/s/js/f0ckm.js b/public/s/js/f0ckm.js index c3e26f6..6d1c971 100644 --- a/public/s/js/f0ckm.js +++ b/public/s/js/f0ckm.js @@ -1678,7 +1678,7 @@ window.cancelAnimFrame = (function () { (parts.length >= 3 && (parts[0] === 'tag' || parts[0] === 'user' || parts[0] === 'h') && /^\d+$/.test(parts[parts.length - 1])) ); const isMessages = !!pathname.match(/^\/messages(\/|$)/); - const isAbyss = !!pathname.match(/^\/abyss(\/?$|\?|#)/) || pathname === '/abyss'; + const isAbyss = !!pathname.match(/^\/abyss(\/|$|\?|#)/) || pathname === '/abyss'; const isGrid = !isProfile && !isUserHall && !isUserHalls && !isHall && !isHalls && !isTags && !isComments && !isNotifs && !isItem && !isAdmin && !isMod && !isSettings && !isStatic && !isUpload && !isMessages && !isAbyss; if (isItem) { diff --git a/public/s/js/scroller.js b/public/s/js/scroller.js index cdfcc01..dd3cd91 100644 --- a/public/s/js/scroller.js +++ b/public/s/js/scroller.js @@ -229,28 +229,32 @@ return ago(fmt(y === 1 ? i.ta_year : i.ta_years, y, 'year')); } function hashId() { - // Strip the leading '#' and allow numeric IDs or board/postid format + // Check path first /abyss/1234 + const pathMatch = location.pathname.match(/\/abyss\/(\d+)$/); + if (pathMatch) return pathMatch[1]; + + // Fallback to hash const raw = location.hash.replace(/^#/, '').trim(); if (/^\d+$/.test(raw)) return raw; if (/^[a-z0-9]+\/\d+$/.test(raw)) return raw; return ''; } - let lastPushedHash = location.hash; + let lastPushedUrl = location.pathname + location.hash; function pushHash(id) { if (!id) return; - const newHash = '#' + id; - if (newHash === lastPushedHash) return; - lastPushedHash = newHash; - history.pushState({ scrollerId: id }, '', '/abyss' + newHash); + const newUrl = '/abyss/' + id; + if (newUrl === lastPushedUrl) return; + lastPushedUrl = newUrl; + history.pushState({ scrollerId: id }, '', newUrl); updateCacheActiveId(id); } // Handle back/forward within abyss — scroll to the target slide window.addEventListener('popstate', (e) => { if (!document.body.classList.contains('scroller-active')) return; - const id = e.state?.scrollerId || location.hash.replace('#', ''); + const id = e.state?.scrollerId || hashId(); if (!id) return; - lastPushedHash = '#' + id; + lastPushedUrl = '/abyss/' + id; const slide = feed.querySelector(`.scroll-slide[data-id="${id}"], .scroll-slide[data-local-id="${id}"]`); if (slide) { slide.scrollIntoView({ behavior: 'smooth', block: 'start' }); diff --git a/public/s/js/sidebar-activity.js b/public/s/js/sidebar-activity.js index 8b01c46..f775d7b 100644 --- a/public/s/js/sidebar-activity.js +++ b/public/s/js/sidebar-activity.js @@ -40,6 +40,7 @@ const ytOembedCache = new Map(); // videoId -> meta object const ytOembedPending = new Map(); // videoId -> Promise + const fetchSidebarYoutubeTitles = async (container) => { const links = container.querySelectorAll('.sidebar-video-link[data-yt-id]'); if (links.length === 0) return; @@ -290,6 +291,14 @@ } ); + // Abyss label replacement + md = md.replace( + /]*href="(?:https?:\/\/[^\/]+)?\/abyss(?:#|\/)(\d+)"[^>]*>([\s\S]*?)<\/a>/gi, + (match, abyssId) => { + return ` /abyss/${abyssId}`; + } + ); + // Build regex for allowed media hosters (video/audio) const escapedSiteHost = window.location.host.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const mediaHosts = [escapedSiteHost]; diff --git a/src/inc/routes/scroller.mjs b/src/inc/routes/scroller.mjs index 1ffef6b..d473933 100644 --- a/src/inc/routes/scroller.mjs +++ b/src/inc/routes/scroller.mjs @@ -4,22 +4,56 @@ import lib from "../lib.mjs"; export default (router, tpl) => { // Serve the scroller page - router.get(/^\/abyss\/?$/, async (req, res) => { + router.get(/^\/abyss(?:\/(?[0-9]+))?\/?$/, async (req, res) => { if (cfg.websrv.abyss_enabled === false) return res.reply({ code: 404, body: tpl.render('error', { message: 'Not found', tmp: null }, req) }); if (cfg.websrv.private_society && !req.session) { return res.reply({ code: 502, body: '502 Bad Gateway' }); } + + const id = req.params?.id; + let page_meta = { + title: 'doomscroll', + description: 'Scroll through content endlessly', + url: `https://${cfg.main.url.domain}/abyss` + }; + + if (id) { + try { + const items = await db` + select i.*, uo.display_name + from "items" i + left join users u on u.id = i.author + left join user_options uo on uo.user_id = u.id + where i.id = ${+id} and i.active = true + limit 1 + `; + if (items.length > 0) { + const item = items[0]; + + // Fetch tags to check for NSFW/NSFL + const tags = await db` + select tag_id from tags_assign where item_id = ${+id} + `; + const tagIds = tags.map(t => t.tag_id); + const isBlurred = tagIds.includes(2) || tagIds.includes(cfg.nsfl_tag_id || 3); + + page_meta.title = `${id}`; + page_meta.description = cfg.websrv.description || "The webs dumpster"; + page_meta.url = `https://${cfg.main.url.domain}/abyss/${id}`; + page_meta.image = `https://${cfg.main.url.domain}/t/${id}${isBlurred ? '_blur' : ''}.webp`; + } + } catch (e) { + console.error('[SCROLLER] Failed to fetch meta for ID:', id, e); + } + } + return res.reply({ body: tpl.render('scroller', { tmp: null, session: req.session ? { ...req.session } : false, enable_nsfl: !!cfg.enable_nsfl, enable_swf: !!cfg.websrv.enable_swf, - page_meta: { - title: 'doomscroll', - description: 'Scroll through content endlessly', - url: `https://${cfg.main.url.domain}/abyss` - } + page_meta }, req) }); });