Compare commits

...

30 Commits

Author SHA1 Message Date
Flummi
70df109d1b socks schmocks
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 19s
2024-08-09 12:57:19 +02:00
Flummi
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
Flummi
38c4abae3c blah.
All checks were successful
fetch npm modules / f0ck the f0cker (push) Successful in 29s
2024-06-28 18:33:12 +02:00
Flummi
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
Flummi
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
Flummi
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
Flummi
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
Flummi
befc8e8e75 fix admin.js 2024-06-28 05:36:25 +02:00
Flummi
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
Flummi
c79cca18cf fix total f0cks in profile 2024-06-24 08:41:13 +02:00
Flummi
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
Flummi
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
Flummi
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
Flummi
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
Flummi
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
Flummi
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
25 changed files with 774 additions and 340 deletions

View File

@ -5,6 +5,7 @@
"domain": "f0ck.dev", "domain": "f0ck.dev",
"regex": "f0ck\\.dev" "regex": "f0ck\\.dev"
}, },
"socks": "",
"maxfilesize": 83886080, "maxfilesize": 83886080,
"adminmultiplier": 3.5, "adminmultiplier": 3.5,
"ignored": [ "ignored": [

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: postgres
--
-- *not* creating schema, since initdb creates it
ALTER SCHEMA public OWNER TO postgres;
--
-- 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 postgres;
--
-- 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

@ -2992,3 +2992,27 @@ 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;
}

View File

@ -333,6 +333,7 @@ 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));
if(document.querySelector("svg#a_delete"))
document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent); document.querySelector("svg#a_delete").addEventListener("click", deleteButtonEvent);
document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent); document.querySelector("svg#a_favo").addEventListener("click", toggleFavEvent);

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

@ -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 = [];

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,7 +121,7 @@ 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) => { exec("journalctl -qeu f0ck --no-pager", (err, stdout) => {
res.reply({ res.reply({
body: tpl.render("admin/log", { body: tpl.render("admin/log", {
@ -143,7 +132,7 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/admin\/recover\/?/, auth, async (req, res) => { router.get(/^\/admin\/recover\/?/, lib.auth, async (req, res) => {
if(req.url.qs?.id) { if(req.url.qs?.id) {
const id = +req.url.qs.id; const id = +req.url.qs.id;
const f0ck = await db` const f0ck = await db`

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({

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,32 +31,43 @@ 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 {
f0cks = await f0cklib.getf0cks({
user: user,
mode: req.session.mode,
fav: false,
session: !!req.session,
limit: 99999999
});
if('items' in f0cks) { if('items' in f0cks) {
count.f0cks = f0cks.items.length; count.f0cks = f0cks.items.length;
f0cks.items = f0cks.items.slice(0, 50); f0cks.items = f0cks.items.slice(0, 50);
} }
} catch(err) {
f0cks = false;
count.f0cks = 0;
}
try {
favs = await f0cklib.getf0cks({
user: user,
mode: req.session.mode,
fav: true,
session: !!req.session,
limit: 99999999
});
if('items' in favs) { if('items' in favs) {
count.favs = favs.items.length; count.favs = favs.items.length;
favs.items = favs.items.slice(0, 50); favs.items = favs.items.slice(0, 50);
} }
} catch(err) {
favs = false;
count.favs = 0;
}
const data = { const data = {
user: query[0], user: query[0],
@ -100,7 +111,7 @@ export default (router, tpl) => {
}); });
}); });
router.get(/^\/mode\/(\d)/, auth, async (req, res) => { 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

@ -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

@ -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();
@ -51,8 +51,8 @@ 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(`insta schminsta`);
@ -69,21 +69,26 @@ 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 ${cfg.main.socks} -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
try { try {
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); const meta = JSON.parse((await queue.exec(`yt-dlp ${cfg.main.socks} -f 'bv*[height<=720]+ba/b[height<=720] / wv*+ba/w' --skip-download --dump-json "${link}"`)).stdout);
ext = meta.ext; 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"];
@ -100,52 +105,43 @@ 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 ${cfg.main.socks} -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 if(link.match(regex.imgur)) {
else // imghure via torsocks
{
try { 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(); await queue.exec(`torsocks wget ${link} -O ./tmp/${uuid}.${ext}`);
source = `./tmp/${uuid}.${ext}`;
} catch(err) { } catch(err) {
console.error('err:', err);
if(e.type == 'tg') if(e.type == 'tg')
return await e.editMessageText(msg.result.chat.id, msg.result.message_id, err); return await e.editMessageText(msg.result.chat.id, msg.result.message_id, err);
return await e.reply(err); return await e.reply('something went wrong lol');
} }
} }
else {
try {
source = (await queue.exec(`yt-dlp ${cfg.main.socks} -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) {
console.log(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');
} }
}
// this is how it was before I fucked it up :> // </download data>
// 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')
@ -215,6 +211,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 +232,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),

View File

@ -71,7 +71,7 @@ process.on('unhandledRejection', err => {
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

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)

View File

@ -14,7 +14,7 @@
<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>
@ -83,7 +83,7 @@
@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

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

@ -11,8 +11,8 @@
@for(let i = 0; i < list.length; i++) @for(let i = 0; i < list.length; i++)
<tr> <tr>
<td>{{ i + 1 }}</td> <td>{{ i + 1 }}</td>
<td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp" /></a></td> <td><a href="/{{ list[i].avatar }}"><img class="avatar" src="/t/{{ list[i].avatar }}.webp"></a></td>
<td><a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td> <td>@if(list[i].admin)&#11088;&nbsp;@endif<a href="/user/{!! list[i].user !!}">{!! list[i].user !!}</a></td>
<td>{{ list[i].count }}</td> <td>{{ list[i].count }}</td>
</tr> </tr>
@endfor @endfor

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

@ -5,14 +5,14 @@
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="dropdown"> <a class="nav-link user" 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> <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>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li> <li><a href="/user/{{ session.user.toLowerCase() }}">my profile</a></li>
<li><a href="/user/{{ session.user.toLowerCase() }}/f0cks">my f0cks</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="/user/{{ session.user.toLowerCase() }}/favs">my favs</a></li>
<li><a href="/search">search</a></li> <li><a href="/search">search</a></li>
<li><a href="/admin">Admin</a></li> @if(session.admin)<li><a href="/admin">Admin</a></li>@endif
<li><a href="/about">About</a></li> <li><a href="/about">About</a></li>
<li><a href="/ranking">ranking</a></li> <li><a href="/ranking">ranking</a></li>
<li><a href="/settings">settings</a></li> <li><a href="/settings">settings</a></li>

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

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>