From 6799ec15676b76a9d17291d2e0c7ab5da3c84e6f Mon Sep 17 00:00:00 2001 From: eins Date: Fri, 23 Jan 2026 14:07:52 +0000 Subject: [PATCH 1/3] fixed issues with the random button and hotkeys --- public/s/js/admin.js | 4 +- public/s/js/f0ck.js | 28 +++++---- public/s/js/theme.js | 19 +++--- src/inc/routes/apiv2/index.mjs | 106 ++++++++++++++++----------------- views/snippets/navbar.html | 4 +- 5 files changed, 85 insertions(+), 76 deletions(-) diff --git a/public/s/js/admin.js b/public/s/js/admin.js index ed2d0f2..2482e40 100644 --- a/public/s/js/admin.js +++ b/public/s/js/admin.js @@ -130,12 +130,12 @@ return false; } renderTags(res.tags); - span.parentElement.removeChild(span); + if (span.parentElement) span.parentElement.removeChild(span); testList.innerText = ""; addtagClick(); } else if (e.key === "Escape") { - span.parentElement.removeChild(span); + if (span.parentElement) span.parentElement.removeChild(span); testList.innerText = ""; } else { diff --git a/public/s/js/f0ck.js b/public/s/js/f0ck.js index b0dbf38..3676fdd 100644 --- a/public/s/js/f0ck.js +++ b/public/s/js/f0ck.js @@ -208,10 +208,10 @@ window.requestAnimFrame = (function () { return; } - const link = e.target.closest('#next, #prev, #random, .id-link, .nav-next, .nav-prev'); + const link = e.target.closest('#next, #prev, #random, #nav-random, .id-link, .nav-next, .nav-prev'); if (link && link.href && link.hostname === window.location.hostname && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) { // Special check for random - if (link.id === 'random') { + if (link.id === 'random' || link.id === 'nav-random') { e.preventDefault(); const nav = document.querySelector("nav.navbar"); if (nav) nav.classList.add("pbwork"); @@ -240,7 +240,10 @@ window.requestAnimFrame = (function () { window.location.href = link.href; } }) - .catch(() => window.location.href = link.href); + .catch((err) => { + console.error("Random fetch failed:", err); + window.location.href = link.href; + }); return; } @@ -261,7 +264,7 @@ window.requestAnimFrame = (function () { "a": clickOnElementBinding("#next"), "ArrowRight": clickOnElementBinding("#prev"), "d": clickOnElementBinding("#prev"), - "r": clickOnElementBinding("#random"), + "r": clickOnElementBinding("#random, #nav-random"), " ": clickOnElementBinding("#f0ck-image") }; document.addEventListener("keydown", e => { @@ -541,10 +544,13 @@ function init() { window.addEventListener('load', init); -document.getElementById('sbtForm').addEventListener('submit', (e) => { - e.preventDefault(); - const input = document.getElementById('sbtInput').value.trim(); - if (input) { - window.location.href = `/tag/${encodeURIComponent(input)}`; - } -}); +const sbtForm = document.getElementById('sbtForm'); +if (sbtForm) { + sbtForm.addEventListener('submit', (e) => { + e.preventDefault(); + const input = document.getElementById('sbtInput').value.trim(); + if (input) { + window.location.href = `/tag/${encodeURIComponent(input)}`; + } + }); +} diff --git a/public/s/js/theme.js b/public/s/js/theme.js index 7cd37b9..318c08f 100644 --- a/public/s/js/theme.js +++ b/public/s/js/theme.js @@ -1,10 +1,10 @@ const Cookie = { get: name => { const c = document.cookie.match(`(?:(?:^|.*; *)${name} *= *([^;]*).*$)|^.*$`)[1]; - if(c) return decodeURIComponent(c); + if (c) return decodeURIComponent(c); }, set: (name, value, opts = {}) => { - if(opts.days) { + if (opts.days) { opts['max-age'] = opts.days * 60 * 60 * 24; delete opts.days; } @@ -17,8 +17,11 @@ const Cookie = { (() => { const acttheme = Cookie.get('theme') ?? "w0bm"; const themecontainer = document.querySelector("li#themes > ul.dropdown-menu"); + + if (!themecontainer) return; // Theme menu not present on this page + const themes = [...themecontainer.querySelectorAll("li > a")].map(t => t.innerText.toLowerCase()); - if(acttheme !== document.documentElement.getAttribute("theme") && themes.includes(acttheme)) + if (acttheme !== document.documentElement.getAttribute("theme") && themes.includes(acttheme)) document.documentElement.setAttribute("theme", acttheme); [...themecontainer.querySelectorAll("li > a")].forEach(t => t.addEventListener("click", e => { e.preventDefault(); @@ -30,15 +33,15 @@ const Cookie = { })); document.addEventListener("keydown", e => { - if(e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") + if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return; const acttheme = Cookie.get('theme') ?? "w0bm"; const themes = [...themecontainer.querySelectorAll("li > a")].map(t => t.innerText.toLowerCase()); const k = e.key; - if(k === "t") { + if (k === "t") { e.preventDefault(); let i = themes.indexOf(acttheme); - if(++i >= themes.length) + if (++i >= themes.length) i = 0; document.documentElement.setAttribute("theme", themes[i]); document.querySelector("#themes > a").setAttribute("content", themes[i]); @@ -46,10 +49,10 @@ const Cookie = { } }); - if(tbuttonfull = document.querySelector('svg#a_tfull')) { + if (tbuttonfull = document.querySelector('svg#a_tfull')) { tbuttonfull.addEventListener('click', e => { let f = Cookie.get('fullscreen'); - if(f == 1) { + if (f == 1) { Cookie.set('fullscreen', 0); document.querySelector('html').setAttribute('res', ''); tbuttonfull.innerHTML = ``; diff --git a/src/inc/routes/apiv2/index.mjs b/src/inc/routes/apiv2/index.mjs index 7fec014..539357b 100644 --- a/src/inc/routes/apiv2/index.mjs +++ b/src/inc/routes/apiv2/index.mjs @@ -3,7 +3,7 @@ import db from '../../sql.mjs'; import lib from '../../lib.mjs'; import search from '../../routeinc/search.mjs'; -const allowedMimes = [ "audio", "image", "video", "%" ]; +const allowedMimes = ["audio", "image", "video", "%"]; export default router => { router.group(/^\/api\/v2/, group => { group.get(/$/, (req, res) => { @@ -13,24 +13,28 @@ export default router => { group.get(/\/random(\/user\/.+|\/image|\/video|\/audio)?$/, async (req, res) => { const user = req.url.split[3] === "user" ? req.url.split[4] : "%"; const mime = (allowedMimes.filter(n => req.url.split[3]?.startsWith(n))[0] ? req.url.split[3] : "") + "%"; - + const tag = req.url.qs.tag || null; + const rows = await db` - select * + select "items".* from "items" + left join tags_assign on tags_assign.item_id = items.id + left join tags on tags.id = tags_assign.tag_id where mime ilike ${mime} and username ilike ${user} and active = 'true' + ${tag ? db`and tags.normalized ilike ${'%' + tag + '%'}` : db``} order by random() limit 1 `; - + return res.json({ success: rows.length > 0, items: rows.length > 0 ? rows[0] : [] }); }); - + group.get(/\/items\/get/, async (req, res) => { let eps = 150; @@ -51,17 +55,15 @@ export default router => { where ${db.unsafe(modequery)} and active = 'true' - ${ - opt.older - ? db`and id <= ${opt.older}` - : opt.newer - ? db`and id >= ${opt.newer}` - : db`` - } - order by id ${ - opt.newer - ? db`asc` - : db`desc` + ${opt.older + ? db`and id <= ${opt.older}` + : opt.newer + ? db`and id >= ${opt.newer}` + : db`` + } + order by id ${opt.newer + ? db`asc` + : db`desc` } limit ${eps} `).sort((a, b) => b.id - a.id); @@ -73,10 +75,10 @@ export default router => { items: rows }, 200); }); - + group.get(/\/item\/[0-9]+$/, async (req, res) => { const id = +req.url.split[3]; - + const item = await db` select * from "items" @@ -97,14 +99,14 @@ export default router => { order by id desc limit 1 `; - - if(item.length === 0) { + + if (item.length === 0) { return res.json({ success: false, msg: 'no items found' }); } - + const rows = { ...item[0], ...{ @@ -118,11 +120,11 @@ export default router => { rows }); }); - + group.get(/\/user\/.*(\/\d+)?$/, async (req, res) => { const user = req.url.split[3]; const eps = +req.url.split[4] || 50; - + const rows = db` select id, mime, size, src, stamp, userchannel, username, usernetwork from "items" @@ -130,7 +132,7 @@ export default router => { order by stamp desc limit ${+eps} `; - + return res.json({ success: rows.length > 0, items: rows.length > 0 ? rows : [] @@ -140,7 +142,7 @@ export default router => { // tags lol group.put(/\/admin\/tags\/(?.*)/, lib.loggedin, async (req, res) => { - if(!req.params.tagname || !req.post.newtag) { + if (!req.params.tagname || !req.post.newtag) { return res.json({ success: false, msg: 'missing tagname or newtag', @@ -154,7 +156,7 @@ export default router => { const tagname = decodeURIComponent(req.params.tagname); const newtag = req.post.newtag; - if(['sfw', 'nsfw'].includes(tagname) || ['sfw', 'nsfw'].includes(newtag)) { + if (['sfw', 'nsfw'].includes(tagname) || ['sfw', 'nsfw'].includes(newtag)) { return res.json({ msg: 'f0ck you' }, 405); // method not allowed @@ -166,8 +168,8 @@ export default router => { where tag = ${tagname} limit 1 `)[0]; - - if(!tmptag) { + + if (!tmptag) { return res.json({ success: false, msg: 'no tag found' @@ -175,10 +177,9 @@ export default router => { } const q = (await db` - update "tags" set ${ - db({ - tag: newtag - }, 'tag') + update "tags" set ${db({ + tag: newtag + }, 'tag') } where tag = ${tagname} returning * @@ -195,7 +196,7 @@ export default router => { const searchString = req.url.qs.q; - if(searchString?.length <= 1) { + if (searchString?.length <= 1) { reply.error = 'too short lol'; return res.json(reply); } @@ -212,7 +213,7 @@ export default router => { `; reply.success = true; reply.suggestions = search(q, searchString); - } catch(err) { + } catch (err) { reply.error = err.msg; } @@ -220,7 +221,7 @@ export default router => { }); group.post(/\/admin\/deletepost$/, lib.auth, async (req, res) => { - if(!req.post.postid) { + if (!req.post.postid) { return res.json({ success: false, msg: 'no postid' @@ -228,7 +229,7 @@ export default router => { } const id = +req.post.postid; - if(id <= 1) { + if (id <= 1) { return res.json({ success: false }); @@ -243,7 +244,7 @@ export default router => { limit 1 `; - if(f0ck.length === 0) { + if (f0ck.length === 0) { return res.json({ success: false, msg: `f0ck ${id}: f0ck not found` @@ -251,15 +252,15 @@ export default router => { } await db`update "items" set active = 'false' where id = ${id}`; - - await fs.copyFile(`./public/b/${f0ck[0].dest}`, `./deleted/b/${f0ck[0].dest}`).catch(_=>{}); - await fs.copyFile(`./public/t/${id}.webp`, `./deleted/t/${id}.webp`).catch(_=>{}); - await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(_=>{}); - await fs.unlink(`./public/t/${id}.webp`).catch(_=>{}); - if(f0ck[0].mime.startsWith('audio')) { - await fs.copyFile(`./public/ca/${id}.webp`, `./deleted/ca/${id}.webp`).catch(_=>{}); - await fs.unlink(`./public/ca/${id}.webp`).catch(_=>{}); + await fs.copyFile(`./public/b/${f0ck[0].dest}`, `./deleted/b/${f0ck[0].dest}`).catch(_ => { }); + await fs.copyFile(`./public/t/${id}.webp`, `./deleted/t/${id}.webp`).catch(_ => { }); + await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(_ => { }); + await fs.unlink(`./public/t/${id}.webp`).catch(_ => { }); + + if (f0ck[0].mime.startsWith('audio')) { + await fs.copyFile(`./public/ca/${id}.webp`, `./deleted/ca/${id}.webp`).catch(_ => { }); + await fs.unlink(`./public/ca/${id}.webp`).catch(_ => { }); } res.json({ @@ -269,14 +270,14 @@ export default router => { group.post(/\/admin\/togglefav$/, lib.loggedin, async (req, res) => { const postid = +req.post.postid; - + let favs = await db` select user_id from "favorites" where item_id = ${+postid} `; - if(Object.values(favs).filter(u => u.user_id === req.session.id)[0]) { + if (Object.values(favs).filter(u => u.user_id === req.session.id)[0]) { // del fav await db` delete from "favorites" @@ -287,11 +288,10 @@ export default router => { else { // add fav await db` - insert into "favorites" ${ - db({ - item_id: +postid, - user_id: +req.session.id - }, 'item_id', 'user_id') + insert into "favorites" ${db({ + item_id: +postid, + user_id: +req.session.id + }, 'item_id', 'user_id') } `; } @@ -310,7 +310,7 @@ export default router => { favs }); }); - + }); return router; diff --git a/views/snippets/navbar.html b/views/snippets/navbar.html index cdbf1a9..710db54 100644 --- a/views/snippets/navbar.html +++ b/views/snippets/navbar.html @@ -8,7 +8,7 @@ tags about @if(!/^\/\d$/.test(url.pathname)) - rand + rand @endif @@ -33,7 +33,7 @@ tags about @if(!/^\/\d$/.test(url.pathname)) - rand + rand @endif From c74e5a7402b0e04c021c09177d3e888d3882f361 Mon Sep 17 00:00:00 2001 From: eins Date: Fri, 23 Jan 2026 14:39:42 +0000 Subject: [PATCH 2/3] fixed scrolling in overview --- .gitignore | 1 + public/s/js/f0ck.js | 11 +++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 7101b15..78e5869 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ deleted/b deleted/ca deleted/t tmp/* +tools \ No newline at end of file diff --git a/public/s/js/f0ck.js b/public/s/js/f0ck.js index 3676fdd..c3af6a2 100644 --- a/public/s/js/f0ck.js +++ b/public/s/js/f0ck.js @@ -187,13 +187,12 @@ window.requestAnimFrame = (function () { }; const changePage = (e, pbwork = true) => { - if (e.tagName === 'A') { - e.preventDefault(); - loadItemAjax(e.href); - } else { - pbwork && document.querySelector("nav.navbar").classList.add("pbwork"); - !tt && (tt = setTimeout(() => e.click(), stimeout)); + if (pbwork) { + const nav = document.querySelector("nav.navbar"); + if (nav) nav.classList.add("pbwork"); } + // Trigger native click for navigation + e.click(); }; // Intercept clicks From 45f9345e9c86d3337e7a828ad6fa35d314eeaa01 Mon Sep 17 00:00:00 2001 From: eins Date: Fri, 23 Jan 2026 14:46:39 +0000 Subject: [PATCH 3/3] fix r key on tag overview --- public/s/js/f0ck.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/public/s/js/f0ck.js b/public/s/js/f0ck.js index c3af6a2..8deb7b2 100644 --- a/public/s/js/f0ck.js +++ b/public/s/js/f0ck.js @@ -140,7 +140,7 @@ window.requestAnimFrame = (function () { html = rawText; } - let container = document.querySelector('.container'); + let container = document.querySelector('#main .container'); if (!container && document.querySelector('.index-container')) { // Transition from Index to Item View @@ -148,13 +148,19 @@ window.requestAnimFrame = (function () { main.innerHTML = '
'; container = main.querySelector('.container'); } else if (container) { - // Already in Item View, clear usage - const oldContent = container.querySelector('.content'); - const oldMetadata = container.querySelector('.metadata'); - const oldHeader = container.querySelector('._204863'); - if (oldHeader) oldHeader.remove(); - if (oldContent) oldContent.remove(); - if (oldMetadata) oldMetadata.remove(); + // Check if we are on Tags Overview logic (which reuses .container) + const tagsOverview = container.querySelector('.tags'); + if (tagsOverview) { + container.innerHTML = ''; + } else { + // Already in Item View, clear usage + const oldContent = container.querySelector('.content'); + const oldMetadata = container.querySelector('.metadata'); + const oldHeader = container.querySelector('._204863'); + if (oldHeader) oldHeader.remove(); + if (oldContent) oldContent.remove(); + if (oldMetadata) oldMetadata.remove(); + } } container.insertAdjacentHTML('beforeend', html);