Compare commits
209 Commits
82702d786a
...
comments
Author | SHA1 | Date | |
---|---|---|---|
d951a072ee | |||
a64a4da8cd | |||
ddaaaee502 | |||
cc5ddf27d3 | |||
e7f6ecd239 | |||
2c9058dec7 | |||
d13eeea588 | |||
79441cf69a | |||
904a7abd86 | |||
aa0d88424b | |||
201f7969b4 | |||
1da992d6a9 | |||
77a703a5f0 | |||
dc14d2f78f | |||
5fcc337038 | |||
076e98a963 | |||
daab816ad2 | |||
0b6b8c549a | |||
39ba04bcc9 | |||
6b98458710 | |||
729522369c | |||
70f9e6553d | |||
2f7f8950ae | |||
f2ba18d186 | |||
2309c3020a | |||
f8cc9f1dc0 | |||
0754cb97a1 | |||
2c7a55415a | |||
1425361a6f | |||
f8c59111aa | |||
a9f65bb798 | |||
d864679775 | |||
e68af4dc96 | |||
17c029e6da | |||
49fb4bfc56 | |||
c6fbe956a0 | |||
75c4e35fdc | |||
d2091494a1 | |||
53a0880c55 | |||
74431a2a29 | |||
af4c48f351 | |||
d0f8cb5acb | |||
29d5b20f5b | |||
86b13f5173 | |||
5bb3fefe52 | |||
41194ca08a | |||
314c476f8d | |||
a575f52005 | |||
2ab187c780 | |||
fa0496949c | |||
4d93ef1152 | |||
f8dffcdfc9 | |||
3813af2c46 | |||
3ab534ee8e | |||
3e7ebba6fd | |||
757c5aa4b4 | |||
7cc6776773 | |||
53ea6389c7 | |||
edfdd7ebbe | |||
08698ee886 | |||
e5b9bdb721 | |||
961ec2cf55 | |||
8bee86c002 | |||
9aec26f4d3 | |||
e16138583e | |||
10ef57b0bf | |||
9f4432a942 | |||
b775d55fba | |||
c33e57c9c0 | |||
d315ae3efa | |||
dc1d658c9a | |||
d4811c3d5c | |||
9be8b3f982 | |||
1dacafdb3a | |||
3bc7cdcd1c | |||
dfea411e1b | |||
3a899e4911 | |||
7a96f26f84 | |||
412a4a348a | |||
587bebbd6a | |||
3aa14e4bfb | |||
522d4903ba | |||
6d795652a7 | |||
9c86d34b87 | |||
34e93b09c5 | |||
48fd0e5ab0 | |||
7df97485e6 | |||
8adee68835 | |||
0bda378993 | |||
b03d265a94 | |||
d78e90ddc0 | |||
a0962d8d5c | |||
58d8268207 | |||
002b796cbc | |||
d6561a66b8 | |||
b82044555d | |||
45792787ba | |||
81f4817f03 | |||
e0618443c0 | |||
6eddad7e0e | |||
6f71101b9e | |||
a33d1606ae | |||
d7abc4e797 | |||
5bcd797e6c | |||
530d0938c6 | |||
7f5ef839cc | |||
a106a31c47 | |||
14c6816c47 | |||
643cf0de76 | |||
c18c6b9283 | |||
4a7c7f8730 | |||
173321f5c8 | |||
6f12cbca32 | |||
a460b974a8 | |||
09d647cc48 | |||
d56c143e80 | |||
b9fbcb4187 | |||
1f761ec62b | |||
c0f8f6c536 | |||
881d44158e | |||
e159776e9b | |||
44ca53a050 | |||
97ef147160 | |||
f57a8b4320 | |||
ba821b81fa | |||
29acafe918 | |||
dc96a2578a | |||
9fc920c1d2 | |||
eb16487d73 | |||
501f68c481 | |||
4c94cac3ef | |||
5be4670ba3 | |||
50b983536c | |||
f0ee736e40 | |||
bb6f4dc2b8 | |||
b960acb0ed | |||
7621f6ca48 | |||
b8e69af878 | |||
be64a42d68 | |||
3d35367302 | |||
80c7d2f3d7 | |||
8dfee166b4 | |||
7a007c95e7 | |||
fd685a6c16 | |||
75fa6e23f5 | |||
bafb0916e2 | |||
fda30ebdee | |||
eb5d4ccfbe | |||
ce72c6f265 | |||
cba529deb4 | |||
8dd58553e2 | |||
8f4ea66cd9 | |||
00837600bb | |||
b76f6439fa | |||
17946742ec | |||
ae0d26aaa7 | |||
9d7b701e96 | |||
77c00de69a | |||
a7e2cb0dd9 | |||
9100f64d81 | |||
1222837d4d | |||
2447d62dac | |||
ac3647aa7f | |||
429b5003d5 | |||
da5d7285a4 | |||
1bc7085e68 | |||
f22b8b4e0d | |||
617385b4b6 | |||
1484c646e8 | |||
dd95c52de6 | |||
f63556e713 | |||
16d85ae5ad | |||
2ae986ccf1 | |||
4f5d54ee19 | |||
a97ed32c9f | |||
94c237561c | |||
7e9599adce | |||
9dfffbb8bf | |||
b0acc1731d | |||
647991b5e9 | |||
78b847ddae | |||
1a3af07309 | |||
8f5680e50f | |||
add3c7a648 | |||
e7ee063021 | |||
d57908f82e | |||
659adca258 | |||
46d8bd45a8 | |||
3731d1d785 | |||
872abd7f73 | |||
2a94a84c44 | |||
1787a69143 | |||
ac96827ad1 | |||
2e0881b109 | |||
315770bf30 | |||
6de804561f | |||
f4815d95e5 | |||
7e1129a567 | |||
1e01a521e4 | |||
9541d9e0b8 | |||
fb744fe341 | |||
a6b881a196 | |||
1be456edb4 | |||
1066e8772b | |||
4ebcbdd886 | |||
73577441d1 | |||
1a8aa81a0b | |||
86409c9d98 | |||
22b171c858 |
9
.gitignore
vendored
9
.gitignore
vendored
@ -1,7 +1,10 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
logs/*.log
|
logs/*.log
|
||||||
config.json
|
config.json
|
||||||
public/b/*
|
public/b
|
||||||
public/ca/*
|
public/ca
|
||||||
public/t/*
|
public/t
|
||||||
|
deleted/b
|
||||||
|
deleted/ca
|
||||||
|
deleted/t
|
||||||
tmp/*
|
tmp/*
|
||||||
|
32
README.md
Normal file
32
README.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# how to install:
|
||||||
|
## dependencies
|
||||||
|
```bash
|
||||||
|
sudo pacman -S nodejs npm ffmpeg yt-dlp ffmpegthumbnailer postgresql python python-pip imagemagick git mime-types
|
||||||
|
```
|
||||||
|
## postgres
|
||||||
|
```bash
|
||||||
|
sudo -u postgres initdb --locale en_US.UTF-8 -D '/var/lib/postgres/data'
|
||||||
|
#(if it fails: sudo localectl set-locale en_US.UTF-8)
|
||||||
|
sudo systemctl enable --now postgresql
|
||||||
|
#(if you're retarded or lazy, append postgresql and postgresql-libs to your ignorepkg)
|
||||||
|
sudo -u postgres createuser -S -D -R -e f0ck
|
||||||
|
sudo -u postgres createdb f0ck -O f0ck
|
||||||
|
```
|
||||||
|
## install f0ck
|
||||||
|
```bash
|
||||||
|
sudo useradd f0ck -m
|
||||||
|
sudo -iu f0ck
|
||||||
|
cd ~
|
||||||
|
git clone https://git.lat/f0ck/f0ckv2.git
|
||||||
|
cd f0ckv2
|
||||||
|
#(for developers: git checkout dev)
|
||||||
|
npm i
|
||||||
|
psql f0ck < f0ck.sql
|
||||||
|
mkdir -p public/ca deleted/{ca,b,t}
|
||||||
|
cp config_example.json config.json
|
||||||
|
- edit config.json
|
||||||
|
- set up clients, as described here: https://git.lat/keinBot/cuffeo
|
||||||
|
pip install nsfw_detector
|
||||||
|
#if this fails make sure to have enough dedicated ram or swap space, alternatively try with pip install nsfw_detector --no-cache-dir
|
||||||
|
npm start
|
||||||
|
```
|
61
config_example.json
Normal file
61
config_example.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"url": {
|
||||||
|
"full": "https://f0ck.dev",
|
||||||
|
"domain": "f0ck.dev",
|
||||||
|
"regex": "f0ck\\.dev"
|
||||||
|
},
|
||||||
|
"maxfilesize": 83886080,
|
||||||
|
"adminmultiplier": 3.5,
|
||||||
|
"ignored": [
|
||||||
|
"f0ck.dev",
|
||||||
|
"f0ck.me"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowedModes": [ "sfw", "nsfw", "untagged", "all" ],
|
||||||
|
"allowedMimes": [ "audio", "image", "video" ],
|
||||||
|
"nsfp": [],
|
||||||
|
"websrv": {
|
||||||
|
"port": "8080",
|
||||||
|
"paths": {
|
||||||
|
"images": "/b",
|
||||||
|
"thumbnails": "/t",
|
||||||
|
"coverarts": "/ca"
|
||||||
|
},
|
||||||
|
"themes": [ "f0ck", "p1nk", "orange", "atmos", "amoled", "paper", "term", "iced" ],
|
||||||
|
"eps": 294,
|
||||||
|
"cache": false,
|
||||||
|
"phrases": [
|
||||||
|
"<img src=\"/s/img/crap/nyancat.gif\" style=\"margin-top: 5px\" />"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"clients": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"sql": {
|
||||||
|
"host": "localhost",
|
||||||
|
"user": "f0ck",
|
||||||
|
"password": "",
|
||||||
|
"database": "f0ck",
|
||||||
|
"schema": "public",
|
||||||
|
"multipleStatements": true
|
||||||
|
},
|
||||||
|
"admins": [
|
||||||
|
|
||||||
|
],
|
||||||
|
"mimes": {
|
||||||
|
"image/png": "png",
|
||||||
|
"video/webm": "webm",
|
||||||
|
"image/gif": "gif",
|
||||||
|
"image/jpeg": "jpg",
|
||||||
|
"image/webp": "webp",
|
||||||
|
"video/mp4": "mp4",
|
||||||
|
"video/quicktime": "mp4",
|
||||||
|
"audio/mpeg": "mpg",
|
||||||
|
"audio/mp3": "mp3",
|
||||||
|
"audio/ogg": "ogg",
|
||||||
|
"audio/flac": "flac",
|
||||||
|
"audio/x-flac": "flac",
|
||||||
|
"video/x-m4v": "mp4"
|
||||||
|
}
|
||||||
|
}
|
32
debug/adduser.mjs
Normal file
32
debug/adduser.mjs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import db from '../src/inc/sql.mjs';
|
||||||
|
import lib from '../src/inc/lib.mjs';
|
||||||
|
|
||||||
|
import readline from 'node:readline/promises';
|
||||||
|
|
||||||
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
||||||
|
|
||||||
|
const newuser = process.argv[2]?.length ? process.argv[2] : await rl.question('username: ');
|
||||||
|
const password = await rl.question('password: ');
|
||||||
|
const level = +(await rl.question('level (0-100): '));
|
||||||
|
|
||||||
|
rl.close();
|
||||||
|
|
||||||
|
if(!newuser.length || !password.length) {
|
||||||
|
console.log('nope lol');
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = (await db`
|
||||||
|
insert into "user" ${
|
||||||
|
db({
|
||||||
|
login: newuser.toLowerCase(),
|
||||||
|
user: newuser,
|
||||||
|
password: await lib.hash(password),
|
||||||
|
level: level >= 0 && level <= 100 ? level : 0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
returning id
|
||||||
|
`)[0]?.id;
|
||||||
|
|
||||||
|
console.log(`created new user ${newuser} with ID ${id}`);
|
||||||
|
process.exit();
|
@ -36,7 +36,7 @@ import lib from "../src/inc/lib.mjs";
|
|||||||
db({
|
db({
|
||||||
item_id: f.id,
|
item_id: f.id,
|
||||||
tag_id: tmp.nsfw ? 2 : 1,
|
tag_id: tmp.nsfw ? 2 : 1,
|
||||||
user_id: 7
|
user_id: 1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -46,8 +46,8 @@ import lib from "../src/inc/lib.mjs";
|
|||||||
insert into "tags_assign" ${
|
insert into "tags_assign" ${
|
||||||
db({
|
db({
|
||||||
item_id: f.id,
|
item_id: f.id,
|
||||||
tag_id: 8, // hentai
|
tag_id: 4, // hentai
|
||||||
user_id: 7 // autotagger
|
user_id: 1 // autotagger
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
214
f0ck.sql
Normal file
214
f0ck.sql
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
\connect "f0ck";
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET lock_timeout = 0;
|
||||||
|
SET idle_in_transaction_session_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = on;
|
||||||
|
SELECT pg_catalog.set_config('search_path', '', false);
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET xmloption = content;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET row_security = off;
|
||||||
|
|
||||||
|
CREATE EXTENSION unaccent;
|
||||||
|
CREATE FUNCTION public.delete_unused_tags() RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
begin
|
||||||
|
delete from tags
|
||||||
|
where
|
||||||
|
tags.id not in (select tag_id from tags_assign) and
|
||||||
|
tags.id = OLD.tag_id and
|
||||||
|
tags.tag != 'sfw' and
|
||||||
|
tags.tag != 'nsfw' and
|
||||||
|
tags.tag != 'hentai' and
|
||||||
|
tags.tag != 'audio';
|
||||||
|
return OLD;
|
||||||
|
end $$;
|
||||||
|
|
||||||
|
ALTER FUNCTION public.delete_unused_tags() OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE FUNCTION public.fill_normalized() RETURNS trigger
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
begin
|
||||||
|
NEW.normalized = slugify(NEW.tag);
|
||||||
|
return NEW;
|
||||||
|
end$$;
|
||||||
|
|
||||||
|
ALTER FUNCTION public.fill_normalized() OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE FUNCTION public.slugify(v text) RETURNS text
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
RETURN trim(BOTH '-' FROM regexp_replace(lower(unaccent(trim(v))), '[\u0000-\u002f \u003a-\u0040\u005b-\u0060\u007b-\u00bf]+', '', 'gi'));
|
||||||
|
END;
|
||||||
|
$$;
|
||||||
|
|
||||||
|
ALTER FUNCTION public.slugify(v text) OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public.favorites (
|
||||||
|
user_id integer NOT NULL,
|
||||||
|
item_id integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE public.favorites OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.items_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
ALTER TABLE public.items_id_seq OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public.items (
|
||||||
|
id integer DEFAULT nextval('public.items_id_seq'::regclass) NOT NULL,
|
||||||
|
src character varying(255) NOT NULL,
|
||||||
|
dest character varying(40) NOT NULL,
|
||||||
|
mime character varying(100) NOT NULL,
|
||||||
|
size integer NOT NULL,
|
||||||
|
checksum character varying(255) NOT NULL,
|
||||||
|
username character varying(40) NOT NULL,
|
||||||
|
userchannel character varying(100) NOT NULL,
|
||||||
|
usernetwork character varying(40) NOT NULL,
|
||||||
|
stamp integer NOT NULL,
|
||||||
|
active boolean NOT NULL,
|
||||||
|
thumb character varying(100)
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE public.items OWNER TO f0ck;
|
||||||
|
|
||||||
|
COMMENT ON COLUMN public.items.src IS 'src-Link';
|
||||||
|
COMMENT ON COLUMN public.items.dest IS 'filename';
|
||||||
|
|
||||||
|
CREATE SEQUENCE public.tags_id_seq
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
ALTER TABLE public.tags_id_seq OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public.tags (
|
||||||
|
id integer DEFAULT nextval('public.tags_id_seq'::regclass) NOT NULL,
|
||||||
|
tag character varying(45) NOT NULL,
|
||||||
|
normalized character varying(45) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE public.tags OWNER TO 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;
|
||||||
|
|
||||||
|
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
|
||||||
|
START WITH 1
|
||||||
|
INCREMENT BY 1
|
||||||
|
NO MINVALUE
|
||||||
|
NO MAXVALUE
|
||||||
|
CACHE 1;
|
||||||
|
|
||||||
|
ALTER TABLE public.user_id_seq OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public."user" (
|
||||||
|
id integer DEFAULT nextval('public.user_id_seq'::regclass) NOT NULL,
|
||||||
|
login character varying(255) NOT NULL,
|
||||||
|
"user" character varying(255) NOT NULL,
|
||||||
|
password character varying(167) NOT NULL,
|
||||||
|
level integer NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
ALTER TABLE public."user" OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public.user_options (
|
||||||
|
user_id integer NOT NULL,
|
||||||
|
mode integer NOT NULL,
|
||||||
|
theme character varying(50) NOT NULL,
|
||||||
|
avatar integer DEFAULT 1 NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
ALTER TABLE public.user_sessions_id_seq OWNER TO f0ck;
|
||||||
|
|
||||||
|
CREATE TABLE public.user_sessions (
|
||||||
|
id integer DEFAULT nextval('public.user_sessions_id_seq'::regclass) NOT NULL,
|
||||||
|
user_id integer NOT NULL,
|
||||||
|
session character varying(32) NOT NULL,
|
||||||
|
browser character varying(255) NOT NULL,
|
||||||
|
created_at integer NOT NULL,
|
||||||
|
last_used integer NOT NULL,
|
||||||
|
last_action character varying(255) NOT NULL,
|
||||||
|
kmsi smallint DEFAULT '0'::smallint NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
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
|
||||||
|
\.
|
||||||
|
|
||||||
|
COPY public.tags (id, tag, normalized) FROM stdin;
|
||||||
|
1 sfw sfw
|
||||||
|
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
|
||||||
|
2 deleted deleted f0ck you 0
|
||||||
|
\.
|
||||||
|
|
||||||
|
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_bi BEFORE INSERT 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;
|
||||||
|
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.user_options ADD CONSTRAINT user_options_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(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;
|
37
package-lock.json
generated
37
package-lock.json
generated
@ -9,18 +9,18 @@
|
|||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuffeo": "^1.0.7-3",
|
"cuffeo": "^1.1.0",
|
||||||
"flumm-fetch": "^1.0.1",
|
"flumm-fetch": "^1.0.1",
|
||||||
"flummpress": "^2.0.5",
|
"flummpress": "^2.0.5",
|
||||||
"postgres": "^3.0.1"
|
"postgres": "^3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cuffeo": {
|
"node_modules/cuffeo": {
|
||||||
"version": "1.0.7-3",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.0.7-3.tgz",
|
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.1.0.tgz",
|
||||||
"integrity": "sha512-Lz8AlLdFWeLLGsf6KBXTHnpseeMbuQH69BamhZr8O9Se9pzuHQgv/ed13n2XWreN0RTyRa49YPtsNVwoQnNrLw==",
|
"integrity": "sha512-7lmx2dvREqCYwy8oUzk3Q0EkyLZkKQTYTBLEjNqKVbinzdEL45Oimi54lmBDFPlrrvTLzQkFvzKmiJ7Zcegi2w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flumm-fetch-cookies": "^1.4.0"
|
"flumm-fetch": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/flumm-fetch": {
|
"node_modules/flumm-fetch": {
|
||||||
@ -28,17 +28,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/flumm-fetch/-/flumm-fetch-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/flumm-fetch/-/flumm-fetch-1.0.1.tgz",
|
||||||
"integrity": "sha512-pZ5U0hheCSW43vfGZQMunr03U7rUOX+iy2y13Tu4nc3iRL+E/Qfeo5nZ2B2JMYKOGIx1A1anUYOz+ulyhouyjg=="
|
"integrity": "sha512-pZ5U0hheCSW43vfGZQMunr03U7rUOX+iy2y13Tu4nc3iRL+E/Qfeo5nZ2B2JMYKOGIx1A1anUYOz+ulyhouyjg=="
|
||||||
},
|
},
|
||||||
"node_modules/flumm-fetch-cookies": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/flumm-fetch-cookies/-/flumm-fetch-cookies-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-OHGUak5iHl9GoDdbkAMsrL9ONkFQ8opd0jYQ9lMUuGVqIP+JPbyzQqElhpwJxLaV/WSE4LR/2dnHoguFHFSLFA==",
|
|
||||||
"dependencies": {
|
|
||||||
"flumm-fetch": "^1.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=11.14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/flummpress": {
|
"node_modules/flummpress": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
||||||
@ -56,11 +45,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuffeo": {
|
"cuffeo": {
|
||||||
"version": "1.0.7-3",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.0.7-3.tgz",
|
"resolved": "https://registry.npmjs.org/cuffeo/-/cuffeo-1.1.0.tgz",
|
||||||
"integrity": "sha512-Lz8AlLdFWeLLGsf6KBXTHnpseeMbuQH69BamhZr8O9Se9pzuHQgv/ed13n2XWreN0RTyRa49YPtsNVwoQnNrLw==",
|
"integrity": "sha512-7lmx2dvREqCYwy8oUzk3Q0EkyLZkKQTYTBLEjNqKVbinzdEL45Oimi54lmBDFPlrrvTLzQkFvzKmiJ7Zcegi2w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"flumm-fetch-cookies": "^1.4.0"
|
"flumm-fetch": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flumm-fetch": {
|
"flumm-fetch": {
|
||||||
@ -68,14 +57,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/flumm-fetch/-/flumm-fetch-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/flumm-fetch/-/flumm-fetch-1.0.1.tgz",
|
||||||
"integrity": "sha512-pZ5U0hheCSW43vfGZQMunr03U7rUOX+iy2y13Tu4nc3iRL+E/Qfeo5nZ2B2JMYKOGIx1A1anUYOz+ulyhouyjg=="
|
"integrity": "sha512-pZ5U0hheCSW43vfGZQMunr03U7rUOX+iy2y13Tu4nc3iRL+E/Qfeo5nZ2B2JMYKOGIx1A1anUYOz+ulyhouyjg=="
|
||||||
},
|
},
|
||||||
"flumm-fetch-cookies": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/flumm-fetch-cookies/-/flumm-fetch-cookies-1.4.0.tgz",
|
|
||||||
"integrity": "sha512-OHGUak5iHl9GoDdbkAMsrL9ONkFQ8opd0jYQ9lMUuGVqIP+JPbyzQqElhpwJxLaV/WSE4LR/2dnHoguFHFSLFA==",
|
|
||||||
"requires": {
|
|
||||||
"flumm-fetch": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flummpress": {
|
"flummpress": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/flummpress/-/flummpress-2.0.5.tgz",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "f0ckv2",
|
"name": "f0ckv2",
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"description": "f0ck, kennste?",
|
"description": "f0ck, kennste?",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -9,12 +9,13 @@
|
|||||||
"autotagger": "node --experimental-json-modules debug/autotagger.mjs",
|
"autotagger": "node --experimental-json-modules debug/autotagger.mjs",
|
||||||
"thumbnailer": "node --experimental-json-modules debug/thumbnailer.mjs",
|
"thumbnailer": "node --experimental-json-modules debug/thumbnailer.mjs",
|
||||||
"test": "node --experimental-json-modules debug/test.mjs",
|
"test": "node --experimental-json-modules debug/test.mjs",
|
||||||
"clean": "node --experimental-json-modules debug/clean.mjs"
|
"clean": "node --experimental-json-modules debug/clean.mjs",
|
||||||
|
"adduser": "node --experimental-json-modules debug/adduser.mjs"
|
||||||
},
|
},
|
||||||
"author": "Flummi",
|
"author": "Flummi",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cuffeo": "^1.0.7-3",
|
"cuffeo": "^1.1.0",
|
||||||
"flumm-fetch": "^1.0.1",
|
"flumm-fetch": "^1.0.1",
|
||||||
"flummpress": "^2.0.5",
|
"flummpress": "^2.0.5",
|
||||||
"postgres": "^3.0.1"
|
"postgres": "^3.0.1"
|
||||||
|
0
public/b/.empty
Executable file → Normal file
0
public/b/.empty
Executable file → Normal file
BIN
public/b/b761fa9339.png
Executable file
BIN
public/b/b761fa9339.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
File diff suppressed because it is too large
Load Diff
@ -3,8 +3,8 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg">
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
<!-- Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
<!-- Font Awesome Free 5.15.3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) -->
|
||||||
<defs>
|
<defs>
|
||||||
<symbol style="fill: var(--accent)" id="heart_regular" viewBox="0 0 512 512"><path d="M458.4 64.3C400.6 15.7 311.3 23 256 79.3 200.7 23 111.4 15.6 53.6 64.3-21.6 127.6-10.6 230.8 43 285.5l175.4 178.7c10 10.2 23.4 15.9 37.6 15.9 14.3 0 27.6-5.6 37.6-15.8L469 285.6c53.5-54.7 64.7-157.9-10.6-221.3zm-23.6 187.5L259.4 430.5c-2.4 2.4-4.4 2.4-6.8 0L77.2 251.8c-36.5-37.2-43.9-107.6 7.3-150.7 38.9-32.7 98.9-27.8 136.5 10.5l35 35.7 35-35.7c37.8-38.5 97.8-43.2 136.5-10.6 51.1 43.1 43.5 113.9 7.3 150.8z"/></symbol>
|
<symbol id="heart_regular" viewBox="0 0 512 512"><path d="M458.4 64.3C400.6 15.7 311.3 23 256 79.3 200.7 23 111.4 15.6 53.6 64.3-21.6 127.6-10.6 230.8 43 285.5l175.4 178.7c10 10.2 23.4 15.9 37.6 15.9 14.3 0 27.6-5.6 37.6-15.8L469 285.6c53.5-54.7 64.7-157.9-10.6-221.3zm-23.6 187.5L259.4 430.5c-2.4 2.4-4.4 2.4-6.8 0L77.2 251.8c-36.5-37.2-43.9-107.6 7.3-150.7 38.9-32.7 98.9-27.8 136.5 10.5l35 35.7 35-35.7c37.8-38.5 97.8-43.2 136.5-10.6 51.1 43.1 43.5 113.9 7.3 150.8z"/></symbol>
|
||||||
<symbol style="fill: var(--accent)" id="heart_solid" viewBox="0 0 512 512"><path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z"/></symbol>
|
<symbol id="heart_solid" viewBox="0 0 512 512"><path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z"/></symbol>
|
||||||
<symbol id="cross" viewBox="0 0 512 512"><path d="M53.6,62.3 L458.4,458.4 M458.4,62.3 L53.6,458.4" style="stroke-linecap: round;stroke-width: 60;stroke: var(--accent);"/></symbol>
|
<symbol id="cross" viewBox="0 0 512 512"><path d="M53.6,62.3 L458.4,458.4 M458.4,62.3 L53.6,458.4" style="stroke-linecap: round;stroke-width: 60;"/></symbol>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.3 KiB |
@ -101,6 +101,7 @@ const flash = ({ type, msg }) => {
|
|||||||
delbutton.href = "#";
|
delbutton.href = "#";
|
||||||
delbutton.addEventListener("click", deleteEvent);
|
delbutton.addEventListener("click", deleteEvent);
|
||||||
span.insertAdjacentElement("beforeend", a);
|
span.insertAdjacentElement("beforeend", a);
|
||||||
|
span.innerHTML += ' ';
|
||||||
span.insertAdjacentElement("beforeend", delbutton);
|
span.insertAdjacentElement("beforeend", delbutton);
|
||||||
|
|
||||||
document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
|
document.querySelector("#tags").insertAdjacentElement("afterbegin", span);
|
||||||
@ -287,6 +288,7 @@ const flash = ({ type, msg }) => {
|
|||||||
|
|
||||||
textfield.addEventListener("keyup", async e => {
|
textfield.addEventListener("keyup", async e => {
|
||||||
if(e.key === 'Enter') {
|
if(e.key === 'Enter') {
|
||||||
|
parent.removeChild(textfield);
|
||||||
// send
|
// send
|
||||||
let res = await fetch('/api/v2/admin/tags/' + encodeURIComponent(oldtag), {
|
let res = await fetch('/api/v2/admin/tags/' + encodeURIComponent(oldtag), {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
@ -303,7 +305,7 @@ const flash = ({ type, msg }) => {
|
|||||||
switch(status) {
|
switch(status) {
|
||||||
case 200: // success, change
|
case 200: // success, change
|
||||||
case 201:
|
case 201:
|
||||||
parent.removeChild(textfield);
|
//parent.removeChild(textfield);
|
||||||
parent.insertAdjacentElement('afterbegin', old);
|
parent.insertAdjacentElement('afterbegin', old);
|
||||||
parent.querySelector('a:last-child').style.display = '';
|
parent.querySelector('a:last-child').style.display = '';
|
||||||
old.href = `/tag/${res.tag}`;
|
old.href = `/tag/${res.tag}`;
|
||||||
|
@ -29,6 +29,8 @@
|
|||||||
};
|
};
|
||||||
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") {
|
||||||
|
if(e.shiftKey || e.ctrlKey || e.metaKey || e.altKey)
|
||||||
|
return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
keybindings[e.key]();
|
keybindings[e.key]();
|
||||||
}
|
}
|
||||||
@ -56,7 +58,7 @@
|
|||||||
: f0ckimagescroll.setAttribute("style", "overflow-y: scroll");
|
: f0ckimagescroll.setAttribute("style", "overflow-y: scroll");
|
||||||
f0ckimage.hasAttribute("style")
|
f0ckimage.hasAttribute("style")
|
||||||
? f0ckimage.removeAttribute("style")
|
? f0ckimage.removeAttribute("style")
|
||||||
: f0ckimage.setAttribute("style", "max-height: none; height: auto; width: 100%; position: absolute; left: 0;");
|
: f0ckimage.setAttribute("style", "max-height: none; height: auto; width: 100%; position: absolute; left: 0; border: var(--img-border-width) solid var(--img-border-color); border-top: none; border-bottom: none;");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// </image-responsive>
|
// </image-responsive>
|
||||||
@ -64,13 +66,13 @@
|
|||||||
// <scroller>
|
// <scroller>
|
||||||
let tts = 0;
|
let tts = 0;
|
||||||
const scroll_treshold = 1;
|
const scroll_treshold = 1;
|
||||||
if(document.querySelector("div#posts")) {
|
if([...document.querySelectorAll("div.posts")].length === 1) {
|
||||||
document.addEventListener("wheel", e => {
|
document.addEventListener("wheel", e => {
|
||||||
if(Math.ceil(window.innerHeight + window.scrollY) >= document.body.offsetHeight && e.deltaY > 0) { // down
|
if(Math.ceil(window.innerHeight + window.scrollY) >= document.body.offsetHeight && e.deltaY > 0) { // down
|
||||||
if(elem = document.querySelector(".pagination > .next:not(.disabled)")) {
|
if(elem = document.querySelector(".pagination > .next:not(.disabled)")) {
|
||||||
if(tts < scroll_treshold) {
|
if(tts < scroll_treshold) {
|
||||||
document.querySelector("div#footbar").style.boxShadow = "inset 0px 4px 0px var(--accent)";
|
document.querySelector("div#footbar").style.boxShadow = "inset 0px 4px 0px var(--footbar-color)";
|
||||||
document.querySelector("div#footbar").style.color = "var(--accent)";
|
document.querySelector("div#footbar").style.color = "var(--footbar-color)";
|
||||||
tts++;
|
tts++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -80,7 +82,7 @@
|
|||||||
else if(window.scrollY <= 0 && e.deltaY < 0) { // up
|
else if(window.scrollY <= 0 && e.deltaY < 0) { // up
|
||||||
if(elem = document.querySelector(".pagination > .prev:not(.disabled)")) {
|
if(elem = document.querySelector(".pagination > .prev:not(.disabled)")) {
|
||||||
if(tts < scroll_treshold) {
|
if(tts < scroll_treshold) {
|
||||||
document.querySelector("nav.navbar").style.boxShadow = "0px 2px 0px var(--accent)";
|
document.querySelector("nav.navbar").style.boxShadow = "0px 2px 0px var(--loading-indicator-color)";
|
||||||
document.querySelector("nav.navbar").style.transition = ".2s ease-in-out";
|
document.querySelector("nav.navbar").style.transition = ".2s ease-in-out";
|
||||||
tts++;
|
tts++;
|
||||||
}
|
}
|
||||||
@ -150,10 +152,10 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(Math.abs(swipeRT.yDiff) > swipeOpt.treshold && timeDiff < swipeOpt.timeout) {
|
if(Math.abs(swipeRT.yDiff) > swipeOpt.treshold && timeDiff < swipeOpt.timeout) {
|
||||||
if(navbar = document.querySelector("nav.navbar") && document.querySelector("div#posts")) {
|
if(navbar = document.querySelector("nav.navbar") && document.querySelector("div.posts")) {
|
||||||
if(swipeRT.yDiff > 0 && (window.innerHeight + window.scrollY) >= document.body.offsetHeight) // up
|
if(swipeRT.yDiff > 0 && (window.innerHeight + window.scrollY) >= document.body.offsetHeight) // up
|
||||||
elem = document.querySelector(".pagination > .next:not(.disabled)");
|
elem = document.querySelector(".pagination > .next:not(.disabled)");
|
||||||
else if(swipeRT.yDiff <= 0 && window.scrollY <= 0 && document.querySelector("div#posts")) // down
|
else if(swipeRT.yDiff <= 0 && window.scrollY <= 0 && document.querySelector("div.posts")) // down
|
||||||
elem = document.querySelector(".pagination > .prev:not(.disabled)");
|
elem = document.querySelector(".pagination > .prev:not(.disabled)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
public/t/1.webp
Executable file
BIN
public/t/1.webp
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
@ -20,7 +20,7 @@ export default async bot => {
|
|||||||
|
|
||||||
let trigger;
|
let trigger;
|
||||||
|
|
||||||
if(e.photo) {
|
if(e.media) {
|
||||||
trigger = [...bot._trigger.entries()].filter(t => t[1].name === "parser");
|
trigger = [...bot._trigger.entries()].filter(t => t[1].name === "parser");
|
||||||
if(!e.message)
|
if(!e.message)
|
||||||
e.message = "";
|
e.message = "";
|
||||||
|
@ -63,7 +63,7 @@ export default new class {
|
|||||||
const link = [];
|
const link = [];
|
||||||
if(env.tag) link.push("tag", env.tag);
|
if(env.tag) link.push("tag", env.tag);
|
||||||
if(env.user) link.push("user", env.user, env.type ?? 'f0cks');
|
if(env.user) link.push("user", env.user, env.type ?? 'f0cks');
|
||||||
if(env.mime.length > 2) link.push(env.mime);
|
if(env.mime?.length > 2) link.push(env.mime);
|
||||||
|
|
||||||
let tmp = link.length === 0 ? '/' : link.join('/');
|
let tmp = link.length === 0 ? '/' : link.join('/');
|
||||||
if(!tmp.endsWith('/'))
|
if(!tmp.endsWith('/'))
|
||||||
@ -162,14 +162,13 @@ export default new class {
|
|||||||
return tags;
|
return tags;
|
||||||
};
|
};
|
||||||
async detectNSFW(dest) {
|
async detectNSFW(dest) {
|
||||||
|
return false;
|
||||||
const { stdout, stderr } = await exec(
|
const { stdout, stderr } = await exec(
|
||||||
`python -c "import sys\nfrom nsfw_detector import predict\nmodel = predict.load_model('./nsfw_model.h5')\nprint(predict.classify(model, './public/b/${dest}'))"`
|
`python -c "import sys\nfrom nsfw_detector import predict\nmodel = predict.load_model('./nsfw_model.h5')\nprint(predict.classify(model, './public/b/${dest}'))"`
|
||||||
);
|
);
|
||||||
const res = JSON.parse(stdout.replace(/\'/g, '"').split('\n').slice(1, -1));
|
const res = JSON.parse(stdout.replace(/\'/g, '"').split('\n').slice(1, -1));
|
||||||
const tmp = Object.values(res)[0];
|
const tmp = Object.values(res)[0];
|
||||||
|
|
||||||
tmp.sexy = tmp.sexy / 2;
|
|
||||||
|
|
||||||
let nsfw = false;
|
let nsfw = false;
|
||||||
if(tmp.neutral >= .7)
|
if(tmp.neutral >= .7)
|
||||||
nsfw = false;
|
nsfw = false;
|
||||||
@ -187,5 +186,15 @@ export default new class {
|
|||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
async getDefaultAvatar() {
|
||||||
|
return (await db`
|
||||||
|
select column_default as avatar
|
||||||
|
from "information_schema"."columns"
|
||||||
|
where
|
||||||
|
TABLE_SCHEMA='public' and
|
||||||
|
TABLE_NAME='user_options' and
|
||||||
|
COLUMN_NAME = 'avatar'
|
||||||
|
`)[0].avatar;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -4,158 +4,74 @@ import cfg from "../config.mjs";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import url from "url";
|
import url from "url";
|
||||||
|
|
||||||
|
const globalfilter = cfg.nsfp.map(n => `tag_id = ${n}`).join(' or ');
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getf0cks: async (o = { user, tag, mime, page, mode, fav }) => {
|
getf0cks: async (o = { user, tag, mime, page, mode, fav, 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 ?? 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 tmp = { user, tag, mime, smime, page };
|
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);
|
||||||
|
|
||||||
let data;
|
const total = (await db`
|
||||||
let total;
|
select distinct on (items.id)
|
||||||
|
count(items.id) as total
|
||||||
if(tag) {
|
|
||||||
if(tag.match(/sfw/) || tag.length <= 2)
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "nope."
|
|
||||||
};
|
|
||||||
|
|
||||||
total = await db`
|
|
||||||
select count(*) as total
|
|
||||||
from items
|
from items
|
||||||
inner join (
|
left join tags_assign on tags_assign.item_id = items.id
|
||||||
select tags_assign.item_id, tags.tag
|
left join tags on tags.id = tags_assign.tag_id
|
||||||
from tags
|
left join favorites on favorites.item_id = items.id
|
||||||
left join tags_assign on tags_assign.tag_id = tags.id
|
left join "user" on "user".id = favorites.user_id
|
||||||
where tags.tag ilike ${'%' + (tag ? tag : '') + '%'}
|
where
|
||||||
group by tags_assign.item_id, tags.tag
|
${ db.unsafe(modequery) }
|
||||||
) as st on st.item_id = items.id
|
and items.active = 'true'
|
||||||
where ${db.unsafe(modequery)}
|
${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` }
|
||||||
group by st.tag, st.item_id`;
|
${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` }
|
||||||
|
${ !o.fav && user ? db`and items.username ilike ${'%'+user+'%'}` : db`` }
|
||||||
|
${ mime ? db`and items.mime ilike ${smime}` : db`` }
|
||||||
|
${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` }
|
||||||
|
group by items.id, tags.tag
|
||||||
|
`)?.length || 0;
|
||||||
|
|
||||||
total = total?.length;
|
if(!total || total === 0) {
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(!o.fav) {
|
|
||||||
total = await db`
|
|
||||||
select count(*) as total
|
|
||||||
from items
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
and items.mime ilike ${smime}
|
|
||||||
and items.username ilike ${user ? user : '%'}
|
|
||||||
`;
|
|
||||||
total = total[0].total;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
total = await db`
|
|
||||||
select count(*) as total
|
|
||||||
from "favorites"
|
|
||||||
left join "user" on "user".id = "favorites".user_id
|
|
||||||
left join "tags_assign" on "tags_assign".item_id = "favorites".item_id
|
|
||||||
left join "tags" on "tags".id = "tags_assign".tag_id
|
|
||||||
left join "items" on "items".id = "favorites".item_id
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
and "items".mime ilike ${smime}
|
|
||||||
and "user".user ilike ${user}
|
|
||||||
group by "items".id
|
|
||||||
`;
|
|
||||||
total = total[0].total;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!total || total.length === 0)
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "404 - no f0cks given"
|
message: "404 - no f0cks given"
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const pages = +Math.ceil(total / cfg.websrv.eps);
|
const pages = +Math.ceil(total / cfg.websrv.eps);
|
||||||
const act_page = Math.min(pages, page || 1);
|
const act_page = Math.min(pages, page || 1);
|
||||||
const offset = Math.max(0, (act_page - 1) * cfg.websrv.eps);
|
const offset = Math.max(0, (act_page - 1) * cfg.websrv.eps);
|
||||||
|
|
||||||
let rows;
|
const rows = await db`
|
||||||
|
select distinct on (items.id)
|
||||||
if(!o.fav) {
|
items.id,
|
||||||
rows = db`
|
items.mime,
|
||||||
select "items".id, "items".mime, "tags_assign".tag_id
|
tags.tag,
|
||||||
from "items"
|
ta.tag_id
|
||||||
left join "tags_assign" on "tags_assign".item_id = "items".id and ("tags_assign".tag_id = 1 or "tags_assign".tag_id = 2)
|
from items
|
||||||
${tag
|
left join tags_assign on tags_assign.item_id = items.id
|
||||||
? db`
|
left join tags on tags.id = tags_assign.tag_id
|
||||||
inner join (
|
left join favorites on favorites.item_id = items.id
|
||||||
select "tags_assign".item_id, "tags".tag
|
left join "user" on "user".id = favorites.user_id
|
||||||
from "tags"
|
left join tags_assign ta on ta.item_id = items.id and (ta.tag_id = 1 or ta.tag_id = 2)
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
where
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
${ db.unsafe(modequery) }
|
||||||
group by "tags_assign".item_id, "tags".tag
|
and items.active = 'true'
|
||||||
) as st on st.item_id = "items".id
|
${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` }
|
||||||
`
|
${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` }
|
||||||
: db``
|
${ !o.fav && user ? db`and items.username ilike ${'%'+user+'%'}` : db`` }
|
||||||
}
|
${ mime ? db`and items.mime ilike ${smime}` : db`` }
|
||||||
where ${db.unsafe(modequery)}
|
${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` }
|
||||||
and "items".mime ilike ${smime}
|
group by items.id, tags.tag, ta.tag_id
|
||||||
and "items".username ilike ${user ? user : '%'}
|
order by items.id desc
|
||||||
${tag
|
|
||||||
? db`group by st.item_id, "items".id, "tags_assign".tag_id`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
order by "items".id desc
|
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
limit ${cfg.websrv.eps}
|
limit ${cfg.websrv.eps}
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
else {
|
|
||||||
rows = db`
|
|
||||||
select "items".id, "items".mime, ta.tag_id
|
|
||||||
from "favorites"
|
|
||||||
left join "user" on "user".id = "favorites".user_id
|
|
||||||
left join "tags_assign" on "tags_assign".item_id = "favorites".item_id
|
|
||||||
left join "tags" on "tags".id = "tags_assign".tag_id
|
|
||||||
left join "items" on "items".id = "favorites".item_id
|
|
||||||
left join "tags_assign" as ta on ta.item_id = "items".id and (ta.tag_id = 1 or ta.tag_id = 2)
|
|
||||||
${ tag
|
|
||||||
? db`
|
|
||||||
inner join (
|
|
||||||
select "tags_assign".item_id, "tags".tag
|
|
||||||
from "tags"
|
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
|
||||||
group by "tags_assign".item_id, "tags".tag
|
|
||||||
) as st on st.item_id = "items".id`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
and "items".mime ilike ${smime}
|
|
||||||
and "user".user ilike ${user}
|
|
||||||
${tag
|
|
||||||
? db`group by st.item_id, "items".id, "tags_assign".tag_id`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
group by "items".id, ta.tag_id
|
|
||||||
order by "items".id desc
|
|
||||||
offset ${offset}
|
|
||||||
limit ${cfg.websrv.eps}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
rows = await rows;
|
|
||||||
|
|
||||||
if(rows.length === 0)
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
message: "oopsi woopsi"
|
|
||||||
};
|
|
||||||
|
|
||||||
/*rows.forEach(e => {
|
|
||||||
if(!fs.existsSync(`public/t/${e.id}.png`))
|
|
||||||
fs.copyFileSync("public/s/img/broken.png", `public/t/${e.id}.png`);
|
|
||||||
});*/
|
|
||||||
|
|
||||||
const cheat = [];
|
const cheat = [];
|
||||||
for(let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
for(let i = Math.max(1, act_page - 3); i <= Math.min(act_page + 3, pages); i++)
|
||||||
@ -163,7 +79,7 @@ export default {
|
|||||||
|
|
||||||
const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks', path: 'p/' });
|
const link = lib.genLink({ user, tag, mime, type: o.fav ? 'favs' : 'f0cks', path: 'p/' });
|
||||||
|
|
||||||
data = {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
items: rows,
|
items: rows,
|
||||||
pagination: {
|
pagination: {
|
||||||
@ -177,9 +93,8 @@ export default {
|
|||||||
link,
|
link,
|
||||||
tmp
|
tmp
|
||||||
};
|
};
|
||||||
return data;
|
|
||||||
},
|
},
|
||||||
getf0ck: async (o = ({ user, tag, mime, itemid, mode })) => {
|
getf0ck: async (o = ({ user, tag, mime, itemid, 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 ?? "");
|
||||||
@ -197,74 +112,26 @@ export default {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let items;
|
const items = await db`
|
||||||
|
select distinct on (items.id)
|
||||||
if(o.fav) {
|
items.*
|
||||||
items = db`
|
from items
|
||||||
select "items".*
|
left join tags_assign on tags_assign.item_id = items.id
|
||||||
from "favorites"
|
left join tags on tags.id = tags_assign.tag_id
|
||||||
left join "items" on "items".id = "favorites".item_id
|
left join favorites on favorites.item_id = items.id
|
||||||
left join "user" on "user".id = "favorites".user_id
|
left join "user" on "user".id = favorites.user_id
|
||||||
${ tag
|
left join tags_assign ta on ta.item_id = items.id and (ta.tag_id = 1 or ta.tag_id = 2)
|
||||||
? db`
|
where
|
||||||
inner join (
|
${ db.unsafe(modequery) }
|
||||||
select "tags_assign".item_id, "tags".tag
|
and items.active = 'true'
|
||||||
from "tags"
|
${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` }
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` }
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
${ !o.fav && user ? db`and items.username ilike ${'%'+user+'%'}` : db`` }
|
||||||
group by "tags_assign".item_id, "tags".tag
|
${ mime ? db`and items.mime ilike ${smime}` : db`` }
|
||||||
) as st on st.item_id = "items".id`
|
${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` }
|
||||||
: db``
|
group by items.id, tags.tag, ta.tag_id
|
||||||
}
|
order by items.id desc
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
and "user".user ilike ${user}
|
|
||||||
${ mime
|
|
||||||
? db`and "items".mime ilike ${mime + '/%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
${ tag
|
|
||||||
? db`group by st.tag, st.item_id, "items".id`
|
|
||||||
: db`group by "items".id, "favorites".user_id, "favorites".item_id, "user".id`
|
|
||||||
}
|
|
||||||
order by "items".id desc
|
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
else {
|
|
||||||
items = db`
|
|
||||||
select "items".*
|
|
||||||
from "items"
|
|
||||||
${ tag
|
|
||||||
? db`
|
|
||||||
inner join (
|
|
||||||
select "tags_assign".item_id, "tags_assign".tag_id, "tags".tag
|
|
||||||
from "tags"
|
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
|
||||||
group by "tags_assign".item_id, "tags".tag, "tags_assign".tag_id
|
|
||||||
) as st on st.item_id = "items".id`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
${ user
|
|
||||||
? db`and "items".username ilike ${'%' + user + '%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
${ mime
|
|
||||||
? db`and "items".mime ilike ${mime + '/%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
${ tag
|
|
||||||
? db`group by st.item_id, "items".id, st.tag_id`
|
|
||||||
: db`group by "items".id`
|
|
||||||
}
|
|
||||||
order by "items".id desc
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
items = await items;
|
|
||||||
|
|
||||||
if(tag)
|
|
||||||
items = items.filter((v, i, s) => i === s.findIndex(t => t.id === v.id));
|
|
||||||
|
|
||||||
const item = items.findIndex(i => i.id === itemid);
|
const item = items.findIndex(i => i.id === itemid);
|
||||||
const actitem = items[item];
|
const actitem = items[item];
|
||||||
@ -334,71 +201,34 @@ export default {
|
|||||||
};
|
};
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
getRandom: async (o = ({ user, tag, mime, mode })) => {
|
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 modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
|
const modequery = mime == "audio" ? lib.getMode(0) : lib.getMode(o.mode ?? 0);
|
||||||
|
|
||||||
let item;
|
const item = await db`
|
||||||
if(o.fav) { // dood lol
|
select
|
||||||
item = db`
|
items.id
|
||||||
select "items".*
|
from items
|
||||||
from "favorites"
|
left join tags_assign on tags_assign.item_id = items.id
|
||||||
left join "items" on "items".id = "favorites".item_id
|
left join tags on tags.id = tags_assign.tag_id
|
||||||
left join "user" on "user".id = "favorites".user_id
|
left join favorites on favorites.item_id = items.id
|
||||||
${ tag
|
left join "user" on "user".id = favorites.user_id
|
||||||
? db`
|
where
|
||||||
inner join (
|
${ db.unsafe(modequery) }
|
||||||
select "tags_assign".item_id, "tags".tag
|
and items.active = 'true'
|
||||||
from "tags"
|
${ tag ? db`and tags.normalized ilike '%' || slugify(${tag}) || '%'` : db`` }
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
${ o.fav ? db`and "user".user ilike ${'%'+user+'%'}` : db`` }
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
${ user ? db`and items.username ilike ${'%'+user+'%'}` : db`` }
|
||||||
group by "tags_assign".item_id, "tags".tag
|
${ mime ? db`and items.mime ilike ${smime}` : db`` }
|
||||||
) as st on st.item_id = "items".id`
|
${ !o.session ? db`and items.id not in (select item_id from tags_assign where item_id = items.id and (${db.unsafe(globalfilter)}))` : db`` }
|
||||||
: db``
|
group by items.id, tags.tag
|
||||||
}
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
and "user".user ilike ${user}
|
|
||||||
${ mime
|
|
||||||
? db`and "items".mime ilike ${mime + '/%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
order by random()
|
order by random()
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
}
|
|
||||||
else {
|
|
||||||
item = db`
|
|
||||||
select *
|
|
||||||
from "items"
|
|
||||||
${ tag
|
|
||||||
? db`
|
|
||||||
inner join (
|
|
||||||
select "tags_assign".item_id, "tags".tag
|
|
||||||
from "tags"
|
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
|
||||||
group by "tags_assign".item_id, "tags".tag
|
|
||||||
) as st on st.item_id = "items".id`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
where ${db.unsafe(modequery)}
|
|
||||||
${ user
|
|
||||||
? db`and "items".username ilike ${'%' + user + '%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
${ mime
|
|
||||||
? db`and "items".mime ilike ${mime + '/%'}`
|
|
||||||
: db``
|
|
||||||
}
|
|
||||||
order by random()
|
|
||||||
limit 1
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = await item;
|
|
||||||
|
|
||||||
if(item.length === 0) {
|
if(item.length === 0) {
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import db from "../sql.mjs";
|
import db from "../sql.mjs";
|
||||||
import lib from "../lib.mjs";
|
import lib from "../lib.mjs";
|
||||||
import { exec } from "child_process";
|
import { exec } from "child_process";
|
||||||
|
import { promises as fs } from "fs";
|
||||||
|
|
||||||
const auth = async (req, res, next) => {
|
const auth = async (req, res, next) => {
|
||||||
if(!req.session) {
|
if(!req.session) {
|
||||||
@ -130,5 +131,61 @@ export default (router, tpl) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get(/^\/admin\/recover\/?/, auth, async (req, res) => {
|
||||||
|
if(req.url.qs?.id) {
|
||||||
|
const id = +req.url.qs.id;
|
||||||
|
const f0ck = await db`
|
||||||
|
select dest, mime
|
||||||
|
from "items"
|
||||||
|
where
|
||||||
|
id = ${id} and
|
||||||
|
active = 'false'
|
||||||
|
limit 1
|
||||||
|
`;
|
||||||
|
if(f0ck.length === 0) {
|
||||||
|
return res.reply({
|
||||||
|
body: `f0ck ${id}: f0ck not found`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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/t/${id}.webp`, `./public/t/${id}.webp`).catch(_=>{});
|
||||||
|
await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
|
await fs.unlink(`./deleted/t/${id}.webp`).catch(_=>{});
|
||||||
|
|
||||||
|
if(f0ck[0].mime.startsWith('audio')) {
|
||||||
|
await fs.copyFile(`./deleted/ca/${id}.webp`, `./public/ca/${id}.webp`).catch(_=>{});
|
||||||
|
await fs.unlink(`./deleted/ca/${id}.webp`).catch(_=>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.reply({
|
||||||
|
body: `f0ck ${id} recovered. <a href="/admin/recover">back</a>`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const _posts = await db`
|
||||||
|
select id, mime, username
|
||||||
|
from "items"
|
||||||
|
where
|
||||||
|
active = 'false'
|
||||||
|
`;
|
||||||
|
|
||||||
|
if(_posts.length === 0) {
|
||||||
|
return res.reply({
|
||||||
|
body: 'blah'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const posts = await Promise.all(_posts.map(async p => ({ ...p, thumbnail: (await fs.readFile(`./deleted/t/${p.id}.webp`)).toString('base64') })));
|
||||||
|
|
||||||
|
res.reply({
|
||||||
|
body: tpl.render('admin/recover', {
|
||||||
|
posts
|
||||||
|
}, req)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return router;
|
return router;
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { promises as fs } from "fs";
|
||||||
import db from '../../sql.mjs';
|
import db from '../../sql.mjs';
|
||||||
import lib from '../../lib.mjs';
|
import lib from '../../lib.mjs';
|
||||||
import search from '../../routeinc/search.mjs';
|
import search from '../../routeinc/search.mjs';
|
||||||
@ -16,8 +17,10 @@ export default router => {
|
|||||||
const rows = await db`
|
const rows = await db`
|
||||||
select *
|
select *
|
||||||
from "items"
|
from "items"
|
||||||
where mime ilike ${mime}
|
where
|
||||||
and username ilike ${user}
|
mime ilike ${mime} and
|
||||||
|
username ilike ${user} and
|
||||||
|
active = 'true'
|
||||||
order by random()
|
order by random()
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
@ -28,27 +31,47 @@ export default router => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
group.get(/\/p\/([0-9]+)/, async (req, res) => { // legacy
|
group.get(/\/items\/get/, async (req, res) => {
|
||||||
let eps = 100;
|
let eps = 150;
|
||||||
let id = +req.url.split[3];
|
|
||||||
|
|
||||||
const rows = await db`
|
const opt = {
|
||||||
select *
|
older: req.url.qs.older ?? null,
|
||||||
from "items"
|
newer: req.url.qs.newer ?? null,
|
||||||
where id < ${+id}
|
mode: +req.url.qs.mode ?? 0 // 0 sfw, 1 nsfw, 2 untagged, 3 all
|
||||||
order by id desc
|
|
||||||
limit ${+eps}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const items = {
|
|
||||||
items: rows,
|
|
||||||
last: rows[rows.length - 1].id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const newest = (await db`select max(id) as id from "items"`)[0].id;
|
||||||
|
const oldest = (await db`select min(id) as id from "items"`)[0].id;
|
||||||
|
const modequery = lib.getMode(opt.mode);
|
||||||
|
|
||||||
|
const rows = (await db`
|
||||||
|
select "items".id, "items".mime, coalesce("tags_assign".tag_id, 0) as tag_id
|
||||||
|
from "items"
|
||||||
|
left join "tags_assign" on "tags_assign".item_id = "items".id and ("tags_assign".tag_id = 1 or "tags_assign".tag_id = 2)
|
||||||
|
where
|
||||||
|
${db.unsafe(modequery)} and
|
||||||
|
active = 'true'
|
||||||
|
${
|
||||||
|
opt.older
|
||||||
|
? db`and id <= ${opt.older}`
|
||||||
|
: opt.newer
|
||||||
|
? db`and id >= ${opt.newer}`
|
||||||
|
: db``
|
||||||
|
}
|
||||||
|
order by id ${
|
||||||
|
opt.newer
|
||||||
|
? db`asc`
|
||||||
|
: db`desc`
|
||||||
|
}
|
||||||
|
limit ${eps}
|
||||||
|
`).sort((a, b) => b.id - a.id);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
atEnd: rows[0].id === newest,
|
||||||
|
atStart: rows[rows.length - 1].id === oldest,
|
||||||
success: true,
|
success: true,
|
||||||
items
|
items: rows
|
||||||
});
|
}, 200);
|
||||||
});
|
});
|
||||||
|
|
||||||
group.get(/\/item\/[0-9]+$/, async (req, res) => {
|
group.get(/\/item\/[0-9]+$/, async (req, res) => {
|
||||||
@ -57,20 +80,20 @@ export default router => {
|
|||||||
const item = await db`
|
const item = await db`
|
||||||
select *
|
select *
|
||||||
from "items"
|
from "items"
|
||||||
where id = ${+id}
|
where id = ${+id} and active = 'true'
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
const next = await db`
|
const next = await db`
|
||||||
select id
|
select id
|
||||||
from "items"
|
from "items"
|
||||||
where id > ${+id}
|
where id > ${+id} and active = 'true'
|
||||||
order by id
|
order by id
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
const prev = await db`
|
const prev = await db`
|
||||||
select id
|
select id
|
||||||
from "items"
|
from "items"
|
||||||
where id < ${+id}
|
where id < ${+id} and active = 'true'
|
||||||
order by id desc
|
order by id desc
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
@ -103,7 +126,7 @@ export default router => {
|
|||||||
const rows = db`
|
const rows = db`
|
||||||
select id, mime, size, src, stamp, userchannel, username, usernetwork
|
select id, mime, size, src, stamp, userchannel, username, usernetwork
|
||||||
from "items"
|
from "items"
|
||||||
where username = ${user}
|
where username = ${user} and active = 'true'
|
||||||
order by stamp desc
|
order by stamp desc
|
||||||
limit ${+eps}
|
limit ${+eps}
|
||||||
`;
|
`;
|
||||||
@ -203,13 +226,42 @@ export default router => {
|
|||||||
msg: 'no postid'
|
msg: 'no postid'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const postid = +req.post.postid;
|
const id = +req.post.postid;
|
||||||
|
|
||||||
await db`
|
if(id <= 1) {
|
||||||
delete from "items"
|
return res.json({
|
||||||
where id = ${+postid}
|
success: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const f0ck = await db`
|
||||||
|
select dest, mime
|
||||||
|
from "items"
|
||||||
|
where
|
||||||
|
id = ${id} and
|
||||||
|
active = 'true'
|
||||||
|
limit 1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
if(f0ck.length === 0) {
|
||||||
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
msg: `f0ck ${id}: f0ck not found`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await db`update "items" set active = 'false' where id = ${id}`;
|
||||||
|
|
||||||
|
await fs.copyFile(`./public/b/${f0ck[0].dest}`, `./deleted/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
|
await fs.copyFile(`./public/t/${id}.webp`, `./deleted/t/${id}.webp`).catch(_=>{});
|
||||||
|
await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
|
await fs.unlink(`./public/t/${id}.webp`).catch(_=>{});
|
||||||
|
|
||||||
|
if(f0ck[0].mime.startsWith('audio')) {
|
||||||
|
await fs.copyFile(`./public/ca/${id}.webp`, `./deleted/ca/${id}.webp`).catch(_=>{});
|
||||||
|
await fs.unlink(`./public/ca/${id}.webp`).catch(_=>{});
|
||||||
|
}
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
success: true
|
success: true
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,7 @@ export default router => {
|
|||||||
const itemid = (await db`
|
const itemid = (await db`
|
||||||
select id
|
select id
|
||||||
from "items"
|
from "items"
|
||||||
where id = ${+avatar}
|
where id = ${+avatar} and active = 'true'
|
||||||
`)?.[0]?.id;
|
`)?.[0]?.id;
|
||||||
|
|
||||||
if(!itemid) {
|
if(!itemid) {
|
||||||
|
@ -30,7 +30,7 @@ export default router => {
|
|||||||
const postid = +req.params.postid;
|
const postid = +req.params.postid;
|
||||||
const tagname = req.post.tagname?.trim();
|
const tagname = req.post.tagname?.trim();
|
||||||
|
|
||||||
if(tagname.length >= 45) {
|
if(tagname.length > 70) {
|
||||||
return res.json({
|
return res.json({
|
||||||
success: false,
|
success: false,
|
||||||
msg: 'tag is too long!'
|
msg: 'tag is too long!'
|
||||||
@ -131,6 +131,14 @@ 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') {
|
||||||
|
return res.json({
|
||||||
|
success: false,
|
||||||
|
msg: 'blacklisted',
|
||||||
|
tags: await lib.getTags(postid)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const tags = await lib.getTags(postid);
|
const tags = await lib.getTags(postid);
|
||||||
|
|
||||||
const tagid = tags.filter(t => t.tag === tagname)[0]?.id ?? null;
|
const tagid = tags.filter(t => t.tag === tagname)[0]?.id ?? null;
|
||||||
|
@ -10,6 +10,55 @@ const auth = async (req, res, next) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default (router, tpl) => {
|
export default (router, tpl) => {
|
||||||
|
router.get(/\/user\/(?<user>.*)/, async (req, res) => {
|
||||||
|
const user = decodeURIComponent(req.params.user);
|
||||||
|
|
||||||
|
const query = await db`
|
||||||
|
select "user".user, user_options.*
|
||||||
|
from user_options
|
||||||
|
left join "user" on "user".id = user_options.user_id
|
||||||
|
where "user".user ilike ${user}
|
||||||
|
limit 1
|
||||||
|
`;
|
||||||
|
|
||||||
|
if(!query.length) {
|
||||||
|
return res.reply({
|
||||||
|
code: 404,
|
||||||
|
body: tpl.render('error', {
|
||||||
|
message: 'this user does not exists',
|
||||||
|
tmp: null
|
||||||
|
}, req)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const f0cks = await f0cklib.getf0cks({
|
||||||
|
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
|
||||||
|
});
|
||||||
|
|
||||||
|
if('items' in f0cks)
|
||||||
|
f0cks.items = f0cks.items.slice(0, 50);
|
||||||
|
if('items' in favs)
|
||||||
|
favs.items = favs.items.slice(0, 50);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
user: query[0],
|
||||||
|
f0cks,
|
||||||
|
favs,
|
||||||
|
tmp: null
|
||||||
|
};
|
||||||
|
|
||||||
|
return res.reply({ body: tpl.render('user', data, req) });
|
||||||
|
});
|
||||||
|
|
||||||
router.get(/^\/?(?:\/tag\/(?<tag>.+?))?(?:\/user\/(?<user>.+?)\/(?<mode>f0cks|favs))?(?:\/(?<mime>image|audio|video))?(?:\/p\/(?<page>\d+))?(?:\/(?<itemid>\d+))?$/, async (req, res) => {
|
router.get(/^\/?(?:\/tag\/(?<tag>.+?))?(?:\/user\/(?<user>.+?)\/(?<mode>f0cks|favs))?(?:\/(?<mime>image|audio|video))?(?:\/p\/(?<page>\d+))?(?:\/(?<itemid>\d+))?$/, async (req, res) => {
|
||||||
const mode = req.params.itemid ? 'item' : 'index';
|
const mode = req.params.itemid ? 'item' : 'index';
|
||||||
const data = await (req.params.itemid ? f0cklib.getf0ck : f0cklib.getf0cks)({
|
const data = await (req.params.itemid ? f0cklib.getf0ck : f0cklib.getf0cks)({
|
||||||
@ -19,7 +68,8 @@ export default (router, tpl) => {
|
|||||||
page: req.params.page,
|
page: req.params.page,
|
||||||
itemid: req.params.itemid,
|
itemid: req.params.itemid,
|
||||||
fav: req.params.mode == 'favs',
|
fav: req.params.mode == 'favs',
|
||||||
mode: req.session.mode
|
mode: req.session.mode,
|
||||||
|
session: !!req.session
|
||||||
});
|
});
|
||||||
if(!data.success) {
|
if(!data.success) {
|
||||||
return res.reply({
|
return res.reply({
|
||||||
@ -73,7 +123,7 @@ export default (router, tpl) => {
|
|||||||
const list = await db`
|
const list = await db`
|
||||||
select
|
select
|
||||||
"user".user,
|
"user".user,
|
||||||
coalesce("user_options".avatar, 47319) 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
|
||||||
|
@ -19,7 +19,8 @@ export default (router, tpl) => {
|
|||||||
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
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!data.success) {
|
if(!data.success) {
|
||||||
|
@ -17,7 +17,7 @@ export default (router, tpl) => {
|
|||||||
total = (await db`
|
total = (await db`
|
||||||
select count(*) as total
|
select count(*) as total
|
||||||
from "items"
|
from "items"
|
||||||
where src ilike ${'%' + tag.substring(4) + '%'}
|
where src ilike ${'%' + tag.substring(4) + '%'} and active = 'true'
|
||||||
group by "items".id
|
group by "items".id
|
||||||
`).length;
|
`).length;
|
||||||
}
|
}
|
||||||
@ -40,7 +40,9 @@ export default (router, tpl) => {
|
|||||||
ret = await db`
|
ret = await db`
|
||||||
select *
|
select *
|
||||||
from "items"
|
from "items"
|
||||||
where src ilike ${'%' + tag.substring(4) + '%'}
|
where
|
||||||
|
src ilike ${'%' + tag.substring(4) + '%'} and
|
||||||
|
active = 'true'
|
||||||
group by "items".id
|
group by "items".id
|
||||||
order by "items".id desc
|
order by "items".id desc
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
@ -53,7 +55,7 @@ export default (router, tpl) => {
|
|||||||
from "tags"
|
from "tags"
|
||||||
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
left join "tags_assign" on "tags_assign".tag_id = "tags".id
|
||||||
left join "items" on "items".id = "tags_assign".item_id
|
left join "items" on "items".id = "tags_assign".item_id
|
||||||
where "tags".tag ilike ${'%' + tag + '%'}
|
where "tags".tag ilike ${'%' + tag + '%'} and "items".active = 'true'
|
||||||
group by "items".id, "tags".tag
|
group by "items".id, "tags".tag
|
||||||
offset ${offset}
|
offset ${offset}
|
||||||
limit ${_eps}
|
limit ${_eps}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
//import knex from "knex";
|
|
||||||
import postgres from "postgres";
|
import postgres from "postgres";
|
||||||
import cfg from "./config.mjs";
|
import cfg from "./config.mjs";
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { promises as fs } from "fs";
|
import { promises as fs } from "fs";
|
||||||
import db from "../sql.mjs";
|
import db from "../sql.mjs";
|
||||||
|
import { getLevel } from "../../inc/admin.mjs";
|
||||||
|
|
||||||
export default async bot => {
|
export default async bot => {
|
||||||
|
|
||||||
@ -7,37 +8,104 @@ export default async bot => {
|
|||||||
name: "delete",
|
name: "delete",
|
||||||
call: /^\!(del|rm) .*/i,
|
call: /^\!(del|rm) .*/i,
|
||||||
active: true,
|
active: true,
|
||||||
level: 100,
|
|
||||||
f: async e => {
|
f: async e => {
|
||||||
const ret = (await Promise.all(e.args.map(async id => {
|
let deleted = [];
|
||||||
|
|
||||||
|
for(let id of e.args) {
|
||||||
id = +id;
|
id = +id;
|
||||||
if(id <= 0)
|
if(id <= 1)
|
||||||
return false;
|
continue;
|
||||||
|
|
||||||
const f0ck = await db`
|
const f0ck = await db`
|
||||||
select dest
|
select dest, mime, username, userchannel, usernetwork
|
||||||
from "items"
|
from "items"
|
||||||
where id = ${+id}
|
where
|
||||||
|
id = ${id} and
|
||||||
|
active = 'true'
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
if(f0ck.length === 0)
|
const level = getLevel(e.user).level;
|
||||||
return false;
|
|
||||||
|
|
||||||
|
if(f0ck.length === 0) {
|
||||||
|
e.reply(`f0ck ${id}: f0ck not found`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(
|
||||||
|
(f0ck[0].username !== (e.user.nick || e.user.username) ||
|
||||||
|
f0ck[0].userchannel !== e.channel ||
|
||||||
|
f0ck[0].usernetwork !== e.network) &&
|
||||||
|
level < 100
|
||||||
|
) {
|
||||||
|
e.reply(`f0ck ${id}: insufficient permissions`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(~~(new Date() / 1e3) >= (f0ck[0].stamp + 600) && level < 100) {
|
||||||
|
e.reply(`f0ck ${id}: too late lol`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db`update "items" set active = 'false' where id = ${id}`;
|
||||||
|
|
||||||
|
await fs.copyFile(`./public/b/${f0ck[0].dest}`, `./deleted/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
|
await fs.copyFile(`./public/t/${id}.webp`, `./deleted/t/${id}.webp`).catch(_=>{});
|
||||||
await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(_=>{});
|
await fs.unlink(`./public/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
await fs.unlink(`./public/t/${id}`).catch(_=>{});
|
await fs.unlink(`./public/t/${id}.webp`).catch(_=>{});
|
||||||
|
|
||||||
await db`
|
if(f0ck[0].mime.startsWith('audio')) {
|
||||||
delete from "items"
|
await fs.copyFile(`./public/ca/${id}.webp`, `./deleted/ca/${id}.webp`).catch(_=>{});
|
||||||
where id = ${+id}
|
await fs.unlink(`./public/ca/${id}.webp`).catch(_=>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleted.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.reply(`deleted ${deleted.length}/${e.args.length} f0cks (${deleted.join(",")})`);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
name: "recover",
|
||||||
|
call: /^\!(recover) .*/i,
|
||||||
|
active: true,
|
||||||
|
level: 100,
|
||||||
|
f: async e => {
|
||||||
|
let recovered = [];
|
||||||
|
|
||||||
|
for(let id of e.args) {
|
||||||
|
id = +id;
|
||||||
|
if(id <= 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const f0ck = await db`
|
||||||
|
select dest, mime
|
||||||
|
from "items"
|
||||||
|
where
|
||||||
|
id = ${id} and
|
||||||
|
active = 'false'
|
||||||
|
limit 1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
return id;
|
if(f0ck.length === 0) {
|
||||||
}))).filter(d => d);
|
e.reply(`f0ck ${id}: f0ck not found`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(ret.length > 0)
|
await fs.copyFile(`./deleted/b/${f0ck[0].dest}`, `./public/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
e.reply(`deleted ${ret.length}/${e.args.length} (${ret.join(",")}) f0cks`);
|
await fs.copyFile(`./deleted/t/${id}.webp`, `./public/t/${id}.webp`).catch(_=>{});
|
||||||
else
|
await fs.unlink(`./deleted/b/${f0ck[0].dest}`).catch(_=>{});
|
||||||
e.reply(`oof`);
|
await fs.unlink(`./deleted/t/${id}.webp`).catch(_=>{});
|
||||||
|
|
||||||
|
if(f0ck[0].mime.startsWith('audio')) {
|
||||||
|
await fs.copyFile(`./deleted/ca/${id}.webp`, `./public/ca/${id}.webp`).catch(_=>{});
|
||||||
|
await fs.unlink(`./deleted/ca/${id}.webp`).catch(_=>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
await db`update "items" set active = 'true' where id = ${id}`;
|
||||||
|
|
||||||
|
recovered.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.reply(`recovered ${recovered.length}/${e.args.length} f0cks (${recovered.join(",")})`);
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
@ -29,8 +29,8 @@ export default async bot => {
|
|||||||
f: e => {
|
f: e => {
|
||||||
const links = e.message.match(regex)?.filter(link => !link.includes("f0ck.me")) || [];
|
const links = e.message.match(regex)?.filter(link => !link.includes("f0ck.me")) || [];
|
||||||
|
|
||||||
if(e.photo)
|
if(e.media)
|
||||||
links.push(e.photo);
|
links.push(e.media);
|
||||||
|
|
||||||
if(links.length === 0)
|
if(links.length === 0)
|
||||||
return false;
|
return false;
|
||||||
@ -128,7 +128,7 @@ export default async bot => {
|
|||||||
await db`
|
await db`
|
||||||
insert into items ${
|
insert into items ${
|
||||||
db({
|
db({
|
||||||
src: e.photo ? "" : link,
|
src: e.media ? "" : link,
|
||||||
dest: filename,
|
dest: filename,
|
||||||
mime: mime,
|
mime: mime,
|
||||||
size: size,
|
size: size,
|
||||||
@ -137,7 +137,7 @@ export default async bot => {
|
|||||||
userchannel: e.channel,
|
userchannel: e.channel,
|
||||||
usernetwork: e.network,
|
usernetwork: e.network,
|
||||||
stamp: ~~(new Date() / 1000),
|
stamp: ~~(new Date() / 1000),
|
||||||
active: 1
|
active: true
|
||||||
}, 'src', 'dest', 'mime', 'size', 'checksum', 'username', 'userchannel', 'usernetwork', 'stamp', 'active')
|
}, 'src', 'dest', 'mime', 'size', 'checksum', 'username', 'userchannel', 'usernetwork', 'stamp', 'active')
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -191,29 +191,31 @@ export default async bot => {
|
|||||||
speed = !Number.isFinite(speed) ? "yes" : `${speed.toFixed(2)} Mbit/s`;
|
speed = !Number.isFinite(speed) ? "yes" : `${speed.toFixed(2)} Mbit/s`;
|
||||||
|
|
||||||
// autotagger
|
// autotagger
|
||||||
let tags = [];
|
/*let tags = [];
|
||||||
|
let score = 0;
|
||||||
try {
|
try {
|
||||||
if(mime.startsWith('image')) {
|
if(mime.startsWith('image')) {
|
||||||
const res = await lib.detectNSFW(filename);
|
const res = await lib.detectNSFW(filename);
|
||||||
|
score = res.score;
|
||||||
|
|
||||||
await db`
|
await db`
|
||||||
insert into "tags_assign" ${
|
insert into "tags_assign" ${
|
||||||
db({
|
db({
|
||||||
item_id: itemid,
|
item_id: itemid,
|
||||||
tag_id: res.nsfw ? 2 : 1,
|
tag_id: res.isNSFW ? 2 : 1,
|
||||||
user_id: 7
|
user_id: 1
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
tags.push(res.nsfw ? 'nsfw' : 'sfw');
|
tags.push(res.isNSFW ? 'nsfw' : 'sfw');
|
||||||
|
|
||||||
if(res.hentai >= .7) {
|
if(res.hentai >= .7) {
|
||||||
await db`
|
await db`
|
||||||
insert into "tags_assign" ${
|
insert into "tags_assign" ${
|
||||||
db({
|
db({
|
||||||
item_id: f.id,
|
item_id: f.id,
|
||||||
tag_id: 8, // hentai
|
tag_id: 4, // hentai
|
||||||
user_id: 7 // autotagger
|
user_id: 1 // autotagger
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -226,11 +228,11 @@ export default async bot => {
|
|||||||
db([{
|
db([{
|
||||||
item_id: itemid,
|
item_id: itemid,
|
||||||
tag_id: 1,
|
tag_id: 1,
|
||||||
user_id: 7
|
user_id: 1
|
||||||
}, {
|
}, {
|
||||||
item_id: itemid,
|
item_id: itemid,
|
||||||
tag_id: 7178,
|
tag_id: 3, // audio
|
||||||
user_id: 7
|
user_id: 1
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@ -238,10 +240,13 @@ export default async bot => {
|
|||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
/*e.reply([
|
||||||
|
`[f0cked] link: ${cfg.main.url.full}/${itemid} | size: ${lib.formatSize(size)} | speed: ${speed}` + (tags.length > 0 ? ` | tags: ${tags.join(', ')} (score: ${score.toFixed(2)})` : '')
|
||||||
|
]);*/
|
||||||
e.reply([
|
e.reply([
|
||||||
`[f0cked] link: ${cfg.main.url.full}/${itemid} | size: ${lib.formatSize(size)} | speed: ${speed}` + (tags.length > 0 ? ` | tags: ${tags.join(', ')}` : '')
|
`[f0cked] link: ${cfg.main.url.full}/${itemid} | size: ${lib.formatSize(size)} | speed: ${speed}`
|
||||||
]);
|
]);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -61,7 +61,7 @@ import flummpress from "flummpress";
|
|||||||
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 || 'f0ck';
|
||||||
|
|
||||||
if(req.cookies.session) {
|
if(req.cookies.session) {
|
||||||
const user = await db`
|
const user = await db`
|
||||||
@ -95,6 +95,8 @@ import flummpress from "flummpress";
|
|||||||
where id = ${+user[0].sess_id}
|
where id = ${+user[0].sess_id}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
req.session.theme = req.cookies.theme;
|
||||||
|
|
||||||
// update userprofile
|
// update userprofile
|
||||||
await db`
|
await db`
|
||||||
insert into "user_options" ${
|
insert into "user_options" ${
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
<div class="about">
|
<div class="about">
|
||||||
<div>
|
<div>
|
||||||
<a href="/48908"><img src="/s/img/loool.webp" /></a>
|
<a href="//f0ck.me/48908"><img src="//f0ck.me/s/img/loool.webp" /></a>
|
||||||
<p>thanks to our turkish fellow lol@n0xy/#f0ck for this gif <3</p>
|
<p>thanks to our turkish fellow lol@n0xy/#f0ck for this gif <3</p>
|
||||||
</div>
|
</div>
|
||||||
<h5>f0ck Contact</h5>
|
<h5>f0ck Contact</h5>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<li>admin@f0ck.me</li>
|
<li>admin@f0ck.me</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h5>Compatibility</h5>
|
<h5>Compatibility</h5>
|
||||||
<!--<p>f0ck is developed and tested for Firefox and Chromium in their latest versions</p>-->
|
<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>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>
|
<p>Microsoft Edgy is not actively supported, but if it werks, great! Same for anything apple related.</p>
|
||||||
<h5>Tinfoil f0ckers listen!</h5>
|
<h5>Tinfoil f0ckers listen!</h5>
|
||||||
@ -44,6 +44,6 @@
|
|||||||
<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>
|
<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>
|
<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>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: No for Tor - Yes for cloudflare and cloudflare probably sells your soul to the devil, however our webserver doesn't log cloudflare connecting to our webserver, if you want to lurk without being flared by the cloud, see the above tor section my man</p>
|
<p>Logs: We do not log users accessing our website.</p>
|
||||||
</div>
|
</div>
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
@ -1,3 +1,10 @@
|
|||||||
@include(snippets/header_admin)
|
@include(snippets/header_admin)
|
||||||
|
<div class="container">
|
||||||
|
<h1>Henlo, {{ session.user }}</h1>
|
||||||
|
<p>Hier entsteht eine Internetpräsenz!</p>
|
||||||
|
<img src="/s/img/favicon.gif" alt="f0ck bash">
|
||||||
|
<p>@if(typeof totals !== "undefined")
|
||||||
|
total: {{ totals.total }} | tagged: {{ totals.tagged }} | untagged: {{ totals.untagged }} | sfw: {{ totals.sfw }} | nsfw: {{ totals.nsfw }}
|
||||||
|
@endif</p>
|
||||||
|
</div>
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
24
views/admin/recover.html
Normal file
24
views/admin/recover.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
@include(snippets/header_admin)
|
||||||
|
<table class="table" style="width: 100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td>ID</td>
|
||||||
|
<td>f0cker</td>
|
||||||
|
<td>mime</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@each(posts as post)
|
||||||
|
<tr>
|
||||||
|
<td><img src="data:image/webp;base64,{{ post.thumbnail }}" /></td>
|
||||||
|
<td>{{ post.id }}</td>
|
||||||
|
<td>{{ post.username }}</td>
|
||||||
|
<td>{{ post.mime }}</td>
|
||||||
|
<td><a href="/admin/recover/?id={{ post.id }}">recover</a></td>
|
||||||
|
</tr>
|
||||||
|
@endeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
@include(snippets/footer)
|
@ -1,5 +1,6 @@
|
|||||||
@include(snippets/header_admin)
|
@include(snippets/header_admin)
|
||||||
<table style="width: 100%;">
|
<table class="table" style="width: 100%">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>ID</td>
|
<td>ID</td>
|
||||||
@ -10,6 +11,8 @@
|
|||||||
<td>last_used</td>
|
<td>last_used</td>
|
||||||
<td>last_action</td>
|
<td>last_action</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
@each(sessions as session)
|
@each(sessions as session)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ session.kmsi ? '⚓' : '' }}</td>
|
<td>{{ session.kmsi ? '⚓' : '' }}</td>
|
||||||
@ -22,5 +25,6 @@
|
|||||||
<td>{{ session.last_action }}</td>
|
<td>{{ session.last_action }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endeach
|
@endeach
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
165
views/comments.html
Normal file
165
views/comments.html
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<div class="sidebar">
|
||||||
|
<div class="header_sidebar">
|
||||||
|
<span>Comments</span>
|
||||||
|
</div>
|
||||||
|
<div class="commentbox">
|
||||||
|
<textarea name="comments" id="comments1" cols="30" rows="5" placeholder="Write a shitpost?"></textarea>
|
||||||
|
<button class="commentbutton">Shit</button>
|
||||||
|
</div>
|
||||||
|
<div class="commentholder">
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="comment">
|
||||||
|
<div class="comment_userimg">
|
||||||
|
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar_comments" />
|
||||||
|
</div>
|
||||||
|
<div class="comment_username">
|
||||||
|
{{ session.user }}
|
||||||
|
</div>
|
||||||
|
<div class="comment_content">
|
||||||
|
<p>Lorem Ipsum Lorem Ipsum <br><img src="https://f0ck.me/b/63144b2b.webp" alt=""></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,8 +1,18 @@
|
|||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="_error_wrapper">
|
||||||
<div class="err">
|
<div class="err">
|
||||||
<span>{{ message }}</span>
|
<div class="_error_topbar">
|
||||||
<img src="https://f0ck.me/s/img/favicon.gif" alt="f0ck?!">
|
<span>x.x</span>
|
||||||
|
</div>
|
||||||
|
<div class="_error_content">
|
||||||
|
<img src="/s/img/favicon.gif" alt="f0ck?!">
|
||||||
|
<div class="_error_message">
|
||||||
|
<span>Error</span>
|
||||||
|
<code>{{ message }}</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<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: {!! tmp.user.toLowerCase() !!}@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 id="posts">
|
<div class="posts">
|
||||||
@each(items as item)
|
@each(items as item)
|
||||||
<a href="{{ 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="{{ 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>
|
||||||
@endeach
|
@endeach
|
||||||
|
@ -1,5 +1,20 @@
|
|||||||
|
<div class="wrapper">
|
||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="_204863">
|
||||||
|
<div class="imageDoor" style="--hover-image: url('/t/{{ item.id }}.webp');">
|
||||||
|
<img src="/t/{{ item.id }}.webp" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="gapLeft">
|
||||||
|
<span class="populateME"><b>f0ck</b> - {{ item.id }}</span>
|
||||||
|
</div>
|
||||||
|
@if(session)
|
||||||
|
<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_delete"><use href="/s/img/iconset.svg#cross"></use></svg>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="next-post">
|
<div class="next-post">
|
||||||
@if(pagination.prev)
|
@if(pagination.prev)
|
||||||
@ -45,11 +60,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="metadata">
|
<div class="metadata">
|
||||||
<span class="badge badge-dark">
|
<span class="badge badge-dark">
|
||||||
<a href="/{{ item.id }}" style="--hover-image: url('/t/{{ item.id }}.webp');" 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>)
|
||||||
<svg class="iconset" id="a_delete"><use href="/s/img/iconset.svg#cross"></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>
|
|
||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
<span class="badge badge-dark">{{ user.network }} / {{ user.channel }}</span>
|
<span class="badge badge-dark">{{ user.network }} / {{ user.channel }}</span>
|
||||||
@ -84,5 +97,10 @@
|
|||||||
@endif
|
@endif
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="random">
|
||||||
|
<a href="/random"></a>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@include(comments)
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
||||||
|
</div>
|
@ -1,11 +1,12 @@
|
|||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
|
<div class="f0ckgle">
|
||||||
<h1 style="text-align: center">f0ckgle</h1>
|
<h1 style="text-align: center">f0ckgle</h1>
|
||||||
<form action="/search" class="admin-search">
|
<form action="/search" class="admin-search">
|
||||||
<input type="text" name="tag" value="{!! searchstring || '' !!}" /><button type="submit"><b>f0ck</b></button>
|
<input type="text" name="tag" value="{!! searchstring || '' !!}" /><button type="submit"><b>f0ck</b></button>
|
||||||
</form>
|
</form>
|
||||||
<div class="results">
|
<div class="results">
|
||||||
@if(result)
|
@if(result)
|
||||||
<h1>{{ count }} f0cks given (page {{ pagination.page }} of {{ pagination.end }}):</h1>
|
<h2>{{ count }} f0cks given (page {{ pagination.page }} of {{ pagination.end }}):</h2>
|
||||||
<table style="width: 100%" class="table">
|
<table style="width: 100%" class="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -21,15 +22,16 @@
|
|||||||
@each(result as line)
|
@each(result as line)
|
||||||
<tr>
|
<tr>
|
||||||
<td style="width: 128px;"><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank"><img src="/t/{{ line.id }}.webp" /></a></td>
|
<td style="width: 128px;"><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank"><img src="/t/{{ line.id }}.webp" /></a></td>
|
||||||
<td><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank">{{ line.id }}</a></td>
|
<td><span class="mview_desc">ID:</span><a href="/tag/{!! line.tag !!}/{{ line.id }}" target="_blank">{{ line.id }}</a></td>
|
||||||
<td><a href="/tag/{!! line.tag !!}">{!! line.tag !!}</a></td>
|
<td><span class="mview_desc">Tag:</span><a href="/tag/{!! line.tag !!}">{!! line.tag !!}</a></td>
|
||||||
<td>{{ line.mime }}</td>
|
<td><span class="mview_desc">Mime:</span>{{ line.mime }}</td>
|
||||||
<td><a href="/user/{!! line.username !!}/f0cks/{{ line.id }}">{!! line.username !!}</a></td>
|
<td><span class="mview_desc">User:</span><a href="/user/{!! line.username !!}/f0cks/{{ line.id }}">{!! line.username !!}</a></td>
|
||||||
<td>{{ line.score?.toFixed(2) }}</td>
|
<td><span class="mview_desc">Score:</span>{{ line.score?.toFixed(2) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@endeach
|
@endeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
@include(snippets/footer)
|
@include(snippets/footer)
|
@ -1,6 +1,6 @@
|
|||||||
@include(snippets/header)
|
@include(snippets/header)
|
||||||
<h1>Settings</h1>
|
<h1>Settings</h1>
|
||||||
@if(session.avatar)<a href="//f0ck.me/{{ session.avatar }}"><img id="img_avatar" src="/t/{{ session.avatar }}.webp" /></a>@endif
|
@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>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@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
|
@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
|
||||||
|
</div>
|
||||||
<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>
|
||||||
|
@ -12,3 +12,4 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@include(snippets/navbar)
|
@include(snippets/navbar)
|
||||||
|
<div id="main">
|
@ -16,3 +16,4 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@include(snippets/navbar_admin)
|
@include(snippets/navbar_admin)
|
||||||
|
<div id="main">
|
@ -1,11 +1,11 @@
|
|||||||
|
@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="/"><span class="f0ck" width="" height="">F0CK</span></a>
|
||||||
<div class="navigation-links">
|
<div class="navigation-links">
|
||||||
<ul class="navbar-nav">
|
<ul class="navbar-nav">
|
||||||
<li class="nav-item dropdown">
|
<li class="nav-item dropdown">
|
||||||
@if(session)
|
<a class="nav-link user" href="#" content="{{ session.user }}" data-toggle="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>
|
||||||
<img src="@if(session.avatar)/t/{{ session.avatar }}.webp@else/s/img/ava/default.png@endif" class="avatar" /> {{ session.user }}
|
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="/admin">adminpanel</a></li>
|
<li><a href="/admin">adminpanel</a></li>
|
||||||
@ -17,22 +17,15 @@
|
|||||||
<li><a href="/ranking">Ranking</a></li>
|
<li><a href="/ranking">Ranking</a></li>
|
||||||
<li><a href="/logout">logout</a></li>
|
<li><a href="/logout">logout</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@else
|
|
||||||
<a class="nav-link" href="/about" data-toggle="dropdown">About</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><a href="/login">login</a></li>
|
|
||||||
</ul>
|
|
||||||
@endif
|
|
||||||
</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">Theme</a>
|
<a class="nav-link ddcontent" href="#" content="{{ theme }}" data-toggle="dropdown">Themes</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
@each(themes as t)
|
@each(themes as t)
|
||||||
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
|
<li><a href="/theme/{{ t }}">{{ t }}</a></li>
|
||||||
@endeach
|
@endeach
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<span class="placeholder"> </span>
|
|
||||||
<li class="nav-item dropdown">
|
<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) ▼@endif</a>
|
<a class="nav-link ddcontent" href="#"@if(tmp?.mime) content="{{ tmp?.mime }}" data-toggle="dropdown"@endif>Filter@if(!tmp?.mime) ▼@endif</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
@ -42,7 +35,6 @@
|
|||||||
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
|
<li><a class="dropdown-item" href="/@if(tmp?.user)user/{{ tmp?.user }}/@endifimage">Image</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@if(session)
|
|
||||||
<li class="nav-item @if(session)dropdown@endif">
|
<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>
|
<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">
|
<ul class="dropdown-menu">
|
||||||
@ -51,7 +43,6 @@
|
|||||||
@endfor
|
@endfor
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a id="random" class="nav-link" href="/random">
|
<a id="random" class="nav-link" href="/random">
|
||||||
<span class="nav-link-identifier">Random</span>
|
<span class="nav-link-identifier">Random</span>
|
||||||
@ -81,3 +72,62 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</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) ▼@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">«</a>
|
||||||
|
<a href="{{ link.main }}{{ link.path }}{{ pagination.prev }}" class="page-item-2 btn prev@if(!pagination.prev) disabled@endif">‹</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">›</a>
|
||||||
|
<a href="{{ link.main }}{{ link.path }}{{ pagination.end }}" class="page-item-4 btn start@if(!pagination.next) disabled@endif">»</a>
|
||||||
|
</nav>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
@endif
|
@ -20,18 +20,14 @@
|
|||||||
<span class="nav-link-identifier">Log</span>
|
<span class="nav-link-identifier">Log</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@if(typeof totals !== "undefined")
|
<li class="nav-item">
|
||||||
<li class="nav-item" style="width: 100%; text-align: center">
|
<a class="nav-link" href="/admin/recover">
|
||||||
total: {{ totals.total }} | tagged: {{ totals.tagged }} | untagged: {{ totals.untagged }} | sfw: {{ totals.sfw }} | nsfw: {{ totals.nsfw }}
|
<span class="nav-link-identifier">Recover</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/logout">Logout</a>
|
||||||
</li>
|
</li>
|
||||||
@endif
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="collapse navbar-collapse show" id="navbarSupportedContent">
|
|
||||||
<div class="pagination-container-fluid">
|
|
||||||
<div class="pagination-wrapper">
|
|
||||||
Henlo, {{ session.user }} <a href="/logout">Logout</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
28
views/user.html
Normal file
28
views/user.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@include(snippets/header)
|
||||||
|
<h1>{{ user.user }}</h1>
|
||||||
|
|
||||||
|
<h2>f0cks:</h2>
|
||||||
|
@if('items' in f0cks)
|
||||||
|
<div class="posts">
|
||||||
|
@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>
|
||||||
|
@endeach
|
||||||
|
</div>
|
||||||
|
<a href="{{ f0cks.link.main }}">show all f0cks</a>
|
||||||
|
@else
|
||||||
|
no f0cks given
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<h2>favs:</h2>
|
||||||
|
@if('items' in favs)
|
||||||
|
<div class="posts">
|
||||||
|
@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>
|
||||||
|
@endeach
|
||||||
|
</div>
|
||||||
|
<a href="{{ favs.link.main }}">show all favs</a>
|
||||||
|
@else
|
||||||
|
no favorites
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@include(snippets/footer)
|
Reference in New Issue
Block a user