105 Commits

Author SHA1 Message Date
x
5cdb86d710 adding new stuff to the terms page, also privacy policy change 2025-05-29 12:33:41 +02:00
x
02a29bb056 remove hoster ranking 2025-05-10 21:57:33 +02:00
x
0ea54f111d f0ck yt... 2025-05-10 19:14:09 +02:00
x
294c59d30b kekse 2025-05-10 19:08:14 +02:00
x
b9a42f9e8b make f0ck95 great again 2025-05-07 12:01:02 +02:00
x
ce1b1770d2 💩💩 2025-05-07 09:15:11 +02:00
x
de66d95207 gfdgds 2025-05-07 09:13:44 +02:00
x
6376366a0c testing out critical css from kigo 2025-05-07 09:09:40 +02:00
x
cd1f99af48 removing some of the admin functionality for now 2025-05-02 19:14:14 +02:00
x
dcc6eac07a uga aga pipi kaka 2025-05-01 18:20:47 +02:00
x
da5bfd5734 narrowing down one of the errors 2025-05-01 16:22:11 +02:00
x
fe714f0556 uga aga pipi kaka 2025-05-01 15:28:18 +02:00
x
0c96c258ab displaying all tags for logged in users, not applying nsfp list 2025-05-01 14:59:28 +02:00
x
4260a7429a 1 2025-04-30 17:56:52 +02:00
x
61f9422f3f uga aga pipi kaka 2025-04-30 17:50:55 +02:00
x
b876e793b1 0 2025-04-30 17:27:58 +02:00
x
a8b1d156e8 about ... 2025-04-30 17:26:40 +02:00
x
941b99c71b F 2025-04-30 17:08:45 +02:00
x
efe37d3a30 f 2025-04-30 17:07:23 +02:00
x
f437ec8e80 blub 2025-04-30 17:04:28 +02:00
x
809a4e7f60 removing commented out shit 2025-04-29 17:40:01 +02:00
x
f3dccb9747 remove dirty fix for non admin users 2025-04-28 20:27:10 +02:00
7b8d486083 xd 2025-04-28 18:24:31 +00:00
eb16d3b120 Merge pull request 'user/admin blah' (#76) from schrumpel-patch-1 into f0bm
Reviewed-on: #76
2025-04-28 18:15:20 +00:00
4ef66e173f user/admin blah
blah
2025-04-28 18:13:39 +00:00
x
675608c3fd dirty fix for non-admin users clicking on tags 2025-04-27 23:00:46 +02:00
x
52b83dee3a potential fix for favorites in production, let's try 2025-04-27 21:09:07 +02:00
x
e18270a1ce uga aga 2025-04-21 14:48:40 +02:00
x
a3b66567c9 404 2025-04-21 03:52:29 +02:00
x
c46fcd0d9b fdsgfds
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 13s
2025-04-07 10:27:49 +02:00
x
e818e902f4 gjgj
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2025-04-07 10:24:18 +02:00
x
daf8faeb8f ich muss kaken 2025-04-07 09:04:27 +02:00
x
e822f118c6 js in die hose kaka 2025-04-07 09:01:07 +02:00
x
b964a71c7a gugu gaga 2025-04-07 08:48:10 +02:00
x
23a62d3803 grnköegnmerkö 2025-04-07 08:44:27 +02:00
x
ed264661a2 fgnmkfgf
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 29s
2025-04-06 22:38:46 +02:00
x
3e2aa4dca4 cock? 2025-04-06 22:25:15 +02:00
x
891129ec2e remove meta tags from item 2025-04-06 19:59:21 +02:00
x
2863065939 pipi kaka 2025-03-28 14:34:55 +01:00
x
cd88cfe3b1 uga aga 2025-03-28 14:30:40 +01:00
x
161cb76709 bvcxbvcxbcxv 2025-03-28 01:34:12 +01:00
x
8991218271 bcvxbc 2025-03-28 01:33:57 +01:00
x
0b81e584a1 tos 2025-03-28 01:26:39 +01:00
x
0aae17f871 c 2025-03-28 01:12:48 +01:00
x
3ca5b5d598 gjorfjgof 2025-03-28 01:10:37 +01:00
x
c4dfd6b5c6 f 2025-03-22 15:40:00 +01:00
x
e24f3f9e35 adding terms of service 2025-03-22 15:37:42 +01:00
x
ba7ea955c5 h 2025-03-21 21:54:50 +01:00
1d5225c9fe cgfxzhdcutblah 2025-03-21 20:29:50 +00:00
356b8eebf1 blah 2025-03-21 20:27:49 +00:00
f5e2bd4a02 encodeURI 2025-03-21 17:55:42 +00:00
x
9da30ac7d2 a 2025-03-19 20:19:53 +01:00
x
69ca852379 add tag page 2025-03-19 19:49:59 +01:00
x
b29537d6d8 aaaaaaaaaaaaaaaaaaaaa 2025-03-16 07:13:49 +01:00
x
cfddf8a274 gaga 2025-03-16 05:58:17 +01:00
x
7a8362bca6 fff 2025-03-16 05:08:10 +01:00
x
817c9c2966 gfds 2025-03-16 04:30:10 +01:00
x
7078378c05 uga aga pipi kaka 2025-03-16 03:19:29 +01:00
x
76f1a3ddbb f 2025-03-16 03:04:21 +01:00
x
a905b8817e 1 2025-03-13 00:33:53 +01:00
x
ab2ea14891 blah daily commit 2025-03-12 23:36:55 +01:00
x
d33168ca92 add header 2025-03-11 20:39:07 +01:00
x
e3cda9faf4 ggfd
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 13s
2025-03-09 21:59:14 +01:00
x
7d8baa1da3 hthtdf
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2025-03-09 13:56:11 +01:00
x
dacd72ffb3 bbbb
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2025-03-09 12:11:17 +01:00
x
5e735f072d f
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2025-03-09 05:08:40 +01:00
x
32712cf70c h
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 12s
2025-03-09 04:33:00 +01:00
x
d02b304728 g
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2025-03-09 04:14:27 +01:00
x
ad6027ab20 f
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 13s
2025-03-09 03:36:52 +01:00
x
4416867ffe f
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 13s
2025-03-09 03:01:28 +01:00
x
1a033723c8 adding id-link oder so
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 13s
2025-03-09 02:56:37 +01:00
x
a504865a6e changing owner to f0ck
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 35s
2025-03-09 02:19:36 +01:00
x
b6f28fdb58 w0bm_theme
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 12s
2025-03-09 01:40:37 +01:00
7028d92d5e changing convert to magick command because of deprecation
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 17s
2024-07-04 03:08:59 +02:00
c1f06de7c5 fixing p1nk theme nav-bg color
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 17s
2024-07-04 01:56:14 +02:00
ce7f854dd6 wip
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-07-04 01:18:41 +02:00
3b29f5f9d5 .
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 15s
2024-06-30 13:41:09 +02:00
f5225a71c5 settings page bisschen aufgehübscht
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 14s
2024-06-28 22:08:27 +02:00
7098c335bc Merge remote-tracking branch 'origin/master' into dev
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 28s
2024-06-28 21:27:45 +02:00
38c4abae3c blah.
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 29s
2024-06-28 18:33:12 +02:00
6852ac40d1 alias the second
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-06-28 16:17:27 +02:00
4e2cfb8637 revert lol
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 22s
2024-06-28 15:44:47 +02:00
65818c2f40 user aliases
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-06-28 06:31:06 +02:00
e20e9899f9 fix user profiles if no f0cks or favs exist
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 21s
2024-06-28 05:37:05 +02:00
befc8e8e75 fix admin.js 2024-06-28 05:36:25 +02:00
058fe94fd1 admin the second lol
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-06-24 08:41:46 +02:00
c79cca18cf fix total f0cks in profile 2024-06-24 08:41:13 +02:00
2ff1842d09 admin schmadmin
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-06-24 07:53:00 +02:00
486580b21c https://github.com/nodejs/node/pull/52104
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 52s
2024-06-20 04:20:28 +02:00
36fc3326d3 Merge remote-tracking branch 'origin/master' into dev
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-02-21 19:56:56 +01:00
5d91ce7d2b fugg - ytdlp template
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 24s
2024-02-21 16:26:31 +01:00
0c6e806525 fix imgur regex & s lol
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-02-21 12:05:50 +01:00
77d041bb19 blah
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-02-20 21:21:05 +01:00
7844bc8b63 blah
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-02-20 21:06:47 +01:00
705e46f838 debugmeldung entfernen
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-02-20 20:52:20 +01:00
c2e9922ae9 debugmeldung entfernen
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
2024-02-20 20:51:29 +01:00
d0336d8cfb imghure
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-02-20 20:39:11 +01:00
95902023e9 imgur schmimgur
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-02-20 20:37:55 +01:00
2b2fe45be8 imgur schmimgur
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 20s
2024-02-20 17:46:41 +01:00
6f71170da9 Merge pull request 'path!' (#70) from f0ck_local into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 17s
Reviewed-on: #70
2024-02-20 00:27:17 +00:00
78457fd644 Merge pull request 'path?' (#69) from f0ck_local into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 17s
Reviewed-on: #69
2024-02-20 00:17:04 +00:00
9f1052320e Merge pull request 'fixing imgur' (#68) from f0ck_local into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 18s
Reviewed-on: #68
2024-02-20 00:14:09 +00:00
ed2a3a4bc5 Merge pull request 'making me latest change return fuck instagram' (#67) from dev into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
Reviewed-on: #67
2024-02-19 20:53:36 +00:00
74fc3a9134 Merge pull request 'removing insta link message' (#66) from dev into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
Reviewed-on: #66
2024-02-19 20:03:08 +00:00
05518fa495 Merge pull request 'experimental instagram video download support' (#65) from dev into master
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
Reviewed-on: #65
2024-02-19 19:59:13 +00:00
46 changed files with 1666 additions and 745 deletions

View File

@ -19,7 +19,7 @@ let items;
if(_itemid > 0) if(_itemid > 0)
items = await sql('items').where('id', _itemid); items = await sql('items').where('id', _itemid);
else else
items = await sql('items').orderBy('id', 'asc').where('src', 'like', '%soundcloud%').where('mime', 'like', 'audio/%'); items = await sql`select id, dest, mime, src from "items"`;
let count = 1; let count = 1;
let total = items.length; let total = items.length;
@ -32,7 +32,7 @@ for(let item of items) {
if(mime.startsWith('video/') || mime == 'image/gif') if(mime.startsWith('video/') || mime == 'image/gif')
await exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./tmp/${itemid}.png`); await exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./tmp/${itemid}.png`);
else if(mime.startsWith('image/') && mime != 'image/gif') else if(mime.startsWith('image/') && mime != 'image/gif')
await exec(`convert ./public/b/${filename} ./tmp/${itemid}.png`); await exec(`magick ./public/b/${filename} ./tmp/${itemid}.png`);
else if(mime.startsWith('audio/')) { else if(mime.startsWith('audio/')) {
if(link.match(/soundcloud/)) { if(link.match(/soundcloud/)) {
let cover = (await exec(`yt-dlp --get-thumbnail "${link}"`)).stdout.trim(); let cover = (await exec(`yt-dlp --get-thumbnail "${link}"`)).stdout.trim();
@ -42,8 +42,8 @@ for(let item of items) {
await exec(`wget "${cover}" -O ./tmp/${itemid}.jpg`); await exec(`wget "${cover}" -O ./tmp/${itemid}.jpg`);
const size = (await fs.promises.stat(`./tmp/${itemid}.jpg`)).size; const size = (await fs.promises.stat(`./tmp/${itemid}.jpg`)).size;
if(size >= 0) { if(size >= 0) {
await exec(`convert ./tmp/${itemid}.jpg ./tmp/${itemid}.png`); await exec(`magick ./tmp/${itemid}.jpg ./tmp/${itemid}.png`);
await exec(`convert ./tmp/${itemid}.jpg ./public/ca/${itemid}.webp`); await exec(`magick ./tmp/${itemid}.jpg ./public/ca/${itemid}.webp`);
} }
} catch(err) { } catch(err) {
//console.log(err); //console.log(err);
@ -51,21 +51,21 @@ for(let item of items) {
} }
else { else {
await exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`); await exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`);
await exec(`convert ./tmp/${itemid}.png ./public/ca/${itemid}.webp`); await exec(`magick ./tmp/${itemid}.png ./public/ca/${itemid}.webp`);
} }
} }
else { else {
await exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`); await exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`);
await exec(`convert ./tmp/${itemid}.png ./public/ca/${itemid}.webp`); await exec(`magick ./tmp/${itemid}.png ./public/ca/${itemid}.webp`);
} }
} }
await exec(`convert "./tmp/${itemid}.png" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.webp`); await exec(`magick "./tmp/${itemid}.png" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.webp`);
await fs.promises.unlink(`./tmp/${itemid}.png`).catch(err => {}); await fs.promises.unlink(`./tmp/${itemid}.png`).catch(err => {});
await fs.promises.unlink(`./tmp/${itemid}.jpg`).catch(err => {}); await fs.promises.unlink(`./tmp/${itemid}.jpg`).catch(err => {});
} catch(err) { } catch(err) {
//console.log(err); //console.log(err);
await exec(`convert ./mugge.png ./public/t/${itemid}.webp`); await exec(`magick ./mugge.png ./public/t/${itemid}.webp`);
} }
console.log(`current: ${itemid} (${count} / ${total})`); console.log(`current: ${itemid} (${count} / ${total})`);
count++; count++;
@ -76,7 +76,7 @@ for(let item of items) {
const itemid = item.id; const itemid = item.id;
const filename = item.dest; const filename = item.dest;
await exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./debug/tmp/${itemid}`); await exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./debug/tmp/${itemid}`);
await exec(`convert "./debug/tmp/${itemid}" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.png`); await exec(`magick "./debug/tmp/${itemid}" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.png`);
await fs.unlink(`./debug/tmp/${itemid}`); await fs.unlink(`./debug/tmp/${itemid}`);
console.log(`current: ${itemid} (${count} / ${total})`); console.log(`current: ${itemid} (${count} / ${total})`);
} catch(err) {} } catch(err) {}

611
f0ck.sql
View File

@ -1,4 +1,9 @@
\connect "f0ck"; --
-- PostgreSQL database dump
--
-- Dumped from database version 16.2
-- Dumped by pg_dump version 16.2
SET statement_timeout = 0; SET statement_timeout = 0;
SET lock_timeout = 0; SET lock_timeout = 0;
@ -11,7 +16,33 @@ SET xmloption = content;
SET client_min_messages = warning; SET client_min_messages = warning;
SET row_security = off; SET row_security = off;
CREATE EXTENSION unaccent; --
-- Name: public; Type: SCHEMA; Schema: -; Owner: f0ck
--
-- *not* creating schema, since initdb creates it
ALTER SCHEMA public OWNER TO f0ck;
--
-- Name: unaccent; Type: EXTENSION; Schema: -; Owner: -
--
CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public;
--
-- Name: EXTENSION unaccent; Type: COMMENT; Schema: -; Owner:
--
COMMENT ON EXTENSION unaccent IS 'text search dictionary that removes accents';
--
-- Name: delete_unused_tags(); Type: FUNCTION; Schema: public; Owner: f0ck
--
CREATE FUNCTION public.delete_unused_tags() RETURNS trigger CREATE FUNCTION public.delete_unused_tags() RETURNS trigger
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
@ -21,14 +52,17 @@ begin
tags.id not in (select tag_id from tags_assign) and tags.id not in (select tag_id from tags_assign) and
tags.id = OLD.tag_id and tags.id = OLD.tag_id and
tags.tag != 'sfw' and tags.tag != 'sfw' and
tags.tag != 'nsfw' and tags.tag != 'nsfw';
tags.tag != 'hentai' and
tags.tag != 'audio';
return OLD; return OLD;
end $$; end $$;
ALTER FUNCTION public.delete_unused_tags() OWNER TO f0ck; ALTER FUNCTION public.delete_unused_tags() OWNER TO f0ck;
--
-- Name: fill_normalized(); Type: FUNCTION; Schema: public; Owner: f0ck
--
CREATE FUNCTION public.fill_normalized() RETURNS trigger CREATE FUNCTION public.fill_normalized() RETURNS trigger
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
@ -37,8 +71,13 @@ begin
return NEW; return NEW;
end$$; end$$;
ALTER FUNCTION public.fill_normalized() OWNER TO f0ck; ALTER FUNCTION public.fill_normalized() OWNER TO f0ck;
--
-- Name: slugify(text); Type: FUNCTION; Schema: public; Owner: f0ck
--
CREATE FUNCTION public.slugify(v text) RETURNS text CREATE FUNCTION public.slugify(v text) RETURNS text
LANGUAGE plpgsql LANGUAGE plpgsql
AS $$ AS $$
@ -47,15 +86,47 @@ BEGIN
END; END;
$$; $$;
ALTER FUNCTION public.slugify(v text) OWNER TO f0ck; ALTER FUNCTION public.slugify(v text) OWNER TO f0ck;
--
-- Name: unaccent_text(text); Type: FUNCTION; Schema: public; Owner: f0ck
--
CREATE FUNCTION public.unaccent_text(text) RETURNS text
LANGUAGE sql IMMUTABLE COST 1
AS $_$
-- unaccent is STABLE, but the indexes must use IMMUTABLE functions.
-- comment this line out when calling pg_dump.
SELECT unaccent($1);
-- Uncomment this line when calling pg_dump.
--SELECT ''::text;
$_$;
ALTER FUNCTION public.unaccent_text(text) OWNER TO f0ck;
SET default_tablespace = '';
SET default_table_access_method = heap;
--
-- Name: favorites; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.favorites ( CREATE TABLE public.favorites (
user_id integer NOT NULL, user_id integer NOT NULL,
item_id integer NOT NULL item_id integer NOT NULL
); );
ALTER TABLE public.favorites OWNER TO f0ck; ALTER TABLE public.favorites OWNER TO f0ck;
--
-- Name: items_id_seq; Type: SEQUENCE; Schema: public; Owner: f0ck
--
CREATE SEQUENCE public.items_id_seq CREATE SEQUENCE public.items_id_seq
START WITH 1 START WITH 1
INCREMENT BY 1 INCREMENT BY 1
@ -63,7 +134,12 @@ CREATE SEQUENCE public.items_id_seq
NO MAXVALUE NO MAXVALUE
CACHE 1; CACHE 1;
ALTER TABLE public.items_id_seq OWNER TO f0ck;
ALTER SEQUENCE public.items_id_seq OWNER TO f0ck;
--
-- Name: items; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.items ( CREATE TABLE public.items (
id integer DEFAULT nextval('public.items_id_seq'::regclass) NOT NULL, id integer DEFAULT nextval('public.items_id_seq'::regclass) NOT NULL,
@ -73,18 +149,115 @@ CREATE TABLE public.items (
size integer NOT NULL, size integer NOT NULL,
checksum character varying(255) NOT NULL, checksum character varying(255) NOT NULL,
username character varying(40) NOT NULL, username character varying(40) NOT NULL,
userchannel character varying(100) NOT NULL, userchannel character varying(255) NOT NULL,
usernetwork character varying(40) NOT NULL, usernetwork character varying(40) NOT NULL,
stamp integer NOT NULL, stamp integer NOT NULL,
active boolean NOT NULL, active boolean NOT NULL,
thumb character varying(100) thumb character varying(100)
); );
ALTER TABLE public.items OWNER TO f0ck; ALTER TABLE public.items OWNER TO f0ck;
--
-- Name: COLUMN items.src; Type: COMMENT; Schema: public; Owner: f0ck
--
COMMENT ON COLUMN public.items.src IS 'src-Link'; COMMENT ON COLUMN public.items.src IS 'src-Link';
--
-- Name: COLUMN items.dest; Type: COMMENT; Schema: public; Owner: f0ck
--
COMMENT ON COLUMN public.items.dest IS 'filename'; COMMENT ON COLUMN public.items.dest IS 'filename';
--
-- Name: items_li; Type: VIEW; Schema: public; Owner: f0ck
--
CREATE VIEW public.items_li AS
SELECT
NULL::integer AS id,
NULL::character varying(255) AS src,
NULL::character varying(40) AS dest,
NULL::character varying(100) AS mime,
NULL::integer AS size,
NULL::character varying(255) AS checksum,
NULL::character varying(40) AS username,
NULL::character varying(255) AS userchannel,
NULL::character varying(40) AS usernetwork,
NULL::integer AS stamp;
ALTER VIEW public.items_li OWNER TO f0ck;
--
-- Name: tags_assign; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.tags_assign (
item_id integer NOT NULL,
tag_id integer NOT NULL,
user_id integer DEFAULT 10 NOT NULL
);
ALTER TABLE public.tags_assign OWNER TO f0ck;
--
-- Name: tags_nsfp; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.tags_nsfp (
id integer NOT NULL
);
ALTER TABLE public.tags_nsfp OWNER TO f0ck;
--
-- Name: items_sfw; Type: VIEW; Schema: public; Owner: f0ck
--
CREATE VIEW public.items_sfw AS
SELECT ( SELECT
CASE
WHEN (tags_assign.tag_id > 0) THEN tags_assign.tag_id
ELSE 0
END AS "case"
FROM public.tags_assign
WHERE ((tags_assign.tag_id = ANY (ARRAY[1, 2])) AND (tags_assign.item_id = items.id))) AS sfw,
( SELECT
CASE
WHEN (tags_assign.tag_id > 0) THEN 1
ELSE 0
END AS "case"
FROM public.tags_assign
WHERE ((tags_assign.tag_id IN ( SELECT tags_nsfp.id
FROM public.tags_nsfp)) AND (tags_assign.item_id = items.id))
LIMIT 1) AS nsfp,
id,
src,
dest,
mime,
size,
checksum,
username,
userchannel,
usernetwork,
stamp,
active
FROM public.items;
ALTER VIEW public.items_sfw OWNER TO f0ck;
--
-- Name: tags_id_seq; Type: SEQUENCE; Schema: public; Owner: f0ck
--
CREATE SEQUENCE public.tags_id_seq CREATE SEQUENCE public.tags_id_seq
START WITH 1 START WITH 1
INCREMENT BY 1 INCREMENT BY 1
@ -92,30 +265,25 @@ CREATE SEQUENCE public.tags_id_seq
NO MAXVALUE NO MAXVALUE
CACHE 1; CACHE 1;
ALTER TABLE public.tags_id_seq OWNER TO f0ck;
ALTER SEQUENCE public.tags_id_seq OWNER TO f0ck;
--
-- Name: tags; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.tags ( CREATE TABLE public.tags (
id integer DEFAULT nextval('public.tags_id_seq'::regclass) NOT NULL, id integer DEFAULT nextval('public.tags_id_seq'::regclass) NOT NULL,
tag character varying(45) NOT NULL, tag character varying(70) NOT NULL,
normalized character varying(45) NOT NULL normalized character varying(70) NOT NULL
); );
ALTER TABLE public.tags OWNER TO f0ck; ALTER TABLE public.tags OWNER TO f0ck;
CREATE TABLE public.tags_alias ( --
tag_orig_id integer NOT NULL, -- Name: user_id_seq; Type: SEQUENCE; Schema: public; Owner: f0ck
tag_alias character varying NOT NULL --
);
ALTER TABLE public.tags_alias OWNER TO f0ck;
CREATE TABLE public.tags_assign (
item_id integer NOT NULL,
tag_id integer NOT NULL,
user_id integer DEFAULT 2 NOT NULL
);
ALTER TABLE public.tags_assign OWNER TO f0ck;
CREATE SEQUENCE public.user_id_seq CREATE SEQUENCE public.user_id_seq
START WITH 1 START WITH 1
@ -124,31 +292,128 @@ CREATE SEQUENCE public.user_id_seq
NO MAXVALUE NO MAXVALUE
CACHE 1; CACHE 1;
ALTER TABLE public.user_id_seq OWNER TO f0ck;
ALTER SEQUENCE public.user_id_seq OWNER TO f0ck;
--
-- Name: user; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public."user" ( CREATE TABLE public."user" (
id integer DEFAULT nextval('public.user_id_seq'::regclass) NOT NULL, id integer DEFAULT nextval('public.user_id_seq'::regclass) NOT NULL,
login character varying(255) NOT NULL, login character varying(255) NOT NULL,
"user" character varying(255) NOT NULL, "user" character varying(255) NOT NULL,
password character varying(167) NOT NULL, password character varying(167) NOT NULL,
level integer NOT NULL admin boolean NOT NULL,
created_at timestamp without time zone DEFAULT now() NOT NULL
); );
ALTER TABLE public."user" OWNER TO f0ck; ALTER TABLE public."user" OWNER TO f0ck;
--
-- Name: items_tags; Type: VIEW; Schema: public; Owner: f0ck
--
CREATE VIEW public.items_tags AS
SELECT ( SELECT
CASE
WHEN (tags_assign.tag_id > 0) THEN tags_assign.tag_id
ELSE 0
END AS "case"
FROM public.tags_assign
WHERE ((tags_assign.tag_id = ANY (ARRAY[1, 2])) AND (tags_assign.item_id = items.id))) AS sfw,
( SELECT
CASE
WHEN (tags_assign.tag_id > 0) THEN 1
ELSE 0
END AS "case"
FROM public.tags_assign
WHERE ((tags_assign.tag_id IN ( SELECT tags_nsfp.id
FROM public.tags_nsfp)) AND (tags_assign.item_id = items.id))
LIMIT 1) AS nsfp,
( SELECT jsonb_agg(jsonb_build_object('id', tags.id, 'normalized', tags.normalized)) AS jsonb_agg
FROM (public.tags_assign
LEFT JOIN public.tags ON ((tags.id = tags_assign.tag_id)))
WHERE (tags_assign.item_id = items.id)) AS tags,
( SELECT jsonb_agg(jsonb_build_object('id', favorites.user_id, 'user', "user"."user")) AS jsonb_agg
FROM (public.favorites
LEFT JOIN public."user" ON (("user".id = favorites.user_id)))
WHERE (favorites.item_id = items.id)) AS favs,
id,
src,
dest,
mime,
size,
checksum,
username,
userchannel,
usernetwork,
stamp,
active
FROM public.items;
ALTER VIEW public.items_tags OWNER TO f0ck;
--
-- Name: tags_alias; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.tags_alias (
tag_orig_id integer NOT NULL,
tag_alias character varying NOT NULL
);
ALTER TABLE public.tags_alias OWNER TO f0ck;
--
-- Name: user_alias; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.user_alias (
userid integer NOT NULL,
alias character varying(255) NOT NULL
);
ALTER TABLE ONLY public.user_alias REPLICA IDENTITY FULL;
ALTER TABLE public.user_alias OWNER TO f0ck;
--
-- Name: user_options; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.user_options ( CREATE TABLE public.user_options (
user_id integer NOT NULL, user_id integer NOT NULL,
mode integer NOT NULL, mode integer NOT NULL,
theme character varying(50) NOT NULL, theme character varying(50) NOT NULL,
avatar integer DEFAULT 1 NOT NULL, avatar integer DEFAULT 56660 NOT NULL,
fullscreen integer DEFAULT 0 NOT NULL fullscreen smallint DEFAULT '0'::smallint NOT NULL
); );
ALTER TABLE public.user_options OWNER TO f0ck; ALTER TABLE public.user_options OWNER TO f0ck;
CREATE SEQUENCE public.user_sessions_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; --
-- Name: user_sessions_id_seq; Type: SEQUENCE; Schema: public; Owner: f0ck
--
ALTER TABLE public.user_sessions_id_seq OWNER TO f0ck; CREATE SEQUENCE public.user_sessions_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE public.user_sessions_id_seq OWNER TO f0ck;
--
-- Name: user_sessions; Type: TABLE; Schema: public; Owner: f0ck
--
CREATE TABLE public.user_sessions ( CREATE TABLE public.user_sessions (
id integer DEFAULT nextval('public.user_sessions_id_seq'::regclass) NOT NULL, id integer DEFAULT nextval('public.user_sessions_id_seq'::regclass) NOT NULL,
@ -161,55 +426,255 @@ CREATE TABLE public.user_sessions (
kmsi smallint DEFAULT '0'::smallint NOT NULL kmsi smallint DEFAULT '0'::smallint NOT NULL
); );
ALTER TABLE public.user_sessions OWNER TO f0ck; ALTER TABLE public.user_sessions OWNER TO f0ck;
COPY public.items (id, src, dest, mime, size, checksum, username, userchannel, usernetwork, stamp, active, thumb) FROM stdin; --
1 b761fa9339.png b761fa9339.png image/png 164 keinPlan Flummi #f0ck n0xy 1471250800 t -- Name: favorites idx_16521_primary; Type: CONSTRAINT; Schema: public; Owner: f0ck
\. --
COPY public.tags (id, tag, normalized) FROM stdin; ALTER TABLE ONLY public.favorites
1 sfw sfw ADD CONSTRAINT idx_16521_primary PRIMARY KEY (user_id, item_id);
2 nsfw nsfw
3 audio audio
4 hentai hentai
\.
COPY public.tags_assign (item_id, tag_id, user_id) FROM stdin;
1 1 1
\.
COPY public."user" (id, login, "user", password, level) FROM stdin; --
1 autotagger autotagger f0ck you 0 -- Name: items idx_16526_primary; Type: CONSTRAINT; Schema: public; Owner: f0ck
2 deleted deleted f0ck you 0 --
\.
ALTER TABLE ONLY public.items
ADD CONSTRAINT idx_16526_primary PRIMARY KEY (id);
--
-- Name: user idx_16554_primary; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public."user"
ADD CONSTRAINT idx_16554_primary PRIMARY KEY (id);
--
-- Name: user_options idx_16567_user_id; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_options
ADD CONSTRAINT idx_16567_user_id UNIQUE (user_id);
--
-- Name: user_sessions idx_16572_primary; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_sessions
ADD CONSTRAINT idx_16572_primary PRIMARY KEY (id);
--
-- Name: items items_checksum; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.items
ADD CONSTRAINT items_checksum UNIQUE (checksum);
--
-- Name: tags_alias tags_alias_tag_alias_tag_orig_id; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_alias
ADD CONSTRAINT tags_alias_tag_alias_tag_orig_id UNIQUE (tag_alias, tag_orig_id);
--
-- Name: tags_alias tags_alias_tag_orig_id; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_alias
ADD CONSTRAINT tags_alias_tag_orig_id PRIMARY KEY (tag_orig_id);
--
-- Name: tags_assign tags_assign_item_id_tag_id_primary; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_assign
ADD CONSTRAINT tags_assign_item_id_tag_id_primary PRIMARY KEY (item_id, tag_id);
--
-- Name: tags_assign tags_assign_item_id_tag_id_unique; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_assign
ADD CONSTRAINT tags_assign_item_id_tag_id_unique UNIQUE (item_id, tag_id);
--
-- Name: tags tags_id; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags
ADD CONSTRAINT tags_id PRIMARY KEY (id);
--
-- Name: tags tags_normalized; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags
ADD CONSTRAINT tags_normalized UNIQUE (normalized);
--
-- Name: tags tags_tag; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags
ADD CONSTRAINT tags_tag UNIQUE (tag);
--
-- Name: user_options user_options_user_id; Type: CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_options
ADD CONSTRAINT user_options_user_id PRIMARY KEY (user_id);
--
-- Name: items_li _RETURN; Type: RULE; Schema: public; Owner: f0ck
--
CREATE OR REPLACE VIEW public.items_li AS
SELECT items.id,
items.src,
items.dest,
items.mime,
items.size,
items.checksum,
items.username,
items.userchannel,
items.usernetwork,
items.stamp
FROM ((public.items
JOIN public.tags_assign ta1 ON (((ta1.tag_id = 1) AND (ta1.item_id = items.id))))
JOIN public.tags_assign ta2 ON (((NOT (ta2.tag_id IN ( SELECT tags_nsfp.id
FROM public.tags_nsfp))) AND (ta2.item_id = items.id))))
WHERE items.active
GROUP BY items.id;
--
-- Name: tags_assign tags_assign_ad; Type: TRIGGER; Schema: public; Owner: f0ck
--
SELECT pg_catalog.setval('public.items_id_seq', 2, true);
SELECT pg_catalog.setval('public.tags_id_seq', 5, true);
SELECT pg_catalog.setval('public.user_id_seq', 3, true);
SELECT pg_catalog.setval('public.user_sessions_id_seq', 1, true);
ALTER TABLE ONLY public.favorites ADD CONSTRAINT idx_16521_primary PRIMARY KEY (user_id, item_id);
ALTER TABLE ONLY public.items ADD CONSTRAINT idx_16526_primary PRIMARY KEY (id);
ALTER TABLE ONLY public."user" ADD CONSTRAINT idx_16554_primary PRIMARY KEY (id);
ALTER TABLE ONLY public.user_options ADD CONSTRAINT idx_16567_user_id UNIQUE (user_id);
ALTER TABLE ONLY public.user_sessions ADD CONSTRAINT idx_16572_primary PRIMARY KEY (id);
ALTER TABLE ONLY public.items ADD CONSTRAINT items_checksum UNIQUE (checksum);
ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_alias_tag_orig_id UNIQUE (tag_alias, tag_orig_id);
ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_orig_id PRIMARY KEY (tag_orig_id);
ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_tag_id_primary PRIMARY KEY (item_id, tag_id);
ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_tag_id_unique UNIQUE (item_id, tag_id);
ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_id PRIMARY KEY (id);
ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_normalized UNIQUE (normalized);
ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_tag UNIQUE (tag);
ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_user_id PRIMARY KEY (user_id);
CREATE TRIGGER tags_assign_ad AFTER DELETE ON public.tags_assign FOR EACH ROW EXECUTE FUNCTION public.delete_unused_tags(); CREATE TRIGGER tags_assign_ad AFTER DELETE ON public.tags_assign FOR EACH ROW EXECUTE FUNCTION public.delete_unused_tags();
--
-- Name: tags tags_bi; Type: TRIGGER; Schema: public; Owner: f0ck
--
CREATE TRIGGER tags_bi BEFORE INSERT ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized(); CREATE TRIGGER tags_bi BEFORE INSERT ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized();
--
-- Name: tags tags_bu; Type: TRIGGER; Schema: public; Owner: f0ck
--
CREATE TRIGGER tags_bu BEFORE UPDATE ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized(); CREATE TRIGGER tags_bu BEFORE UPDATE ON public.tags FOR EACH ROW EXECUTE FUNCTION public.fill_normalized();
ALTER TABLE ONLY public.favorites ADD CONSTRAINT favorites_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.favorites ADD CONSTRAINT favorites_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.tags_alias ADD CONSTRAINT tags_alias_tag_orig_id_fkey FOREIGN KEY (tag_orig_id) REFERENCES public.tags(id) ON DELETE CASCADE; --
ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE; -- Name: favorites favorites_item_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE; --
ALTER TABLE ONLY public.tags_assign ADD CONSTRAINT tags_assign_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE SET DEFAULT;
ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_avatar_fkey FOREIGN KEY (avatar) REFERENCES public.items(id) ON DELETE SET DEFAULT; ALTER TABLE ONLY public.favorites
ALTER TABLE ONLY public.user_options ADD CONSTRAINT user_options_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE; ADD CONSTRAINT favorites_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE;
ALTER TABLE ONLY public.user_sessions ADD CONSTRAINT user_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
--
-- Name: favorites favorites_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.favorites
ADD CONSTRAINT favorites_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
--
-- Name: tags_alias tags_alias_tag_orig_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_alias
ADD CONSTRAINT tags_alias_tag_orig_id_fkey FOREIGN KEY (tag_orig_id) REFERENCES public.tags(id) ON DELETE CASCADE;
--
-- Name: tags_assign tags_assign_item_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_assign
ADD CONSTRAINT tags_assign_item_id_fkey FOREIGN KEY (item_id) REFERENCES public.items(id) ON DELETE CASCADE;
--
-- Name: tags_assign tags_assign_tag_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_assign
ADD CONSTRAINT tags_assign_tag_id_fkey FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE;
--
-- Name: tags_assign tags_assign_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.tags_assign
ADD CONSTRAINT tags_assign_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE SET DEFAULT;
--
-- Name: user_options user_options_avatar_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_options
ADD CONSTRAINT user_options_avatar_fkey FOREIGN KEY (avatar) REFERENCES public.items(id) ON DELETE SET DEFAULT;
--
-- Name: user_options user_options_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_options
ADD CONSTRAINT user_options_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
--
-- Name: user_sessions user_sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: f0ck
--
ALTER TABLE ONLY public.user_sessions
ADD CONSTRAINT user_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
--
-- Name: alltables; Type: PUBLICATION; Schema: -; Owner: postgres
--
CREATE PUBLICATION alltables FOR ALL TABLES WITH (publish = 'insert, update, delete, truncate');
ALTER PUBLICATION alltables OWNER TO f0ck;
--
-- Name: SCHEMA public; Type: ACL; Schema: -; Owner: postgres
--
REVOKE USAGE ON SCHEMA public FROM PUBLIC;
GRANT ALL ON SCHEMA public TO PUBLIC;
--
-- PostgreSQL database dump complete
--

View File

@ -72,7 +72,7 @@ html[theme='p1nk'] {
--black: #000; --black: #000;
--white: #fff; --white: #fff;
--gray: #262626; --gray: #262626;
--nav-bg: #2b2b2b; --nav-bg: #201f1f;
--nav-brand-border: inset 1px #242424; --nav-brand-border: inset 1px #242424;
--nav-brand-bg: #171717; --nav-brand-bg: #171717;
--navigation-links-bg: #201f1f; --navigation-links-bg: #201f1f;
@ -494,7 +494,7 @@ html[theme="atmos"] {
--posts-meta-bg: #000000b8; --posts-meta-bg: #000000b8;
--badge-sfw: #68a728; --badge-sfw: #68a728;
--badge-nsfw: #a72828; --badge-nsfw: #a72828;
--badge-tag: #090909; --badge-tag: #353535;
--scrollbar-color: #2b2b2b; --scrollbar-color: #2b2b2b;
--footbar-color: #1fb2b0; --footbar-color: #1fb2b0;
--loading-indicator-color: #1fb2b0; --loading-indicator-color: #1fb2b0;
@ -1618,9 +1618,10 @@ span.placeholder {
} }
@media (max-width: 1325px) { @media (max-width: 1325px) {
.ranking { /* ranking page - idea */
/* .ranking {
grid-template-columns: 1fr 1fr !important; grid-template-columns: 1fr 1fr !important;
} } */
.by-user, .by-user,
.by-stats, .by-stats,
@ -2401,7 +2402,7 @@ table.table tbody tr:nth-of-type(odd) {
.ranking { .ranking {
display: grid; display: grid;
grid-template-columns: auto; grid-template-columns: auto;
justify-content: center; /* justify-content: center; */
} }
.ranking div { .ranking div {
@ -2414,15 +2415,15 @@ table.table tbody tr:nth-of-type(odd) {
} }
.by-user { .by-user {
grid-column: 1; grid-row: 1;
} }
.by-stats { .by-stats {
grid-column: 3; grid-row: 3;
} }
.by-hoster { .by-hoster {
grid-column: 2; grid-row: 2;
} }
/* tags */ /* tags */
@ -2991,4 +2992,32 @@ button#togglebg {
.fader-out { .fader-out {
animation: fadeOut .8s steps(100) forwards animation: fadeOut .8s steps(100) forwards
} }
.settings {
display: grid;
justify-content: center;
}
input[name="i_avatar"] {
text-align: center;
width: 50px;
padding: 10px;
}
input#s_avatar {
padding: 5px;
border: 1px solid var(--black);
border-radius: 3px;
background-image: linear-gradient(to bottom, var(--nav-link-background-linear-gradient));
box-shadow: var(--nav-link-box-shadow);
cursor: pointer;
}
#s_avatar:hover {
background: #ffffff0f;
}
.theforceofthree {
display: grid;
grid-template-columns: 0.4fr 1fr 0.4fr;
}

171
public/s/css/w0bm.css Normal file
View File

@ -0,0 +1,171 @@
.navbar-brand {
display: grid;
grid-template-columns: 1fr auto;
}
.image-brand {
width: 5cm;
}
.kontrollelement {
grid-column: 2;
}
.metadata {
grid-template-columns: 0.4fr auto 0.4fr;
grid-template-rows: auto 1fr;
background-color: transparent !important;
border: none !important;
}
html[theme="f0ck95d"] .badge-dark {
border: none;
background-image: none;
box-shadow: none;
}
.steuerung {
font-size:x-large;
font-family: monospace;
}
.steuerung a {
color: white;
}
.blahlol {
grid-column: 2;
}
span#favs {
background: transparent !important;
border: none !important;
}
.badge-dark, #themeselector {
background-color: unset;
border: unset;
}
._204863 {
background: none;
border: none;
background-color: none;
}
html[theme="iced"] ._204863 {
background: none;
}
.media-object {
border: none;
}
.v0ck {
background: transparent !important;
}
html[theme="f0ck95d"] .embed-responsive.embed-responsive-16by9 {
background:#0000008f !important;
}
html[theme="f0ck95"] .embed-responsive.embed-responsive-16by9 {
background:var(--nav-bg) !important;
}
.v0ck_overlay {
background-color: transparent;
}
.v0ck_player_controls {
background:rgba(0, 0, 0, 0.95) !important;
}
html[theme="term"] .image-brand {
filter: hue-rotate(-50deg);
}
html[theme="f0ck"] .image-brand {
filter: hue-rotate(-50deg);
}
html[theme="p1nk"] .image-brand {
filter: hue-rotate(150deg);
}
html[theme="orange"] .image-brand {
filter: hue-rotate(-160deg);
}
.v0ck_overlay {
background-color: none !important;
}
.tags {
display: grid;
}
@media (min-width: 600px) {
.tags { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
.tags { grid-template-columns: repeat(3, 1fr); }
}
.tag {
box-shadow: 1px 1px 1px black;
display: grid;
margin: 5px;
grid-template-columns: auto;
grid-template-rows: 1fr;
}
.navigation-rechts {
display: flex;
}
.about {
background: none!important;
}
.login-image {
width: 300px;
}
.tos {
margin: 2em;
}
.nav-link[data-toggle="dropdown"]::after {
content: "" !important;
}
.dropdown-menu.shii {
width: auto;
}
@media (min-width: 900px) {
.tags {
grid-template-columns: repeat(auto-fill, 20em);
justify-content: center;
}
}
.tag img {
width: 100%;
}
@media (max-width: 1056px) {
html, body {
text-align: left;
}
}
html[theme="f0ck95d"] .embed-responsive.embed-responsive-16by9 {
border-bottom: outset 2px silver;
}
html[theme="f0ck95"] .embed-responsive.embed-responsive-16by9 {
border-bottom: outset 2px silver;
}

BIN
public/s/img/404.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 KiB

BIN
public/s/img/cockfag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 KiB

View File

@ -1,41 +1,3 @@
let flashActive = false;
const flashTypes = [ "error", "success", "warn" ];
const flash = ({ type, msg }) => {
let flashContainer;
if(tmp = document.querySelector("div#flash"))
flashContainer = tmp;
else {
flashContainer = document.createElement("div");
flashContainer.id = "flash";
document.body.insertAdjacentElement("afterbegin", flashContainer);
}
flashContainer.innerHTML = msg;
if(flashTypes.includes(type)) {
flashContainer.className = "";
flashContainer.classList.add(type);
}
if(flashActive)
return false;
flashActive = true;
flashContainer.animate(
[ { bottom: "-28px" }, { bottom: 0 } ], {
duration: 500,
fill: "both"
}
).onfinish = () => setTimeout(() => {
flashContainer.animate(
[ { bottom: 0 }, { bottom: "-28px" } ], {
duration: 500,
fill: "both"
}
).onfinish = () => flashActive = false;
}, 4 * 1e3);
return true;
};
(async () => { (async () => {
if(_addtag = document.querySelector("a#a_addtag")) { if(_addtag = document.querySelector("a#a_addtag")) {
const postid = +document.querySelector("a.id-link").innerText; const postid = +document.querySelector("a.id-link").innerText;
@ -140,10 +102,8 @@ const flash = ({ type, msg }) => {
tagname: tmptag tagname: tmptag
}); });
if(!res.success) { if(!res.success) {
return flash({ alert(res.msg);
type: "error", return false;
msg: res.msg
});
} }
tags = res.tags.map(t => t.tag); tags = res.tags.map(t => t.tag);
renderTags(res.tags); renderTags(res.tags);
@ -202,12 +162,6 @@ const flash = ({ type, msg }) => {
})).json(); })).json();
renderTags(res.tags); renderTags(res.tags);
tags = res.tags.map(t => t.tag);
flash({
type: "success",
msg: tags.join()
});
}; };
const deleteButtonEvent = async e => { const deleteButtonEvent = async e => {
@ -218,17 +172,8 @@ const flash = ({ type, msg }) => {
const res = await post("/api/v2/admin/deletepost", { const res = await post("/api/v2/admin/deletepost", {
postid: postid postid: postid
}); });
if(res.success) { if(!res.success) {
flash({ alert(res.msg);
type: "success",
msg: "post was successfully deleted"
});
}
else {
flash({
type: "error",
msg: res.msg
});
} }
}; };
@ -333,11 +278,12 @@ const flash = ({ type, msg }) => {
document.querySelector("a#a_toggle").addEventListener("click", toggleEvent); document.querySelector("a#a_toggle").addEventListener("click", toggleEvent);
[...document.querySelectorAll("#tags > .badge > a:first-child")].map(t => t.addEventListener("click", editTagEvent)); [...document.querySelectorAll("#tags > .badge > a:first-child")].map(t => t.addEventListener("click", editTagEvent));
[...document.querySelectorAll("#tags > .badge > a:last-child")].map(t => t.addEventListener("click", deleteEvent)); [...document.querySelectorAll("#tags > .badge > a:last-child")].map(t => t.addEventListener("click", deleteEvent));
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent); if(document.querySelector("svg#a_delete"))
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent);
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent); document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);
document.addEventListener("keyup", e => { document.addEventListener("keyup", e => {
if(e.target.tagName === "INPUT") if(e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")
return; return;
if(e.key === "p") if(e.key === "p")
toggleEvent(); toggleEvent();

View File

@ -11,7 +11,7 @@ window.requestAnimFrame = (function(){
if(elem = document.querySelector("#my-video")) { if(elem = document.querySelector("#my-video")) {
video = new v0ck(elem); video = new v0ck(elem);
document.addEventListener("keydown", e => { document.addEventListener("keydown", e => {
if(e.key === " " && e.target.tagName !== "INPUT") { if(e.key === " " && e.target.tagName !== "INPUT" && e.target.tagName !== "TEXTAREA") {
video[video.paused ? 'play' : 'pause'](); video[video.paused ? 'play' : 'pause']();
document.querySelector('.v0ck_overlay').classList[video.paused ? 'remove' : 'add']('v0ck_hidden'); document.querySelector('.v0ck_overlay').classList[video.paused ? 'remove' : 'add']('v0ck_hidden');
} }
@ -72,7 +72,7 @@ window.requestAnimFrame = (function(){
" ": clickOnElementBinding("#f0ck-image") " ": clickOnElementBinding("#f0ck-image")
}; };
document.addEventListener("keydown", e => { document.addEventListener("keydown", e => {
if(e.key in keybindings && e.target.tagName !== "INPUT") { if(e.key in keybindings && e.target.tagName !== "INPUT" && e.target.tagName !== "TEXTAREA") {
if(e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) if(e.shiftKey || e.ctrlKey || e.metaKey || e.altKey)
return; return;
e.preventDefault(); e.preventDefault();

View File

@ -15,7 +15,7 @@ const Cookie = {
}; };
(() => { (() => {
const acttheme = Cookie.get('theme') ?? "f0ck"; const acttheme = Cookie.get('theme') ?? "w0bm";
const themecontainer = document.querySelector("li#themes > ul.dropdown-menu"); const themecontainer = document.querySelector("li#themes > ul.dropdown-menu");
const themes = [...themecontainer.querySelectorAll("li > a")].map(t => t.innerText.toLowerCase()); 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))
@ -30,9 +30,9 @@ const Cookie = {
})); }));
document.addEventListener("keydown", e => { document.addEventListener("keydown", e => {
if(e.target.tagName === "INPUT") if(e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA")
return; return;
const acttheme = Cookie.get('theme') ?? "f0ck"; const acttheme = Cookie.get('theme') ?? "w0bm";
const themes = [...themecontainer.querySelectorAll("li > a")].map(t => t.innerText.toLowerCase()); const themes = [...themecontainer.querySelectorAll("li > a")].map(t => t.innerText.toLowerCase());
const k = e.key; const k = e.key;
if(k === "t") { if(k === "t") {

229
public/s/js/user.js Normal file
View File

@ -0,0 +1,229 @@
(async () => {
if(_addtag = document.querySelector("a#a_addtag")) {
const postid = +document.querySelector("a.id-link").innerText;
const poster = document.querySelector("a#a_username").innerText;
let tags = [...document.querySelectorAll("#tags > .badge")].map(t => t.innerText.slice(0, -2));
const queryapi = async (url, data, method = 'GET') => {
let req;
if(method == 'POST') {
req = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
}
else {
let s = [];
for(const [ key, val ] of Object.entries(data))
s.push(encodeURIComponent(key) + "=" + encodeURIComponent(val));
req = await fetch(url + '?' + s.join('&'));
}
return await req.json();
};
const get = async (url, data) => queryapi(url, data, 'GET');
const post = async (url, data) => queryapi(url, data, 'POST');
const renderTags = _tags => {
[...document.querySelectorAll("#tags > .badge")].forEach(tag => tag.parentElement.removeChild(tag));
_tags.reverse().forEach(tag => {
const a = document.createElement("a");
a.href = `/tag/${tag.normalized}`;
a.style = "color: inherit !important";
a.innerHTML = tag.tag;
const span = document.createElement("span");
span.classList.add("badge", "mr-2");
span.setAttribute('tooltip', tag.user);
tag.badge.split(" ").forEach(b => span.classList.add(b));
span.insertAdjacentElement("beforeend", a);
document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
});
};
const addtagClick = (ae = false) => {
if(ae)
ae.preventDefault();
const insert = document.querySelector("a#a_addtag");
const span = document.createElement("span");
span.classList.add("badge", "badge-light", "mr-2");
const input = document.createElement("input");
input.size = "10";
input.value = "";
input.setAttribute("list", "testlist");
input.setAttribute("autoComplete", "off");
span.insertAdjacentElement("afterbegin", input);
insert.insertAdjacentElement("beforebegin", span);
input.focus();
let tt = null;
let lastInput = '';
const testList = document.querySelector('#testlist');
input.addEventListener("keyup", async e => {
if(e.key === "Enter") {
const tmptag = input.value?.trim();
if(tags.includes(tmptag))
return alert("tag already exists");
const res = await post("/api/v2/admin/" + postid + "/tags", {
tagname: tmptag
});
if(!res.success) {
alert(res.msg);
return false;
}
tags = res.tags.map(t => t.tag);
renderTags(res.tags);
addtagClick();
testList.innerText = "";
}
else if(e.key === "Escape") {
span.parentElement.removeChild(span);
testList.innerText = "";
}
else {
if(tt != null)
clearTimeout(tt);
tt = setTimeout(async () => {
tt = null;
const tmptag = input.value?.trim();
if(tmptag == lastInput || tmptag.length <= 1)
return false;
testList.innerText = "";
lastInput = tmptag;
const res = await get('/api/v2/admin/tags/suggest', {
q: tmptag
});
for(const entry of res.suggestions) {
const option = document.createElement('option');
option.value = entry.tag;
if(!/fox/.test(navigator.userAgent))
option.innerText = `tagged ${entry.tagged} times (score: ${entry.score.toFixed(2)})`;
testList.insertAdjacentElement('beforeEnd', option);
};
}, 500);
}
return true;
});
input.addEventListener("focusout", ie => {
if(input.value.length === 0)
input.parentElement.parentElement.removeChild(input.parentElement);
});
};
const toggleEvent = async (e = false) => {
if(e)
e.preventDefault();
const res = await (await fetch('/api/v2/admin/' + encodeURIComponent(postid) + '/tags/toggle', {
method: 'PUT'
})).json();
renderTags(res.tags);
};
const toggleFavEvent = async e => {
const res = await post('/api/v2/admin/togglefav', {
postid: postid
});
if(res.success) {
const fav = document.querySelector("svg#a_favo > use").href;
fav.baseVal = '/s/img/iconset.svg#heart_' + (fav.baseVal.match(/heart_(regular|solid)$/)[1] == "solid" ? "regular" : "solid");
// span#favs
const favcontainer = document.querySelector('span#favs');
favcontainer.innerHTML = "";
favcontainer.hidden = !(favcontainer.hidden || res.favs.length > 0);
res.favs.forEach(f => {
const a = document.createElement('a');
a.href = `/user/${f.user}/favs`;
a.setAttribute('tooltip', f.user);
a.setAttribute('flow', 'up');
const img = document.createElement('img');
img.src = `/t/${f.avatar}.webp`;
img.style.height = "32px";
img.style.width = "32px";
a.insertAdjacentElement('beforeend', img);
favcontainer.insertAdjacentElement('beforeend', a);
favcontainer.innerHTML += "&nbsp;";
});
}
else {
// lul
}
};
_addtag.addEventListener("click", addtagClick);
document.querySelector("a#a_toggle").addEventListener("click", toggleEvent);
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);
document.addEventListener("keyup", e => {
if(e.target.tagName === "INPUT")
return;
if(e.key === "p")
toggleEvent();
else if(e.key === "i")
addtagClick();
else if(e.key === "x")
deleteButtonEvent();
else if(e.key === "f")
toggleFavEvent();
});
}
if(document.location.pathname === '/settings') {
const saveAvatar = async e => {
e.preventDefault();
const avatar = +document.querySelector('input[name="i_avatar"]').value;
let res = await fetch('/api/v2/settings/setAvatar', {
method: 'PUT',
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ avatar })
});
const code = res.status;
res = await res.json();
switch(code) {
case 200:
document.querySelector('#img_avatar').src = `/t/${avatar}.webp`;
document.querySelector('img.avatar').src = `/t/${avatar}.webp`;
break;
default:
console.log(res);
break;
}
};
document.querySelector('input#s_avatar').addEventListener('click', saveAvatar);
document.querySelector('input[name="i_avatar"]').addEventListener('keyup', async e => {
if(e.key === 'Enter')
await saveAvatar(e);
});
}
})();

View File

@ -1,4 +1,4 @@
import _config from "../../config.json" assert { type: "json" }; import _config from "../../config.json" with { type: "json" };
let config = JSON.parse(JSON.stringify(_config)); let config = JSON.parse(JSON.stringify(_config));

View File

@ -134,15 +134,6 @@ export default new class {
const derivedKey = await scrypt(str, salt, 64); const derivedKey = await scrypt(str, salt, 64);
return crypto.timingSafeEqual(keyBuffer, derivedKey); return crypto.timingSafeEqual(keyBuffer, derivedKey);
}; };
async auth(req, res, next) {
if(!req.session) {
return res.reply({
code: 401,
body: "401 - Unauthorized"
});
}
return next();
};
async getTags(itemid) { async getTags(itemid) {
const tags = await db` const tags = await db`
select "tags".id, "tags".tag, "tags".normalized, "user".user select "tags".id, "tags".tag, "tags".normalized, "user".user
@ -217,6 +208,27 @@ export default new class {
TABLE_NAME='user_options' and TABLE_NAME='user_options' and
COLUMN_NAME = 'avatar' COLUMN_NAME = 'avatar'
`)[0].avatar; `)[0].avatar;
} };
// meddlware
async auth(req, res, next) {
if(!req.session || !req.session.admin) {
return res.reply({
code: 401,
body: "401 - Unauthorized"
});
}
return next();
};
async loggedin(req, res, next) {
if(!req.session) {
return res.reply({
code: 401,
body: "401 - Unauthorized"
});
}
return next();
};
}; };

View File

@ -62,7 +62,7 @@ export default new class queue {
if(mime.startsWith('video/') || mime == 'image/gif') if(mime.startsWith('video/') || mime == 'image/gif')
await this.exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./tmp/${itemid}.png`); await this.exec(`ffmpegthumbnailer -i./public/b/${filename} -s1024 -o./tmp/${itemid}.png`);
else if(mime.startsWith('image/') && mime != 'image/gif') else if(mime.startsWith('image/') && mime != 'image/gif')
await this.exec(`convert "./public/b/${filename}[0]" ./tmp/${itemid}.png`); await this.exec(`magick "./public/b/${filename}[0]" ./tmp/${itemid}.png`);
else if(mime.startsWith('audio/')) { else if(mime.startsWith('audio/')) {
if(link.match(/soundcloud/)) { if(link.match(/soundcloud/)) {
let cover = (await this.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' --get-thumbnail "${link}"`)).stdout.trim(); let cover = (await this.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' --get-thumbnail "${link}"`)).stdout.trim();
@ -72,23 +72,23 @@ export default new class queue {
await this.exec(`wget "${cover}" -O ./tmp/${itemid}.jpg`); await this.exec(`wget "${cover}" -O ./tmp/${itemid}.jpg`);
const size = (await fs.promises.stat(`./tmp/${itemid}.jpg`)).size; const size = (await fs.promises.stat(`./tmp/${itemid}.jpg`)).size;
if(size >= 0) { if(size >= 0) {
await this.exec(`convert ./tmp/${itemid}.jpg ./tmp/${itemid}.png`); await this.exec(`magick ./tmp/${itemid}.jpg ./tmp/${itemid}.png`);
await this.exec(`convert ./tmp/${itemid}.jpg ./public/ca/${itemid}.webp`); await this.exec(`magick ./tmp/${itemid}.jpg ./public/ca/${itemid}.webp`);
} }
} catch(err) {} } catch(err) {}
} }
else { else {
await this.exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`); await this.exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`);
await this.exec(`convert ./tmp/${itemid}.png ./public/ca/${itemid}.webp`); await this.exec(`magick ./tmp/${itemid}.png ./public/ca/${itemid}.webp`);
} }
} }
else { else {
await this.exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`); await this.exec(`ffmpeg -i ./public/b/${filename} -update 1 -map 0:v -map 0:1 -c copy ./tmp/${itemid}.png`);
await this.exec(`convert ./tmp/${itemid}.png ./public/ca/${itemid}.webp`); await this.exec(`magick ./tmp/${itemid}.png ./public/ca/${itemid}.webp`);
} }
} }
await this.exec(`convert "./tmp/${itemid}.png" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.webp`); await this.exec(`magick "./tmp/${itemid}.png" -resize "128x128^" -gravity center -crop 128x128+0+0 +repage ./public/t/${itemid}.webp`);
await fs.promises.unlink(`./tmp/${itemid}.png`).catch(_=>{}); await fs.promises.unlink(`./tmp/${itemid}.png`).catch(_=>{});
await fs.promises.unlink(`./tmp/${itemid}.jpg`).catch(_=>{}); await fs.promises.unlink(`./tmp/${itemid}.jpg`).catch(_=>{});
return true; return true;

View File

@ -7,12 +7,13 @@ import url from "url";
const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or '); const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ');
export default { export default {
getf0cks: async (o = { user, tag, mime, page, mode, fav, session }) => { getf0cks: async (o = { user, tag, mime, page, mode, fav, session, limit }) => {
const user = o.user ? decodeURI(o.user) : null; const user = o.user ? decodeURI(o.user) : null;
const tag = lib.parseTag(o.tag ?? null); const tag = lib.parseTag(o.tag ?? null);
const mime = o.mime ?? null; const mime = o.mime ?? null;
const page = +(o.page ?? 1); const page = +(o.page ?? 1);
const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%"; const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%";
const eps = o.limit ?? cfg.websrv.eps;
const tmp = { user, tag, mime, smime, page, mode: o.mode }; const tmp = { user, tag, mime, smime, page, mode: o.mode };
const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0); const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
@ -70,7 +71,7 @@ export default {
group by items.id, tags.tag, ta.tag_id group by items.id, tags.tag, ta.tag_id
order by items.id desc order by items.id desc
offset ${offset} offset ${offset}
limit ${cfg.websrv.eps} limit ${eps}
`; `;
const cheat = []; const cheat = [];
@ -165,7 +166,7 @@ export default {
success: true, success: true,
user: { user: {
name: actitem.username, name: actitem.username,
channel: actitem.usernetwork == "Telegram" && actitem.userchannel !== "f0ck.me" ? "anonymous" : actitem.userchannel, channel: actitem.usernetwork == "Telegram" && actitem.userchannel !== "w0bm.com" ? "anonymous" : actitem.userchannel,
network: actitem.usernetwork network: actitem.usernetwork
}, },
item: { item: {
@ -186,7 +187,7 @@ export default {
favorites: favorites, favorites: favorites,
tags: tags tags: tags
}, },
title: `${actitem.id} - f0ck.me`, title: `${actitem.id} - w0bm.com`,
pagination: { pagination: {
end: items[items.length - 1]?.id, end: items[items.length - 1]?.id,
start: items[0]?.id, start: items[0]?.id,
@ -200,49 +201,65 @@ export default {
tmp tmp
}; };
return data; return data;
}, },getRandom: async (o = ({ user, tag, mime, mode, fav, session })) => {
getRandom: async (o = ({ user, tag, mime, mode, session })) => { const user = o.user ? decodeURI(o.user) : null;
const user = o.user ? decodeURI(o.user) : null; const tag = lib.parseTag(o.tag ?? null);
const tag = lib.parseTag(o.tag ?? null); const mime = (o.mime ?? "");
const mime = (o.mime ?? ""); const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%";
const smime = cfg.allowedMimes.includes(mime) ? mime + "/%" : mime === "" ? "%" : "%";
const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0); const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
const item = await db` let item;
select
items.id if (o.fav && user) {
from items // Special case: random from user's favorites
left join tags_assign on tags_assign.item_id = items.id item = await db`
left join tags on tags.id = tags_assign.tag_id select
left join favorites on favorites.item_id = items.id items.id
left join "user" on "user".id = favorites.user_id from favorites
where inner join items on favorites.item_id = items.id
${ db.unsafe(modequery) } inner join "user" on "user".id = favorites.user_id
and items.active = 'true' where
${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` } "user".user ilike ${'%' + user + '%'}
${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` } and items.active = 'true'
${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` } ${mime ? db`and items.mime ilike ${smime}` : db``}
${ mime ? db`and items.mime ilike ${smime}` : db`` } order by random()
${ !o.session && globalfilter ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` } limit 1
group by items.id, tags.tag `;
order by random() } else {
limit 1 // Normal random logic
`; item = await db`
select
if(item.length === 0) { 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
where
${db.unsafe(modequery)}
and items.active = 'true'
${tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db``}
${user ? db`and items.username ilike ${'%' + user + '%'}` : db``}
${mime ? db`and items.mime ilike ${smime}` : db``}
${!o.session && globalfilter ? 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 { return {
success: false, success: false,
message: "no f0cks found :(" message: "no f0cks found :("
}; };
} }
const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks' }); const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks' });
return { return {
success: true, success: true,
link: link, link: link,
itemid: item[0].id itemid: item[0].id
}; };
} }
}; };

View File

@ -3,18 +3,7 @@ import lib from "../lib.mjs";
import { exec } from "child_process"; import { exec } from "child_process";
import { promises as fs } from "fs"; import { promises as fs } from "fs";
const auth = async (req, res, next) => {
if(!req.session) {
return res.reply({
code: 401,
body: "401 - Unauthorized"
});
}
return next();
};
export default (router, tpl) => { export default (router, tpl) => {
router.get(/^\/login(\/)?$/, async (req, res) => { router.get(/^\/login(\/)?$/, async (req, res) => {
if(req.cookies.session) { if(req.cookies.session) {
return res.reply({ return res.reply({
@ -72,7 +61,7 @@ export default (router, tpl) => {
}).end(); }).end();
}); });
router.get(/^\/logout$/, auth, async (req, res) => { router.get(/^\/logout$/, lib.loggedin, async (req, res) => {
const usersession = await db` const usersession = await db`
select * select *
from "user_sessions" from "user_sessions"
@ -103,7 +92,7 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/admin(\/)?$/, auth, async (req, res) => { // frontpage router.get(/^\/admin(\/)?$/, lib.auth, async (req, res) => { // frontpage
res.reply({ res.reply({
body: tpl.render("admin", { body: tpl.render("admin", {
@ -114,7 +103,7 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/admin\/sessions(\/)?$/, auth, async (req, res) => { router.get(/^\/admin\/sessions(\/)?$/, lib.auth, async (req, res) => {
const rows = await db` const rows = await db`
select "user_sessions".*, "user".user select "user_sessions".*, "user".user
from "user_sessions" from "user_sessions"
@ -132,77 +121,79 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/admin\/log(\/)?$/, auth, async (req, res) => { // router.get(/^\/admin\/log(\/)?$/, lib.auth, async (req, res) => {
exec("journalctl -qeu f0ck --no-pager", (err, stdout) => { // // Funktioniert ohne systemd service natürlich nicht.
res.reply({ // exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
body: tpl.render("admin/log", { // res.reply({
log: stdout.split("\n").slice(0, -1), // body: tpl.render("admin/log", {
tmp: null // log: stdout.split("\n").slice(0, -1),
}, req) // tmp: null
}); // }, req)
}); // });
}); // });
// });
router.get(/^\/admin\/recover\/?/, auth, async (req, res) => { // router.get(/^\/admin\/recover\/?/, lib.auth, async (req, res) => {
if(req.url.qs?.id) { // Gelöschte Objekte werden nicht aufgehoben.
const id = +req.url.qs.id; // if(req.url.qs?.id) {
const f0ck = await db` // const id = +req.url.qs.id;
select dest, mime // const f0ck = await db`
from "items" // select dest, mime
where // from "items"
id = ${id} and // where
active = 'false' // id = ${id} and
limit 1 // active = 'false'
`; // limit 1
if(f0ck.length === 0) { // `;
return res.reply({ // if(f0ck.length === 0) {
body: `f0ck ${id}: f0ck not found` // return res.reply({
}); // body: `f0ck ${id}: f0ck not found`
} // });
// }
await db`update "items" set active = 'true' where id = ${id}`; // await db`update "items" set active = 'true' where id = ${id}`;
await fs.copyFile(`./deleted/b/${f0ck[0].dest}`, `./public/b/${f0ck[0].dest}`).catch(_=>{}); // await fs.copyFile(`./deleted/b/${f0ck[0].dest}`, `./public/b/${f0ck[0].dest}`).catch(_=>{});
await fs.copyFile(`./deleted/t/${id}.webp`, `./public/t/${id}.webp`).catch(_=>{}); // await fs.copyFile(`./deleted/t/${id}.webp`, `./public/t/${id}.webp`).catch(_=>{});
await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(_=>{}); // await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(_=>{});
await fs.unlink(`./deleted/t/${id}.webp`).catch(_=>{}); // await fs.unlink(`./deleted/t/${id}.webp`).catch(_=>{});
if(f0ck[0].mime.startsWith('audio')) { // if(f0ck[0].mime.startsWith('audio')) {
await fs.copyFile(`./deleted/ca/${id}.webp`, `./public/ca/${id}.webp`).catch(_=>{}); // await fs.copyFile(`./deleted/ca/${id}.webp`, `./public/ca/${id}.webp`).catch(_=>{});
await fs.unlink(`./deleted/ca/${id}.webp`).catch(_=>{}); // await fs.unlink(`./deleted/ca/${id}.webp`).catch(_=>{});
} // }
return res.reply({ // return res.reply({
body: `f0ck ${id} recovered. <a href="/admin/recover">back</a>` // body: `f0ck ${id} recovered. <a href="/admin/recover">back</a>`
}); // });
} // }
const _posts = await db` // const _posts = await db`
select id, mime, username // select id, mime, username
from "items" // from "items"
where // where
active = 'false' // active = 'false'
order by id desc // order by id desc
`; // `;
if(_posts.length === 0) { // if(_posts.length === 0) {
return res.reply({ // return res.reply({
body: 'blah' // body: 'blah'
}); // });
} // }
const posts = await Promise.all(_posts.map(async p => ({ // const posts = await Promise.all(_posts.map(async p => ({
...p, // ...p,
thumbnail: (await fs.readFile(`./deleted/t/${p.id}.webp`)).toString('base64') // thumbnail: (await fs.readFile(`./deleted/t/${p.id}.webp`)).toString('base64')
}))); // })));
res.reply({ // res.reply({
body: tpl.render('admin/recover', { // body: tpl.render('admin/recover', {
posts, // posts,
tmp: null // tmp: null
}, req) // }, req)
}); // });
}); // });
return router; return router;
}; };

View File

@ -139,7 +139,7 @@ export default router => {
// tags lol // tags lol
group.put(/\/admin\/tags\/(?<tagname>.*)/, lib.auth, async (req, res) => { group.put(/\/admin\/tags\/(?<tagname>.*)/, lib.loggedin, async (req, res) => {
if(!req.params.tagname || !req.post.newtag) { if(!req.params.tagname || !req.post.newtag) {
return res.json({ return res.json({
success: false, success: false,
@ -187,7 +187,7 @@ export default router => {
return res.json(q, tagname === newtag ? 200 : 201); // created (modified) return res.json(q, tagname === newtag ? 200 : 201); // created (modified)
}); });
group.get(/\/admin\/tags\/suggest$/, lib.auth, async (req, res) => { group.get(/\/admin\/tags\/suggest$/, lib.loggedin, async (req, res) => {
const reply = { const reply = {
success: false, success: false,
suggestions: {} suggestions: {}
@ -267,7 +267,7 @@ export default router => {
}); });
}); });
group.post(/\/admin\/togglefav$/, lib.auth, async (req, res) => { group.post(/\/admin\/togglefav$/, lib.loggedin, async (req, res) => {
const postid = +req.post.postid; const postid = +req.post.postid;
let favs = await db` let favs = await db`

View File

@ -3,7 +3,7 @@ import lib from '../../lib.mjs';
export default router => { export default router => {
router.group(/^\/api\/v2\/settings/, group => { router.group(/^\/api\/v2\/settings/, group => {
group.put(/\/setAvatar/, lib.auth, async (req, res) => { group.put(/\/setAvatar/, lib.loggedin, async (req, res) => {
if(!req.post.avatar) { if(!req.post.avatar) {
return res.json({ return res.json({
msg: 'no avatar provided', msg: 'no avatar provided',

View File

@ -3,7 +3,7 @@ import lib from '../../lib.mjs';
export default router => { export default router => {
router.group(/^\/api\/v2\/admin\/(?<postid>\d+)\/tags/, group => { router.group(/^\/api\/v2\/admin\/(?<postid>\d+)\/tags/, group => {
group.get(/$/, lib.auth, async (req, res) => { group.get(/$/, lib.loggedin, async (req, res) => {
// get tags // get tags
if(!req.params.postid) { if(!req.params.postid) {
return res.json({ return res.json({
@ -18,7 +18,7 @@ export default router => {
}); });
}); });
group.post(/$/, lib.auth, async (req, res) => { group.post(/$/, lib.loggedin, async (req, res) => {
// assign and/or create tag // assign and/or create tag
if(!req.params.postid || !req.post.tagname) { if(!req.params.postid || !req.post.tagname) {
return res.json({ return res.json({
@ -80,7 +80,7 @@ export default router => {
}); });
}); });
group.put(/\/toggle$/, lib.auth, async (req, res) => { group.put(/\/toggle$/, lib.loggedin, async (req, res) => {
// xD // xD
if(!req.params.postid) { if(!req.params.postid) {
return res.json({ return res.json({
@ -131,13 +131,13 @@ export default router => {
const postid = +req.params.postid; const postid = +req.params.postid;
const tagname = decodeURIComponent(req.params.tagname); const tagname = decodeURIComponent(req.params.tagname);
if(tagname == 'sfw' || tagname == 'nsfw' || tagname == 'hentai' || tagname == 'audio') { // if(tagname == 'sfw' || tagname == 'nsfw' || tagname == 'hentai' || tagname == 'audio') {
return res.json({ // return res.json({
success: false, // success: false,
msg: 'blacklisted', // msg: 'blacklisted',
tags: await lib.getTags(postid) // tags: await lib.getTags(postid)
}); // });
} // }
const tags = await lib.getTags(postid); const tags = await lib.getTags(postid);

View File

@ -14,7 +14,7 @@ export default (router, tpl) => {
const user = decodeURIComponent(req.params.user); const user = decodeURIComponent(req.params.user);
const query = await db` const query = await db`
select "user".user, "user".created_at, user_options.* select "user".user, "user".admin, "user".created_at, user_options.*
from user_options from user_options
left join "user" on "user".id = user_options.user_id left join "user" on "user".id = user_options.user_id
where "user".user ilike ${user} where "user".user ilike ${user}
@ -31,31 +31,42 @@ export default (router, tpl) => {
}); });
} }
const f0cks = await f0cklib.getf0cks({ let f0cks, favs;
user: user,
mode: req.session.mode,
fav: false,
session: !!req.session
});
const favs = await f0cklib.getf0cks({
user: user,
mode: req.session.mode,
fav: true,
session: !!req.session
});
const count = { const count = {
f0cks: 0, f0cks: 0,
favs: 0 favs: 0
}; };
try {
if('items' in f0cks) { f0cks = await f0cklib.getf0cks({
count.f0cks = f0cks.items.length; user: user,
f0cks.items = f0cks.items.slice(0, 50); mode: req.session.mode,
fav: false,
session: !!req.session,
limit: 99999999
});
if('items' in f0cks) {
count.f0cks = f0cks.items.length;
f0cks.items = f0cks.items.slice(0, 50);
}
} catch(err) {
f0cks = false;
count.f0cks = 0;
} }
if('items' in favs) { try {
count.favs = favs.items.length; favs = await f0cklib.getf0cks({
favs.items = favs.items.slice(0, 50); user: user,
mode: req.session.mode,
fav: true,
session: !!req.session,
limit: 99999999
});
if('items' in favs) {
count.favs = favs.items.length;
favs.items = favs.items.slice(0, 50);
}
} catch(err) {
favs = false;
count.favs = 0;
} }
const data = { const data = {
@ -100,7 +111,13 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/mode\/(\d)/, auth, async (req, res) => { router.get(/^\/(terms)$/, (req, res) => {
res.reply({
body: tpl.render(req.url.split[0], { tmp: null }, req)
});
});
router.get(/^\/mode\/(\d)/, lib.loggedin, async (req, res) => {
const mode = +req.url.split[1]; const mode = +req.url.split[1];
let referertmp = req.headers.referer; let referertmp = req.headers.referer;
let referer = ""; let referer = "";

View File

@ -0,0 +1,26 @@
import db from "../../inc/sql.mjs";
import cfg from "../../inc/config.mjs";
import f0cklib from "../routeinc/f0cklib.mjs";
export default (router, tpl) => {
router.get(/^\/picdump$/, async (req, res) => {
const dump = await db`
SELECT *
FROM items
WHERE (
to_timestamp(stamp) >= date_trunc('week', CURRENT_TIMESTAMP - interval '1 week') AND
to_timestamp(stamp) < date_trunc('week', CURRENT_TIMESTAMP)
) AND
mime LIKE 'image/%'
ORDER BY stamp DESC
`;
res.reply({
body: tpl.render('picdump', {
dump,
tmp: null
}, req)
});
});
return router;
};

View File

@ -6,10 +6,14 @@ export default (router, tpl) => {
let referer = req.headers.referer ?? ''; let referer = req.headers.referer ?? '';
let opts = {}; let opts = {};
if(referer.match(new RegExp(cfg.main.url.regex))) { // parse referer if (referer.match(new RegExp(cfg.main.url.regex))) { // parse referer
referer = referer.split(cfg.main.url.domain)[1]; referer = referer.split(cfg.main.url.domain)[1];
console.log("referer: ", referer);
const tmp = referer.match(/^\/?(?:\/tag\/(?<tag>.+?))?(?:\/user\/(?<user>.+?)\/(?<mode>f0cks|favs))?(?:\/(?<mime>image|audio|video))?(?:\/p\/(?<page>\d+))?(?:\/(?<itemid>\d+))?$/); const tmp = referer.match(/^\/?(?:\/tag\/(?<tag>.+?))?(?:\/user\/(?<user>.+?)\/(?<mode>f0cks|favs))?(?:\/(?<mime>image|audio|video))?(?:\/p\/(?<page>\d+))?(?:\/(?<itemid>\d+))?$/);
if(tmp) console.log("tmp: ", tmp);
if (tmp && tmp.groups)
opts = tmp.groups; opts = tmp.groups;
} }
@ -18,12 +22,14 @@ export default (router, tpl) => {
tag: opts.tag, tag: opts.tag,
mime: opts.mime, mime: opts.mime,
page: opts.page, page: opts.page,
fav: opts.mode == 'favs', fav: opts.mode === 'favs',
mode: req.session.mode, mode: req.session.mode,
session: !!req.session session: !!req.session
}); });
if(!data.success) { console.log("data", data);
if (!data.success) {
return res.reply({ return res.reply({
code: 404, code: 404,
body: tpl.render('error', { body: tpl.render('error', {
@ -33,7 +39,8 @@ export default (router, tpl) => {
}); });
} }
res.redirect(`${data.link.main}${data.link.path}${data.itemid}`); res.redirect(encodeURI(`${data.link.main}${data.link.path}${data.itemid}`));
}); });
return router; return router;
}; };

View File

@ -8,13 +8,13 @@ export default (router, tpl) => {
try { try {
const list = await db` const list = await db`
select select
"user".user, "user".user, "user".admin,
coalesce("user_options".avatar, ${await lib.getDefaultAvatar()}) as avatar, coalesce("user_options".avatar, ${await lib.getDefaultAvatar()}) as avatar,
count(distinct(tag_id, item_id)) as count count(distinct(tag_id, item_id)) as count
from "tags_assign" from "tags_assign"
left join "user" on "user".id = "tags_assign".user_id left join "user" on "user".id = "tags_assign".user_id
left join "user_options" on "user_options".user_id = "user".id left join "user_options" on "user_options".user_id = "user".id
group by "user".user, "user_options".avatar group by "user".user, "user_options".avatar, "user".admin
order by count desc order by count desc
`; `;
const stats = await lib.countf0cks(); const stats = await lib.countf0cks();

View File

@ -5,7 +5,7 @@ import search from "../routeinc/search.mjs";
const _eps = 20; const _eps = 20;
export default (router, tpl) => { export default (router, tpl) => {
router.get(/^\/search(\/)?$/, lib.auth, async (req, res) => { router.get(/^\/search(\/)?$/, lib.loggedin, async (req, res) => {
let ret; let ret;
let tag = req.url.qs.tag ?? []; let tag = req.url.qs.tag ?? [];
let page = req.url.qs.page ?? 1; let page = req.url.qs.page ?? 1;

View File

@ -0,0 +1,42 @@
import db from "../../inc/sql.mjs";
import cfg from "../../inc/config.mjs";
export default (router, tpl) => {
router.get(/^\/tags$/, async (req, res) => {
const phrase = cfg.websrv.phrases[~~(Math.random() * cfg.websrv.phrases.length)];
const nsfp = cfg.nsfp.map(n => `${n}`);
const toptags = await db`
SELECT t.id, t.tag, COUNT(DISTINCT ta.item_id) AS total_items
FROM tags t
LEFT JOIN tags_assign ta ON t.id = ta.tag_id
WHERE t.id not in (${db.unsafe(nsfp)})
GROUP BY t.id, t.tag
ORDER BY total_items DESC
LIMIT 500
;
`;
const toptags_regged = await db`
SELECT t.id, t.tag, COUNT(DISTINCT ta.item_id) AS total_items
FROM tags t
LEFT JOIN tags_assign ta ON t.id = ta.tag_id
GROUP BY t.id, t.tag
ORDER BY total_items DESC
LIMIT 500
;
`;
res.reply({
body: tpl.render('tags', {
toptags,
toptags_regged,
phrase,
tmp: null
}, req)
});
});
return router;
};

View File

@ -2,7 +2,7 @@ import cfg from "../config.mjs";
import db from "../sql.mjs"; import db from "../sql.mjs";
import lib from "../lib.mjs"; import lib from "../lib.mjs";
const regex = /(https\:\/\/f0ck\.me|http\:\/\/fockmoonsb24iczs7odozzy5uktlzbcgp337nabrgffzxv5ihabgpvyd\.onion)(\/(video|image|audio))?\/(\d+|(?:b\/)(\w{8})\.(jpg|webm|gif|mp4|png|mov|mp3|ogg|flac))/gi; const regex = /(https\:\/\/w0bm\.com)(\/(video|image|audio))?\/(\d+|(?:b\/)(\w{8})\.(jpg|webm|gif|mp4|png|mov|mp3|ogg|flac))/gi;
export default async bot => { export default async bot => {

View File

@ -11,7 +11,7 @@ import path from "path";
const regex = { const regex = {
all: /https?:\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/gi, all: /https?:\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?/gi,
yt: /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\/?\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})/gi, yt: /(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\/?\?(?:\S*?&?v\=))|youtu\.be\/)([a-zA-Z0-9_-]{6,11})/gi,
imgur: /(?:https?:)?\/\/(\w+\.)?imgur\.com\/(\S*)(\.[a-zA-Z]{3})/gm, imgur: /(?:https?:)?\/\/(\w+\.)?imgur\.com\/(\S*)(\..{3,4})/i,
instagram: /(?:https?:\/\/www\.)?instagram\.com\S*?\/(?:p|reel)\/(\w{11})\/?/im instagram: /(?:https?:\/\/www\.)?instagram\.com\S*?\/(?:p|reel)\/(\w{11})\/?/im
}; };
const mediagroupids = new Set(); const mediagroupids = new Set();
@ -34,7 +34,7 @@ export default async bot => {
if(e.message.match(/\!i(gnore)?\b/)) if(e.message.match(/\!i(gnore)?\b/))
return false; return false;
if(!e.channel.includes("f0ck") && (!e.message.match(/\!f(0ck)?\b/i) && (typeof e.raw.forward_from == 'undefined'))) if(!e.channel.includes("f0bm") && (!e.message.match(/\!f(0ck)?\b/i) && (typeof e.raw.forward_from == 'undefined')))
return false; return false;
if(e.type === 'tg' && // proto: tg if(e.type === 'tg' && // proto: tg
@ -51,11 +51,14 @@ export default async bot => {
console.log(`parsing ${links.length} link${links.length > 1 ? "s" : ""}...`); console.log(`parsing ${links.length} link${links.length > 1 ? "s" : ""}...`);
links.forEach(async link => { links.forEach(async link => {
if(regex.imgur.test(link)) //if(regex.imgur.test(link))
await e.reply(`imgur schmimigur`); // return await e.reply(`fuck imgur... seriously`);
if(regex.instagram.test(link)) if(regex.instagram.test(link))
await e.reply(`insta schminsta`); await e.reply(`instagay`);
if(regex.yt.test(link))
await e.reply(`hi yt here, I am gay this is why I am not giving you the file`);
// check repost (link) // check repost (link)
repost = await queue.checkrepostlink(link); repost = await queue.checkrepostlink(link);
@ -69,16 +72,21 @@ export default async bot => {
// read metadata // read metadata
let ext; let ext;
if(regex.imgur.test(link)) { if(link.match(regex.instagram)) {
// is imgur // is instagram
try { try {
// will die extension von der url // @flummi -> is there a variable for the actual work directory so it doesn't have to be hardcoded?
ext = link.split(".").slice(-1).join("."); const meta = JSON.parse((await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' --skip-download --dump-json "${link}"`)).stdout);
ext = meta.ext;
} catch(err) { } catch(err) {
const tmphead = (await fetch(link, { method: "HEAD" })).headers["content-type"]; const tmphead = (await fetch(link, { method: "HEAD" })).headers["content-type"];
// this can be undefined for unsupported mime types, but will be caught in the general mime check below // this can be undefined for unsupported mime types, but will be caught in the general mime check below
ext = cfg.mimes[tmphead]; ext = cfg.mimes[tmphead];
} }
}
else if(link.match(regex.imgur)) {
// imghure
ext = link.split('.').pop();
} }
else { else {
// is not instagram // is not instagram
@ -100,53 +108,54 @@ export default async bot => {
disable_notification: true disable_notification: true
}); });
// download data // <download data>
const start = new Date(); const start = new Date();
let source; let source;
try { if(link.match(regex.instagram)) {
if(regex.instagram.test(link)) try {
try { // add --cookies <path-to-cookies-file> on local instance if you want to avoid getting rate limited
// add --cookies <path-to-cookies-file> on local instance if you want to avoid getting rate limited source = (await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim();
source = (await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim(); } catch(err) {
} catch(err) { if(e.type == 'tg')
if(e.type == 'tg') return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "instagram dl error");
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "instagram dl error"); return await e.reply("instagram dl error", err);
return await e.reply("instagram dl error", err);
}
else if(regex.imgur.test(link)) {
console.log("penis123");
try {
await queue.exec(`torsocks wget "${link}" -O "./tmp/${uuid}.${ext}"`);
source = "./tmp/"+uuid+"."+ext;
console.log(source);
} catch(err) {
console.log(err);
}
}
else
{
try {
source = (await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim();
} catch(err) {
if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, err);
return await e.reply(err);
}
} }
} catch(err) {
console.log(err);
} }
else if(link.match(regex.imgur)) {
// imghure via torsocks
try {
await queue.exec(`torsocks wget ${link} -O ./tmp/${uuid}.${ext}`);
source = `./tmp/${uuid}.${ext}`;
} catch(err) {
console.error('err:', err);
if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, err);
return await e.reply('something went wrong lol');
}
}
else if(link.match(regex.yt)) {
try {
// add --cookies <path-to-cookies-file> on local instance if you want to avoid getting rate limited
source = (await queue.exec(`yt-dlp --cookies /tmp/cookies.txt -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim();
} catch(err) {
if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "yt dl error");
return await e.reply("yt dl error", err);
}
}
else {
try {
source = (await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim();
} catch(err) {
console.error('err:', err);
if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, err);
return await e.reply('something went wrong lol / check maxfilesize?');
}
}
// </download data>
// this is how it was before I fucked it up :>
// try {
// source = (await queue.exec(`yt-dlp -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' "${link}" --max-filesize ${maxfilesize / 1024}k --postprocessor-args "ffmpeg:-bitexact" -o "./tmp/${uuid}.%(ext)s" --print after_move:filepath --merge-output-format "mp4"`)).stdout.trim();
// } catch(err) {
// if(e.type == 'tg')
// return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "something went wrong lol");
// return await e.reply("something went wrong lol");
// }
if(!source) { if(!source) {
if(e.type == 'tg') if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "something went wrong lol"); return await e.editMessageText(msg.result.chat.id, msg.result.message_id, "something went wrong lol");
@ -215,6 +224,19 @@ export default async bot => {
await fs.promises.copyFile(source, `./public/b/${filename}`); await fs.promises.copyFile(source, `./public/b/${filename}`);
await fs.promises.unlink(source).catch(_=>{}); await fs.promises.unlink(source).catch(_=>{});
// user alias
let username = e.user.nick || e.user.username;
const alias = (await db`
select "user"."user"
from "user_alias"
join "user" on "user".id = user_alias.userid
where lower(user_alias.alias) ilike ${username}
limit 1
`)?.[0]?.user;
if(alias) {
username = alias;
}
await db` await db`
insert into items ${ insert into items ${
db({ db({
@ -223,7 +245,7 @@ export default async bot => {
mime: mime, mime: mime,
size: size, size: size,
checksum: checksum, checksum: checksum,
username: e.user.nick || e.user.username, username: username,
userchannel: e.channel, userchannel: e.channel,
usernetwork: e.network, usernetwork: e.network,
stamp: ~~(new Date() / 1000), stamp: ~~(new Date() / 1000),
@ -238,7 +260,7 @@ export default async bot => {
try { try {
await queue.genThumbnail(filename, mime, itemid, link); await queue.genThumbnail(filename, mime, itemid, link);
} catch(err) { } catch(err) {
await queue.exec(`convert ./mugge.png ./public/t/${itemid}.webp`); await queue.exec(`magick ./mugge.png ./public/t/${itemid}.webp`);
} }
let speed = lib.calcSpeed(size, end); let speed = lib.calcSpeed(size, end);

View File

@ -66,12 +66,12 @@ process.on('unhandledRejection', err => {
req.session = false; req.session = false;
if(req.url.pathname.match(/^\/(s|b|t|ca)\//)) if(req.url.pathname.match(/^\/(s|b|t|ca)\//))
return; return;
req.theme = req.cookies.theme || 'f0ck'; req.theme = req.cookies.theme || 'atmos';
req.fullscreen = req.cookies.fullscreen || 0; req.fullscreen = req.cookies.fullscreen || 0;
if(req.cookies.session) { if(req.cookies.session) {
const user = await db` const user = await db`
select "user".id, "user".login, "user".user, "user".level, "user_sessions".id as sess_id, "user_options".* select "user".id, "user".login, "user".user, "user".admin, "user_sessions".id as sess_id, "user_options".*
from "user_sessions" from "user_sessions"
left join "user" on "user".id = "user_sessions".user_id left join "user" on "user".id = "user_sessions".user_id
left join "user_options" on "user_options".user_id = "user_sessions".user_id left join "user_options" on "user_options".user_id = "user_sessions".user_id
@ -110,7 +110,7 @@ process.on('unhandledRejection', err => {
db({ db({
user_id: +user[0].id, user_id: +user[0].id,
mode: user[0].mode ?? 0, mode: user[0].mode ?? 0,
theme: req.session.theme ?? 'f0ck', theme: req.session.theme ?? 'atmos',
fullscreen: req.session.fullscreen || 0 fullscreen: req.session.fullscreen || 0
}, 'user_id', 'mode', 'theme', 'fullscreen') }, 'user_id', 'mode', 'theme', 'fullscreen')
} }

View File

@ -1,51 +1,13 @@
@include(snippets/header) @include(snippets/header)
<div id="main"> <div id="main">
<div class="about"> <div class="about">
<div> <p>Welcome stranger!</p>
<a href="//f0ck.me/48908"><img src="//f0ck.me/s/img/loool.webp" /></a> <p>bringing you some of the greatest webms from the past, the present and the future!</p>
<p>thanks to our turkish fellow lol@n0xy/#f0ck for this gif &lt;3</p> <p>Enjoy your stay.</p>
</div> <img style="width: 200px" src="/s/img/cockfag.png" alt="cockfag">
<h5>f0ck Contact</h5> <p>If you have any questions you can reach out via Mail.</p>
<p>Whatever it is, we might have a answer, even though it might not be the one you were looking for: <a href="mailto:admin@f0ck.me">admin@f0ck.me</a></p> <p>mail: admin@w0bm.com</p>
<h5>About f0ck</h5> <p>Please also make yourself familiar with the <a href="/terms">Terms Of Service</a></p>
<p>f0ck is your friendly IRC shitposting bot, it's built for catching urls that are passed to it and displays the content of passed urls on a simple and accessible web gallery reachable at <a href="/">f0ck.me</a></p> </div>
<h5>WTF is a f0ck?</h5>
<p>A f0ck is basically giving a fuck about some internet bullshit, like stupid images, videos and so on, but also for great things like good music taste and shit, it's basically "a f0ck was given" and f0ck and it's users gave a lot of f0cks over the past years, it's not hard to finally start giving a damn f0ck about something, just f0ck it dood!</p>
<h5>Where to f0ck?</h5>
<h4>#f0ck on n0xy.net</h4>
<p>You can invite f0ck to your channel on the following supported networks by simply typing<br><code>/invite f0ck</code></p>
<ul>
<li><a href="https://n0xy.net">n0xy.net</a></li>
<li><a href="https://www.rizon.net/">rizon.net</a></li>
<li><a href="https://libera.chat/">libera.chat</a></li>
</ul>
<p>To start f0cking the shit out of something simply add a <code>!f0ck</code> behind the url you want to f0ck, that's it</p>
<p>#f0ck specific: to have f0ck ignore a link add <code>!ignore</code> at the end <br>Example: <a href="https://www.youtube.com/watch?v=dQw4w9WgXcQ" target="_blank">https://www.youtube.com/watch?v=dQw4w9WgXcQ</a> !ignore</p>
<p>f0ck supports a variety of websites, in fact all websites supported by <code>yt-dlp</code> are supported by f0ck aswell!</p>
<h5>f0ck Rules</h5>
<ul>
<li>You must be 18 years or older to visit or post</li>
<li>You shall not post animal cruelty, we like our animals alive and well, living a happy life until they are ready for our Schnitzel!</li>
<li>You shall not post under <b>ANY</b> circumstances: Snuff, Beastiality, Rape, Terrorist stuff (Beheadings, First person shootings, warcrimes), Childporn, Childmodeling</li>
</ul>
<h5>f0cked up?</h5>
<p>To have something removed in case you accidentally f0cked something that actually shouldn't be f0cked you can always contact the admins either via IRC or Email</p>
<ul>
<li>irc.n0xy.net #f0ck</li>
<li>admin@f0ck.me</li>
</ul>
<h5>Compatibility</h5>
<p>f0ck is developed and tested for Firefox and Chromium in their latest versions</p>
<p>If you encounter bugs please report them so we can fix them.</p>
<p>Microsoft Edgy is not actively supported, but if it werks, great! Same for anything apple related.</p>
<h5>Tinfoil f0ckers listen!</h5>
<p>f0ck onions and moons, but fockulite!</p>
<p>http://fockmoonsb24iczs7odozzy5uktlzbcgp337nabrgffzxv5ihabgpvyd.onion</p>
<p>http://fockulite74atso2xsxxw6q2gzqrgck572tiwvkyf5vdxictjn2vmlyd.onion</p>
<p>f0ck is completely functional without javascript enabled, you can be the beardiest neckbeard of all, we got you m'gentleman, if you want to use a custom theme you gotta allow our style cookie.</p>
<h5>f0ck Privacy?</h5>
<p>Cookies: Yes, we set 1 cookie for your prefered stylesheet, this is a optional cookie and not required for the site to function, simply cosmetics, you can block this cookie and the site will still work as intended and will default to the default f0ck theme called "f0ck"</p>
<p>Logs: We do not log users accessing our website.</p>
</div>
</div> </div>
@include(snippets/footer) @include(snippets/footer)

View File

@ -12,8 +12,8 @@
<div class="admintools"> <div class="admintools">
<p>Adminwerkzeuge</p> <p>Adminwerkzeuge</p>
<ul> <ul>
<li><a href="/admin/log">Logs</a></li> <!-- <li><a href="/admin/log">Logs</a></li>
<li><a href="/admin/recover">Recover f0cks</a></li> <li><a href="/admin/recover">Recover f0cks</a></li> -->
<li><a href="/admin/sessions">Sessions</a></li> <li><a href="/admin/sessions">Sessions</a></li>
</ul> </ul>
</div> </div>

View File

@ -2,7 +2,7 @@
<div class="pagewrapper"> <div class="pagewrapper">
<div id="main"> <div id="main">
<div class="index-container"> <div class="index-container">
@if(tmp.user)<h2>user: {!! tmp.user.toLowerCase() !!}@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif @if(tmp.user)<h2>user: <a href="/user/{{ tmp.user.toLowerCase() }}">{!! tmp.user.toLowerCase() !!}</a>@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
@if(tmp.tag)<h2>tag: @if(session)<a href="/search?tag={!! tmp.tag.toLowerCase() !!}" target="_blank">{!! tmp.tag.toLowerCase() !!}</a>@else{!! tmp.tag.toLowerCase() !!}@endif@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif @if(tmp.tag)<h2>tag: @if(session)<a href="/search?tag={!! tmp.tag.toLowerCase() !!}" target="_blank">{!! tmp.tag.toLowerCase() !!}</a>@else{!! tmp.tag.toLowerCase() !!}@endif@if(tmp.mime) ({{ tmp.mime }}s)@else (all)@endif</h2>@endif
<div class="posts"> <div class="posts">
@each(items as item) @each(items as item)
@ -15,4 +15,4 @@
</div> </div>
</div> </div>
</div> </div>
@include(snippets/footer) @include(snippets/footer)

View File

@ -2,19 +2,16 @@
<canvas class="hidden-xs" id="bg"></canvas> <canvas class="hidden-xs" id="bg"></canvas>
<div class="wrapper"> <div class="wrapper">
<div id="main"> <div id="main">
<div class="container"> <div class="container">
<div class="_204863"> <div class="_204863">
<div class="imageDoor" style="--hover-image: url('/t/{{ item.id }}.webp');"> <div class="imageDoor"></div>
<img src="/t/{{ item.id }}.webp" alt="" /> <div class="gapLeft"></div>
</div>
<div class="gapLeft">
<span class="populateME"><b>f0ck</b> - {{ item.id }}</span>
</div>
@if(session) @if(session)
<div class="gapRight"> <div class="gapRight">
<svg class="iconset" id="a_favo"><use href="/s/img/iconset.svg#heart_{{ Object.values(item.favorites).filter(u => u.user == session.user)[0] ? 'solid' : 'regular' }}"></use></svg> <svg class="iconset" id="a_favo"><use href="/s/img/iconset.svg#heart_{{ Object.values(item.favorites).filter(u => u.user == session.user)[0] ? 'solid' : 'regular' }}"></use></svg>
<svg class="iconset" id="a_tfull"><use href="/s/img/iconset.svg#window-{{ fullscreen == 1 ? 'minimize' : 'maximize' }}"></use></svg> <svg class="iconset" id="a_tfull"><use href="/s/img/iconset.svg#window-{{ fullscreen == 1 ? 'minimize' : 'maximize' }}"></use></svg>
<svg class="iconset" id="a_delete"><use href="/s/img/iconset.svg#cross"></use></svg> @if(session.admin)<svg class="iconset" id="a_delete"><use href="/s/img/iconset.svg#cross"></use></svg>@endif
</div> </div>
@endif @endif
</div> </div>
@ -36,7 +33,7 @@
<video id="my-video" class="embed-responsive-item" width="640" height="360" src="{{ item.dest }}" preload="auto" autoplay controls loop playsinline></video> <video id="my-video" class="embed-responsive-item" width="640" height="360" src="{{ item.dest }}" preload="auto" autoplay controls loop playsinline></video>
</div> </div>
@elseif(item.mime.startsWith("audio")) @elseif(item.mime.startsWith("audio"))
<div class="embed-responsive embed-responsive-16by9" style="background: url('@if(item.coverart)//f0ck.me{{ item.coverart }}@else/s/img/200.gif@endif') no-repeat center / contain black;"> <div class="embed-responsive embed-responsive-16by9" style="background: url('@if(item.coverart)//w0bm.com{{ item.coverart }}@else/s/img/200.gif@endif') no-repeat center / contain black;">
<audio id="my-video" class="embed-responsive-item" autoplay controls loop src="{{ item.dest }}" data-setup="{}" poster="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" type="{{ item.mime }}"></audio> <audio id="my-video" class="embed-responsive-item" autoplay controls loop src="{{ item.dest }}" data-setup="{}" poster="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" type="{{ item.mime }}"></audio>
</div> </div>
@elseif(item.mime.startsWith("image")) @elseif(item.mime.startsWith("image"))
@ -62,28 +59,44 @@
</div> </div>
</div> </div>
<div class="metadata"> <div class="metadata">
<span class="badge badge-dark"> <div class="kontrollelement">
<div class="einheit">
@if(typeof pagination !== "undefined")
<nav class="steuerung">
@if(pagination.prev)
<a id="" href="{{ link.main }}{{ pagination.prev }}">← next</a>
@else
<a id="" href="#" style="visibility: hidden">← next</a>
@endif
<span>|</span>
<a id="random" class="" href="/random">
<span>random</span>
</a>
<span>
|
</span>
@if(pagination.next)
<a id="" href="{{ link.main }}{{ pagination.next }}">prev →</a>
@else
<a id="" href="#" style="visibility: hidden">prev →</a>
@endif
</nav>
@endif
</div>
</div>
<div class="blahlol">
<span class="badge badge-dark">
<a href="/{{ item.id }}" class="id-link">{{ item.id }}</a> <a href="/{{ item.id }}" class="id-link">{{ item.id }}</a>
@if(session) @if(session)
(<a id="a_username" href="/user/{{ user.name.toLowerCase() }}/f0cks@if(tmp.mime)/{{ tmp.mime }}@endif">{{ user.name }}</a>) (<a id="a_username" href="/user/{{ user.name.toLowerCase() }}/f0cks@if(tmp.mime)/{{ tmp.mime }}@endif">{{ user.name }}</a>)
@endif @endif
</span> </span>
<span class="badge badge-dark">{{ user.network }} / {{ user.channel }}</span>
<span class="badge badge-dark image-source">
@if(item.src.long.length)
<a href="{{ item.src.long }}" target="_blank">{{ item.src.short }}</a>
@else
hidden
@endif
</span>
<span class="badge badge-dark"><a class="dest-link" href="{{ item.dest }}" target="_blank">{{ item.mime }}</a> / {{ item.size }}</span>
<span class="badge badge-dark"><time class="timeago" tooltip="{{ item.timestamp.timefull }}">{{ item.timestamp.timeago }}</time></span> <span class="badge badge-dark"><time class="timeago" tooltip="{{ item.timestamp.timefull }}">{{ item.timestamp.timeago }}</time></span>
<span class="badge badge-dark">{{ phrase }}</span>
<span class="badge badge-dark" id="tags"> <span class="badge badge-dark" id="tags">
@if(typeof item.tags !== "undefined") @if(typeof item.tags !== "undefined")
@each(item.tags as tag) @each(item.tags as tag)
<span @if(session)tooltip="{{ tag.user }}"@endif class="badge {{ tag.badge }} mr-2"> <span @if(session)tooltip="{{ tag.user }}"@endif class="badge {{ tag.badge }} mr-2">
<a href="/tag/{{ tag.normalized }}">{!! tag.tag !!}</a>@if(session)&nbsp;<a class="removetag" href="#">&#215;</a>@endif <a href="/tag/{{ tag.normalized }}">{!! tag.tag !!}</a>@if(session.admin)&nbsp;<a class="removetag" href="#">&#215;</a>@endif
</span> </span>
@endeach @endeach
@endif @endif
@ -99,8 +112,8 @@
@endeach @endeach
@endif @endif
</span> </span>
</div>
</div> </div>
</div>
</div> </div>
</div> </div>
@include(snippets/footer) @include(snippets/footer)

View File

@ -3,12 +3,12 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>f0ck login</title> <title>login</title>
<link href="/s/css/f0ck.css" rel="stylesheet" /> <link href="/s/css/f0ck.css" rel="stylesheet" />
</head> </head>
<body type="login"> <body type="login">
<form class="login-form" method="post" action="/login"> <form class="login-form" method="post" action="/login">
<p><a href="/"><img src="/s/img/f0ck_small.png" /></a></p> <img class="login-image" src="/s/img/w0bm_mosh_banner_by_marderchen.gif" alt="">
<input type="text" name="username" placeholder="username" autocomplete="off" required /> <input type="text" name="username" placeholder="username" autocomplete="off" required />
<input type="password" name="password" placeholder="password" autocomplete="off" required /> <input type="password" name="password" placeholder="password" autocomplete="off" required />
<p><input type="checkbox" id="kmsi" name="kmsi" /> <label for="kmsi">stay signed in</label></p> <p><input type="checkbox" id="kmsi" name="kmsi" /> <label for="kmsi">stay signed in</label></p>

22
views/picdump.html Normal file
View File

@ -0,0 +1,22 @@
@include(snippets/header)
<div id="main">
<h2>Picdump (last week)</h2>
<div class="picdump">
@each(dump as line)
<a href="/{{ line.id }}"><img src="/t/{{ line.id }}.webp"></a>
@endeach
</div>
</div>
<style>
.picdump {
width: 100%;
padding: 10px;
}
.picdump > a {
margin-top: 12px;
}
.picdump > a > img {
width: 100%;
}
</style>
@include(snippets/footer)

View File

@ -1,51 +1,55 @@
@include(snippets/header) @include(snippets/header)
<div id="main"> <div id="main">
<div class="topf0ckers"> <div class="topf0ckers">
<h3>Top f0ckers of all time <br>- Ranking -</h3> <h3>f0ck Rankings?</h3>
</div> </div>
<div class="ranking"> <div class="theforceofthree">
<div class="by-user"> <div class="triin">
<h3>Biggest taggers</h3> </div>
<table class="table"> <div class="ranking">
<tbody> <div class="by-user">
@for(let i = 0; i < list.length; i++) <h3>Biggest taggers</h3>
<table class="table">
<tr> <tr>
<td>{{ i + 1 }}</td> <th>Rank</th>
<td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp" /></a></td> <th>Avatar</th>
<td><a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td> <th>Username</th>
<td>{{ list[i].count }}</td> <th>Tagged</th>
</tr> </tr>
@endfor <tbody>
</tbody> @for(let i = 0; i < list.length; i++)
</table> <tr>
</div> <td>{{ i + 1 }}</td>
<div class="by-hoster"> <td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp"></a></td>
<h3>Top {{ hoster.length }} hoster</h3> <td>@if(list[i].admin)&#11088;&nbsp;@endif<a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td>
<table class="table"> <td>{{ list[i].count }}</td>
@each(hoster as host) </tr>
<tr><td>{{ host.part.length ? host.part : "Telegram" }}</td><td>{{ host.c }}</td></tr> @endfor
@endeach </tbody>
</table> </table>
</div> </div>
<div class="by-stats"> <div class="by-stats">
<h3>Tag stats</h3> <h3>Tag stats</h3>
<table class="table"> <table class="table">
<tr><td>total</td><td>{{ stats.total }}</td></tr> <tr><td>total</td><td>{{ stats.total }}</td></tr>
<tr><td>tagged</td><td>{{ stats.tagged }}</td></tr> <tr><td>tagged</td><td>{{ stats.tagged }}</td></tr>
<tr><td>untagged</td><td>{{ stats.untagged }}</td></tr> <tr><td>untagged</td><td>{{ stats.untagged }}</td></tr>
<tr><td>SFW</td><td>{{ stats.sfw }}</td></tr> <tr><td>SFW</td><td>{{ stats.sfw }}</td></tr>
<tr><td>NSFW</td><td>{{ stats.nsfw }}</td></tr> <tr><td>NSFW</td><td>{{ stats.nsfw }}</td></tr>
<tr><td>deleted</td><td>{{ stats.deleted }}</td></tr> <tr><td>deleted</td><td>{{ stats.deleted }}</td></tr>
<tr><td>missing ids</td><td>{{ stats.untracked }}</td></tr> <tr><td>missing ids</td><td>{{ stats.untracked }}</td></tr>
</table> </table>
<h3>Top f0cks</h3> <h3>Top f0cks</h3>
<table class="table"> <table class="table">
@each(favotop as favo) @each(favotop as favo)
<tr><td><a href="/{{ favo.item_id }}">{{ favo.item_id }}</a></td><td>{{ favo.favs }}</td></tr> <tr><td><a href="/{{ favo.item_id }}">{{ favo.item_id }}</a></td><td>{{ favo.favs }}</td></tr>
@endeach @endeach
</table> </table>
</div>
</div> </div>
</div> <div class="triout">
</div>
</div>
</div> </div>
@include(snippets/footer) @include(snippets/footer)

View File

@ -2,13 +2,7 @@
<div id="main"> <div id="main">
<div class="f0ckgle"> <div class="f0ckgle">
<div class="search-title"> <div class="search-title">
<span style="color:#4285F4;">f</span> <span>search</span>
<span style="color:#EA4335;">0</span>
<span style="color:#FBBC05;">c</span>
<span style="color:#4285F4;">k</span>
<span style="color:#34A853;">g</span>
<span style="color:#EA4335;">l</span>
<span style="color:#4285F4;">e</span>
</div> </div>
<form action="/search" class="admin-search"> <form action="/search" class="admin-search">
<input type="text" name="tag" value="{!! searchstring || '' !!}" /><button type="submit">🔍</button> <input type="text" name="tag" value="{!! searchstring || '' !!}" /><button type="submit">🔍</button>

View File

@ -1,7 +1,6 @@
@include(snippets/header) @include(snippets/header)
<div id="main"> <div class="settings">
<h1>Settings</h1> <h1>Settings</h1>
@if(session.avatar)<a href="/{{ session.avatar }}"><img id="img_avatar" src="/t/{{ session.avatar }}.webp" /></a>@endif
<h2>Account</h2> <h2>Account</h2>
<table class="table"> <table class="table">
<tbody> <tbody>
@ -10,16 +9,23 @@
<td>{{ session.id }}</td> <td>{{ session.id }}</td>
</tr> </tr>
<tr> <tr>
<td>level</td> <td>admin</td>
<td>{{ session.level }}/100</td> <td>{{ !!session.admin }}</td>
</tr> </tr>
<tr> <tr>
<td>username</td> <td>username</td>
<td>{!! session.user !!}</td> <td>{!! session.user !!}</td>
</tr> </tr>
<tr> <tr>
<td>avatar</td> <td>@if(session.avatar)<a href="/{{ session.avatar }}"><img id="img_avatar" src="/t/{{ session.avatar }}.webp"></a>@endif</td>
<td><input type="text" class="input" name="i_avatar" value="{{ session.avatar }}" /><input type="submit" id="s_avatar" value="save" /></td> <td><input type="text" class="input" name="i_avatar" value="{{ session.avatar }}"></td>
</tr>
<tr>
<td>mail</td>
<td><input type="text" class="input" name="i_mail" placeholder="hashed" disabled></td>
</tr>
<tr>
<td colspan="2"><input type="submit" id="s_avatar" value="save"></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -1,7 +1,10 @@
@if(session)<!--<div style="position: fixed; bottom: 0; z-index: 998; background-color: var(--bg); width: 100%; height: 29px; border-top: 1px solid var(--accent)">{{ JSON.stringify(session) }}</div>-->@endif
<script async src="/s/js/theme.js?v=@mtime(/public/s/js/theme.js)"></script> <script async src="/s/js/theme.js?v=@mtime(/public/s/js/theme.js)"></script>
<script src="/s/js/v0ck.js?v=@mtime(/public/s/js/v0ck.js)"></script> <script src="/s/js/v0ck.js?v=@mtime(/public/s/js/v0ck.js)"></script>
<script src="/s/js/f0ck.js?v=@mtime(/public/s/js/f0ck.js)"></script> <script src="/s/js/f0ck.js?v=@mtime(/public/s/js/f0ck.js)"></script>
@if(session)<script src="/s/js/admin.js?v=@mtime(/public/s/js/admin.js)"></script>@endif @if(session && session.admin)
<script src="/s/js/admin.js?v=@mtime(/public/s/js/admin.js)"></script>
@elseif(session && !session.admin)
<script src="/s/js/user.js?v=@mtime(/public/s/js/user.js)"></script>
@endif
</body> </body>
</html> </html>

View File

@ -1,14 +1,13 @@
<!doctype html> <!doctype html>
<html lang="en" theme="@if(typeof theme !== "undefined"){{ theme }}@endif" res="@if(typeof fullscreen !== "undefined"){{ fullscreen == 1 ? 'fullscreen' : '' }}@endif"> <html lang="en" theme="@if(typeof theme !== "undefined"){{ theme }}@endif" res="@if(typeof fullscreen !== "undefined"){{ fullscreen == 1 ? 'fullscreen' : '' }}@endif">
<head> <head>
<title>f0ck!</title> <title>f0bm</title>
<meta name="description" content="Welcome to the internet"/> <link rel="icon" type="image/gif" href="/s/img/favicon.png" />
<meta property="og:image" content="/s/img/favicon.gif">
<link rel="icon" type="image/gif" href="/s/img/favicon.gif" />
<link rel="stylesheet" href="/s/css/f0ck.css?v=@mtime(/public/s/css/f0ck.css)"> <link rel="stylesheet" href="/s/css/f0ck.css?v=@mtime(/public/s/css/f0ck.css)">
<link rel="stylesheet" href="/s/css/w0bm.css?v=@mtime(/public/s/css/w0bm.css)">
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
@if(typeof item !== "undefined")<link rel="canonical" href="https://f0ck.me/{{ item.id }}" />@endif @if(typeof item !== "undefined")<link rel="canonical" href="https://w0bm.com/{{ item.id }}" />@endif
</head> </head>
<body> <body>
@include(snippets/navbar) @include(snippets/navbar)

View File

@ -1,89 +1,85 @@
@if(session) @if(session)
<nav class="navbar navbar-expand-lg"> <nav class="navbar navbar-expand-lg">
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a> <a class="navbar-brand" href="/"><img class="image-brand" src="/s/img/w0bm_mosh_banner_by_marderchen.gif" alt="w...?"><span class="f0ck" width="" height=""></span></a>
<div class="navigation-links"> <div class="navigation-links">
<ul class="navbar-nav"> <div class="pagination-container-fluid">
<li class="nav-item dropdown"> <ul class="navbar-nav">
<a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="dropdown"> <li class="nav-item dropdown">
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar" /><span>{{ session.user }}</span> <a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="dropdown">
</a> <img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar"><span>@if(session.admin)&#11088;&nbsp;@endif{{ session.user }}</span>
<ul class="dropdown-menu"> </a>
<li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li> <ul class="dropdown-menu">
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li> <li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li>
<li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li> <li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li>
<li><a href="/search">search</a></li> <li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
<li><a href="/admin">Admin</a></li> <li><a href="/search">search</a></li>
<li><a href="/about">About</a></li> @if(session.admin)<li><a href="/admin">Admin</a></li>@endif
<li><a href="/ranking">ranking</a></li> <li><a href="/about">About</a></li>
<li><a href="/settings">settings</a></li> <li><a href="/ranking">ranking</a></li>
<li><a href="/logout">logout</a></li> <li><a href="/settings">settings</a></li>
</ul> <li><a href="/logout">logout</a></li>
</li> </ul>
<li class="nav-item dropdown" id="themes"> </li>
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a> <li class="nav-item dropdown" id="themes">
<ul class="dropdown-menu"> <a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">𐂧</a>
@each(themes as t) <ul class="dropdown-menu shii">
<li><a href="/theme/{{ t }}">{{ t }}</a></li> @each(themes as t)
@endeach <li><a href="/theme/{{ t }}">{{ t }}</a></li>
</ul> @endeach
</li> </ul>
<li class="nav-item dropdown"> </li>
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime)&nbsp;&#9660;@endif</a> <li class="nav-item @if(session)dropdown@endif">
<ul class="dropdown-menu"> <a class="nav-link ddcontent" href="#"@if(typeof session.mode !== "undefined") content="{{ modes[session.mode] ?? 'sfw' }}" data-toggle="dropdown"@endif>Mode</a>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li> <ul class="dropdown-menu">
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li> @for(let i = 0; i < modes.length; i++)
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li> <li><a class="dropdown-item" href="/mode/{{ i }}">{{ modes[i] }}</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li> @endfor
</ul> </ul>
</li> </li>
<li class="nav-item @if(session)dropdown@endif"> <li class="nav-item">
<a class="nav-link ddcontent" href="#"@if(typeof session.mode !== "undefined") content="{{ modes[session.mode] ?? 'sfw' }}" data-toggle="dropdown"@endif>Mode</a> <a id="explore-tags" class="nav-link" href="/tags">
<ul class="dropdown-menu"> <span class="nav-link-identifier">Tags</span>
@for(let i = 0; i < modes.length; i++) </a>
<li><a class="dropdown-item" href="/mode/{{ i }}">{{ modes[i] }}</a></li> </li>
@endfor <li class="nav-item">
</ul> <a id="random" class="nav-link" href="/random">
</li> <span class="nav-link-identifier">Random</span>
<li class="nav-item"> </a>
<a id="random" class="nav-link" href="/random"> </li>
<span class="nav-link-identifier">Random</span> </ul>
</a> </div>
</li>
</ul>
</div> </div>
<div class="collapse navbar-collapse show" id="navbarSupportedContent"> <div class="collapse navbar-collapse show" id="navbarSupportedContent">
<div class="pagination-container-fluid"> <div class="pagination-wrapper">
<div class="pagination-wrapper"> @if(typeof pagination !== "undefined")
@if(typeof pagination !== "undefined") <nav class="pagination">
<nav class="pagination"> <a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">&laquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">&laquo;</a> <a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">&lsaquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">&lsaquo;</a> @each(pagination.cheat as i)
@each(pagination.cheat as i) @if(i == pagination.page)
@if(i == pagination.page) <span class="btn disabled">{{ i }}</span>
<span class="btn disabled">{{ i }}</span> @else
@else <a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a>
<a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a> @endif
@endif @endeach
@endeach <a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">&rsaquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">&rsaquo;</a> <a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">&raquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">&raquo;</a> </nav>
</nav> @endif
@endif
</div>
</div> </div>
</div> </div>
</div>
</nav> </nav>
@else @else
<!-- not logged in -->
<nav class="navbar navbar-expand-lg"> <nav class="navbar navbar-expand-lg">
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a> <a class="navbar-brand" href="/"><img class="image-brand" src="/s/img/w0bm_mosh_banner_by_marderchen.gif" alt="w...?"><span class="f0ck" width="" height=""></span></a>
<div class="navigation-links-guest"> <div class="navigation-links-guest">
<ul class="navbar-nav-guests"> <ul class="navbar-nav-guests">
<li class="nav-item dropdown"> <li class="nav-item">
<a class="nav-link" href="/about" data-toggle="dropdown">About</a> <a class="nav-link" href="/about">About</a>
<ul class="dropdown-menu">
<li><a href="/login">login</a></li>
</ul>
</li> </li>
<li class="nav-item dropdown" id="themes"> <li class="nav-item dropdown" id="themes">
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a> <a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
@ -93,14 +89,10 @@
@endeach @endeach
</ul> </ul>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item">
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime)&nbsp;&#9660;@endif</a> <a id="explore-tags" class="nav-link" href="/tags">
<ul class="dropdown-menu"> <span class="nav-link-identifier">Tags</span>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li> </a>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
</ul>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a id="random" class="nav-link" href="/random"> <a id="random" class="nav-link" href="/random">
@ -109,6 +101,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<!-- rechte seite -->
<div class="collapse navbar-collapse show" id="navbarSupportedContent"> <div class="collapse navbar-collapse show" id="navbarSupportedContent">
<div class="pagination-container-fluid"> <div class="pagination-container-fluid">
<div class="pagination-wrapper"> <div class="pagination-wrapper">

View File

@ -1,133 +0,0 @@
@if(session)
<nav class="navbar navbar-expand-lg">
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a>
<div class="navigation-links">
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link" href="#" content="{{ session.user }}" data-toggle="dropdown">
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar" /><span>{{ session.user }}</span>
</a>
<ul class="dropdown-menu">
<li><a href="/admin">adminpanel</a></li>
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</a></li>
<li><a href="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
<li><a href="/settings">settings</a></li>
<li><a href="/search">search</a></li>
<li><a href="/about">About</a></li>
<li><a href="/ranking">Ranking</a></li>
<li><a href="/logout">logout</a></li>
</ul>
</li>
<li class="nav-item dropdown" id="themes">
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
<ul class="dropdown-menu">
@each(themes as t)
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
@endeach
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime)&nbsp;&#9660;@endif</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
</ul>
</li>
<li class="nav-item @if(session)dropdown@endif">
<a class="nav-link ddcontent" href="#"@if(typeof session.mode !== "undefined") content="{{ modes[session.mode] ?? 'sfw' }}" data-toggle="dropdown"@endif>Mode</a>
<ul class="dropdown-menu">
@for(let i = 0; i < modes.length; i++)
<li><a class="dropdown-item" href="/mode/{{ i }}">{{ modes[i] }}</a></li>
@endfor
</ul>
</li>
<li class="nav-item">
<a id="random" class="nav-link" href="/random">
<span class="nav-link-identifier">Random</span>
</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse show" id="navbarSupportedContent">
<div class="pagination-container-fluid">
<div class="pagination-wrapper">
@if(typeof pagination !== "undefined")
<nav class="pagination">
<a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">&laquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">&lsaquo;</a>
@each(pagination.cheat as i)
@if(i == pagination.page)
<span class="btn disabled">{{ i }}</span>
@else
<a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a>
@endif
@endeach
<a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">&rsaquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">&raquo;</a>
</nav>
@endif
</div>
</div>
</div>
</nav>
@else
<nav class="navbar navbar-expand-lg">
<a class="navbar-brand" href="/"><span class="f0ck" width="" height="">F0CK</span></a>
<div class="navigation-links-guest">
<ul class="navbar-nav-guests">
<li class="nav-item dropdown">
<a class="nav-link" href="/about" data-toggle="dropdown">About</a>
<ul class="dropdown-menu">
<li><a href="/login">login</a></li>
</ul>
</li>
<li class="nav-item dropdown" id="themes">
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
<ul class="dropdown-menu">
@each(themes as t)
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
@endeach
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime)&nbsp;&#9660;@endif</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endif">All</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifaudio">Audio</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifvideo">Video</a></li>
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
</ul>
</li>
<li class="nav-item">
<a id="random" class="nav-link" href="/random">
<span class="nav-link-identifier">Random</span>
</a>
</li>
</ul>
</div>
<div class="collapse navbar-collapse show" id="navbarSupportedContent">
<div class="pagination-container-fluid">
<div class="pagination-wrapper">
@if(typeof pagination !== "undefined")
<nav class="pagination">
<a href="{{ link.main }}{{ link.path }}{{ pagination.start }}" class="page-item-1 btn start@if(!pagination.prev) disabled@endif">&laquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">&lsaquo;</a>
@each(pagination.cheat as i)
@if(i == pagination.page)
<span class="btn disabled">{{ i }}</span>
@else
<a href="{{ link.main }}{{ link.path }}{{ i }}" class="pagination-int-item btn">{{ i }}</a>
@endif
@endeach
<a href="{{ link.main }}{{ link.path }}{{ pagination.next }}" class="page-item-3 btn next@if(!pagination.next) disabled@endif">&rsaquo;</a>
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">&raquo;</a>
</nav>
@endif
</div>
</div>
</div>
</nav>
@endif

28
views/tags.html Normal file
View File

@ -0,0 +1,28 @@
@include(snippets/header)
<div id="main">
<div class="container">
<h3 style="text-align: center;"></h3>
<div class="tags">
@if(session)
@each(toptags_regged as toptag)
<div class="tag badge badge-light mr-2">
<div class="tagbox-body">
<span class="toptag_id">{!! toptag.tag !!}</span>
<span class="toptag_tag"><a href="/tag/{!! toptag.tag !!}">{{ toptag.total_items }}</a></span>
</div>
</div>
@endeach
@else
@each(toptags as toptag)
<div class="tag badge badge-light mr-2">
<div class="tagbox-body">
<span class="toptag_id">{!! toptag.tag !!}</span>
<span class="toptag_tag"><a href="/tag/{!! toptag.tag !!}">{{ toptag.total_items }}</a></span>
</div>
</div>
@endeach
@endif
</div>
</div>
</div>
@include(snippets/footer)

56
views/terms.html Normal file
View File

@ -0,0 +1,56 @@
@include(snippets/header)
<div id="main">
<div class="tos">
<p>Terms of Service</p>
<ol>
<li>Acceptance of Terms</li>
<p>By accessing and using this website, you acknowledge that your access is a privilege, not a right. If you do not agree with these terms, you are free to leave at any time.</p>
<li>No Claims</li>
<p>Visitors to this website have no claims whatsoever against the website owner or operators. Access to the website and its content is provided as-is, with no guarantees, warranties, or entitlements of any kind.</p>
<li>No Liability</li>
<p>This website and its operators assume no liability for any errors, omissions, inaccuracies, or any other issues that may arise from the use of this site. Use of this website is entirely at your own risk.</p>
<li>No Warranty</li>
<p>There is no warranty regarding the completeness, accuracy, reliability, or availability of the content provided on this website. The content may change at any time without notice.</p>
<li>Compliance with Requests</li>
<p>The website owner reserves the right to remove content, restrict access, or comply with any valid legal or personal requests at their sole discretion.</p>
<li>Changes to Terms</li>
<p>These terms may be updated at any time without prior notice. It is your responsibility to review them periodically.</p>
</ol>
<p>Data Privacy</p>
<ol>
<li>No Data Logging</li>
<p>This website does not collect, store, or log any personal data, including IP addresses or other identifying information of its visitors. No server-side logs are maintained.</p>
<li>Use of Cookies</li>
<p>Upon changing the theme, a single cookie is set. This cookie solely stores the name of the currently active theme to enhance the visual experience. It does not contain any personal data, tracking information, or other identifiers.</p>
<li>Cookie Control</li>
<p>The cookie is purely of cosmetic nature and not essential for the website's functionality. Users can disable cookies for this website entirely via their browser settings without affecting their ability to access and use the site.</p>
<li>No Third-Party Tracking</li>
<p>This website does not use third-party tracking services, analytics tools, or embedded content that collects user data.</p>
<li>User Accounts</li>
<p>When a former visitor is granted access with an account, the following data is collected:</p>
<ul>
<li>The User Agent</li>
<li>The Timestamp of the first login</li>
<li>The Timestamp of the account's last usage</li>
<li>The User's last recorded action</li>
</ul>
<li>Email Communication</li>
<p>If you send me an email your mail is stored on our server, we can make a connection to your Email-Address and your user account if you contact us this way.</p>
<p>The Emails are not deleted after being answered.</p>
<li>Fully complying with Art. 15 GDPR</li>
<p>You can ask anytime what data we have of you and how we use it, see Email Communication too.</p>
<li>Changes to This Policy</li>
<p>This privacy policy may be updated from time to time. Users are encouraged to review it periodically to stay informed about any changes.</p>
<p>By using this website, you acknowledge and accept the terms of service and the data privacy policy.</p>
</ol>
</div>
</div>
@include(snippets/footer)

View File

@ -4,8 +4,8 @@
<table class="table"> <table class="table">
@each(f0cks as f0ck) @each(f0cks as f0ck)
<tr> <tr>
<td><a href="//f0ck.me/{{ f0ck.id }}"><img src="//f0ck.me/t/{{ f0ck.id }}.webp" /></a></td> <td><a href="//w0bm.com/{{ f0ck.id }}"><img src="//w0bm.com/t/{{ f0ck.id }}.webp" /></a></td>
<td><a href="//f0ck.me/{{ f0ck.id }}">{{ f0ck.id }}</a></td> <td><a href="//w0bm.com/{{ f0ck.id }}">{{ f0ck.id }}</a></td>
<td>{{ f0ck.username }}</td> <td>{{ f0ck.username }}</td>
</tr> </tr>
@endeach @endeach

View File

@ -8,7 +8,7 @@
@endif @endif
<div class="layersoffear"> <div class="layersoffear">
<div class="profile_head_username"> <div class="profile_head_username">
<span>{{ user.user }}</span> <span>@if(user.admin)&#11088;&nbsp;@endif{{ user.user }}</span>
</div> </div>
<div class="profile_head_user_stats"> <div class="profile_head_user_stats">
ID: {{ user.user_id }} Joined: {{ user.created_at }} ID: {{ user.user_id }} Joined: {{ user.created_at }}
@ -18,9 +18,9 @@
<div class="user_content_wrapper"> <div class="user_content_wrapper">
<div class="f0cks"> <div class="f0cks">
<div class="f0cks-header"> <div class="f0cks-header">
f0ck{{ count.f0cks == 1 ? '' : 's' }}: {{ count.f0cks }} <a href="{{ f0cks.link.main }}">view all</a> f0ck{{ count.f0cks == 1 ? '' : 's' }}: {{ count.f0cks }} <a href="{{ f0cks.link?.main }}">view all</a>
</div> </div>
@if('items' in f0cks) @if(count.f0cks)
<div class="posts"> <div class="posts">
@each(f0cks.items as item) @each(f0cks.items as item)
<a href="{{ f0cks.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a> <a href="{{ f0cks.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>
@ -32,9 +32,9 @@
</div> </div>
<div class="favs"> <div class="favs">
<div class="favs-header"> <div class="favs-header">
fav{{ count.favs == 1 ? '' : 's' }}: {{ count.favs }} <a href="{{ favs.link.main }}">view all</a> fav{{ count.favs == 1 ? '' : 's' }}: {{ count.favs }} <a href="{{ favs.link?.main }}">view all</a>
</div> </div>
@if('items' in favs) @if(count.favs)
<div class="posts"> <div class="posts">
@each(favs.items as item) @each(favs.items as item)
<a href="{{ favs.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a> <a href="{{ favs.link.main }}{{ item.id }}" data-mime="{{ item.mime }}" data-mode="{{ item.tag_id ? ['','sfw','nsfw'][item.tag_id] : 'null' }}" style="background-image: url('/t/{{ item.id }}.webp')"><p></p></a>