import db from "../sql.mjs"; import lib from "../lib.mjs"; import cfg from "../config.mjs"; import fs from "fs"; import url from "url"; const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or '); export default { getf0cks: async (o = { user, tag, mime, page, mode, fav, session }) => { const user = o.user ? decodeURI(o.user) : null; const tag = lib.parseTag(o.tag ?? null); const mime = o.mime ?? null; const page = +(o.page ?? 1); const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%"; const tmp = { user, tag, mime, smime, page, mode: o.mode }; const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0); const total = (await db` select distinct on (items.id) count(items.id) as total from items left join tags_assign on tags_assign.item_id = items.id left join tags on tags.id = tags_assign.tag_id left join favorites on favorites.item_id = items.id left join "user" on "user".id = favorites.user_id where ${ db.unsafe(modequery) } ${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` } ${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` } ${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` } ${ mime ? db`and items.mime ilike ${smime}` : db`` } ${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` } group by items.id, tags.tag `)?.length || 0; if(!total || total === 0) { return { success: false, message: "404 - no f0cks given" }; } const pages = +Math.ceil(total / cfg.websrv.eps); const act_page = Math.min(pages, page || 1); const offset = Math.max(0, (act_page - 1) * cfg.websrv.eps); const rows = await db` select distinct on (items.id) items.id, items.mime, tags.tag, ta.tag_id from items left join tags_assign on tags_assign.item_id = items.id left join tags on tags.id = tags_assign.tag_id left join favorites on favorites.item_id = items.id left join "user" on "user".id = favorites.user_id left join tags_assign ta on ta.item_id = items.id and (ta.tag_id = 1 or ta.tag_id = 2) where ${ db.unsafe(modequery) } ${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` } ${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` } ${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` } ${ mime ? db`and items.mime ilike ${smime}` : db`` } ${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` } group by items.id, tags.tag, ta.tag_id order by items.id desc offset ${offset} limit ${cfg.websrv.eps} `; const cheat = []; for(let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++) cheat.push(i); const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks', path: 'p/' }); return { success: true, items: rows, pagination: { start: 1, end: pages, prev: (act_page > 1) ? act_page - 1 : null, next: (act_page < pages) ? act_page + 1 : null, page: act_page, cheat: cheat }, link, tmp }; }, getf0ck: async (o = ({ user, tag, mime, itemid, mode, session })) => { const user = o.user ? decodeURI(o.user) : null; const tag = lib.parseTag(o.tag ?? null); const mime = (o.mime ?? ""); const itemid = +(o.itemid ?? 404); const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%"; const tmp = { user, tag, mime, smime, itemid }; const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0); if(itemid === 404) { return { success: false, message: "404 - f0ck not found" }; } const items = await db` select distinct on (items.id) items.* from items left join tags_assign on tags_assign.item_id = items.id left join tags on tags.id = tags_assign.tag_id left join favorites on favorites.item_id = items.id left join "user" on "user".id = favorites.user_id left join tags_assign ta on ta.item_id = items.id and (ta.tag_id = 1 or ta.tag_id = 2) where ${ db.unsafe(modequery) } ${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` } ${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` } ${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` } ${ mime ? db`and items.mime ilike ${smime}` : db`` } ${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` } group by items.id, tags.tag, ta.tag_id order by items.id desc `; const item = items.findIndex(i => i.id === itemid); const actitem = items[item]; if(!actitem) { // sfw-check! return { success: false, message: "Sorry, this post is currently not visible." }; } const tags = await lib.getTags(itemid); const cheat = [...new Set(items.slice(Math.max(0, item - 3), item + 4).map(i => i.id))]; const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks', path: '' }); const favorites = await db` select "user".user, "user_options".avatar from "favorites" left join "user" on "user".id = "favorites".user_id left join "user_options" on "user_options".user_id = "favorites".user_id where "favorites".item_id = ${itemid} `; let coverart = true; try { await fs.promises.access(`./public${cfg.websrv.paths.coverarts}/${actitem.id}.webp`); } catch(err) { coverart = false; } const data = { success: true, user: { name: actitem.username, channel: actitem.usernetwork == "Telegram" && actitem.userchannel !== "f0ck.me" ? "anonymous" : actitem.userchannel, network: actitem.usernetwork }, item: { id: actitem.id, src: { long: actitem.src, short: url.parse(actitem.src).hostname, }, thumbnail: `${cfg.websrv.paths.thumbnails}/${actitem.id}.png`, coverart: coverart ? `${cfg.websrv.paths.coverarts}/${actitem.id}.webp` : '/s/img/music.webp', dest: `${cfg.websrv.paths.images}/${actitem.dest}`, mime: actitem.mime, size: lib.formatSize(actitem.size), timestamp: { timeago: lib.timeAgo(new Date(actitem.stamp * 1e3).toISOString()), timefull: new Date(actitem.stamp * 1e3).toISOString() }, favorites: favorites, tags: tags }, title: `${actitem.id} - f0ck.me`, pagination: { end: items[items.length - 1]?.id, start: items[0]?.id, next: items[item + 1]?.id, prev: items[item - 1]?.id, page: actitem.id, cheat: cheat }, phrase: cfg.websrv.phrases[~~(Math.random() * cfg.websrv.phrases.length)], link, tmp }; return data; }, getRandom: async (o = ({ user, tag, mime, mode, session })) => { const user = o.user ? decodeURI(o.user) : null; const tag = lib.parseTag(o.tag ?? null); const mime = (o.mime ?? ""); const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%"; const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0); const item = await db` select items.id from items left join tags_assign on tags_assign.item_id = items.id left join tags on tags.id = tags_assign.tag_id left join favorites on favorites.item_id = items.id left join "user" on "user".id = favorites.user_id where ${ db.unsafe(modequery) } ${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` } ${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` } ${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` } ${ mime ? db`and items.mime ilike ${smime}` : db`` } ${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` } group by items.id, tags.tag order by random() limit 1 `; if(item.length === 0) { return { success: false, message: "no f0cks found :(" }; } const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks' }); return { success: true, link: link, itemid: item[0].id }; } };