feat: Added better nsfw filtering

This commit is contained in:
florian 2023-07-21 16:27:48 +02:00
parent d6ee3d4270
commit b26ff70f52
3 changed files with 83 additions and 19 deletions

View File

@ -11,11 +11,12 @@ import {
buildFilter, buildFilter,
extractImageUrls, extractImageUrls,
hasContentWarning, hasContentWarning,
hasNsfwTag,
isReply, isReply,
prepareContent, prepareContent,
urlFix, urlFix,
} from "./nostrImageDownload"; } from "./nostrImageDownload";
import { appName } from "./env"; import { appName, nsfwPubKeys } from "./env";
/* /*
FEATURES: FEATURES:
@ -39,6 +40,7 @@ FEATURES:
- Prevent duplicates (shuffle?), prevent same author twice in a row - Prevent duplicates (shuffle?), prevent same author twice in a row
- show content warning? - show content warning?
- Support Deleted Events - Support Deleted Events
- Prevent duplicate images (shuffle? histroy?)
*/ */
let oldest = Infinity; let oldest = Infinity;
@ -55,6 +57,8 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
const [posts, setPosts] = useState<any[]>([]); const [posts, setPosts] = useState<any[]>([]);
const images = useRef<NostrImage[]>([]); const images = useRef<NostrImage[]>([]);
const [activeImages, setActiveImages] = useState<NostrImage[]>([]); const [activeImages, setActiveImages] = useState<NostrImage[]>([]);
const [history, setHistory] = useState<NostrImage[]>([]);
const upcommingImage = useRef<NostrImage>(); const upcommingImage = useRef<NostrImage>();
const [title, setTitle] = useState(appName); const [title, setTitle] = useState(appName);
const [paused, setPaused] = useState(false); const [paused, setPaused] = useState(false);
@ -88,6 +92,8 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
if ( if (
!isReply(event) && !isReply(event) &&
(npub !== undefined || !hasContentWarning(event)) && // only allow content warnings on profile content (npub !== undefined || !hasContentWarning(event)) && // only allow content warnings on profile content
(npub !== undefined || !hasNsfwTag(event)) && // only allow nsfw on profile content
(npub !== undefined || !nsfwPubKeys.includes(event.pubkey.toLowerCase()) ) && // block nsfw authors
oldPosts.findIndex((p) => p.id === event.id) === -1 oldPosts.findIndex((p) => p.id === event.id) === -1
) { ) {
return [...oldPosts, event]; return [...oldPosts, event];
@ -113,28 +119,34 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
}; };
useEffect(() => { useEffect(() => {
loadNdk([ loadNdk([
"wss://relay.nostr.band", "wss://relay.nostr.band",
"wss://nos.lol", "wss://nos.lol",
"wss://relay.mostr.pub", "wss://relay.mostr.pub",
"wss://purplepag.es/", // needed for user profiles
//"wss://feeds.nostr.band/pics"
]); ]);
fetch(); fetch();
}, []); }, []);
const animateImages = () => { const animateImages = () => {
setActiveImages((oldImages) => { setActiveImages((oldImages) => {
const newImages = [...oldImages]; const newActiveImages = [...oldImages];
if (newImages.length > 2) { if (newActiveImages.length > 2) {
// always keep 2 images // always keep 2 images
newImages.shift(); newActiveImages.shift();
} }
if (images.current.length > 0) { if (images.current.length > 0) {
const randomImage = const randomImage =
images.current[Math.floor(Math.random() * images.current.length)]; images.current[Math.floor(Math.random() * images.current.length)];
newImages.push(randomImage); images.current = images.current.filter((i) => i !== randomImage);
setHistory((oldHistory) => [...oldHistory, randomImage]);
newActiveImages.push(randomImage);
upcommingImage.current = randomImage; upcommingImage.current = randomImage;
} }
return newImages; return newActiveImages;
}); });
}; };
@ -150,8 +162,9 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
) )
.map((url) => ({ .map((url) => ({
url, url,
author: p.author, author: p.author.npub,
content: prepareContent(p.content), content: prepareContent(p.content),
tags: p.tags.filter((t: string[]) => t[0] === "t").map((t: string[]) => t[1].toLowerCase()),
})); }));
}); });
console.log(images.current.length); console.log(images.current.length);
@ -174,6 +187,10 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
} }
}; };
useEffect(() => {
console.log(history);
}, [history]);
const queueNextImage = (waitTime = 8000) => { const queueNextImage = (waitTime = 8000) => {
clearTimeout(timeoutHandle.current); clearTimeout(timeoutHandle.current);
timeoutHandle.current = setTimeout(() => { timeoutHandle.current = setTimeout(() => {
@ -197,7 +214,7 @@ const SlideShow = ({ tags, npub }: SlideShowProps) => {
useDebouncedEffect( useDebouncedEffect(
() => { () => {
setActiveNpub(upcommingImage?.current?.author?.npub); setActiveNpub(upcommingImage?.current?.author);
setActiveContent(upcommingImage?.current?.content); setActiveContent(upcommingImage?.current?.content);
}, },
[upcommingImage?.current], [upcommingImage?.current],

View File

@ -1,3 +1,5 @@
import { nip19 } from "nostr-tools";
export const appName = "slidestr.net"; export const appName = "slidestr.net";
export const defaultHashTags = [ export const defaultHashTags = [
@ -8,4 +10,40 @@ export const defaultHashTags = [
"catstr", "catstr",
"dogstr", "dogstr",
"nature", "nature",
]; "naturephotography",
"streetphotography",
];
export const nfswTags = [
"nsfw",
"boobstr",
"titstr",
"nasstr",
"nudeart",
"pornstr",
"nude",
];
export const nsfwPubKeys = [
"npub1xfu7047thly6aghl79z97kckkvwfvtcx88n6wq7c2tlng484d8xqv0kuvv", // Erandis Vol
"npub1rv08kght99a7xwckm0qpmzw09m5gwppequgqd8lwu74eakgaavwsp5cjtw", // CuratedNSFW
"npub1femd0mrawr0jmtjr2jwa2nm90haxrpglzdt6tt0djrsav39e53asf74aer", // FemDom Raw
"npub19xwjw7f23nsmnsd0j72mvhrdswt4cp6urc5el2zuu8se3yfu87ess524je", // Gone Wild (NSFW)
"npub1ylrnf0xfp9wsmqthxlqjqyqj9yy27pnchjwjq93v3mq66ts7ftjs6x7dcq", // Welcome To The Jungle
"npub1ga79p6qsjh0xd343q3du2unf2gl6gk0rde36c06mafxkrssmnnesxyzcss", // Orange Incest 🔞
"npub1jjtzhxzu8dlf7yn480sz67tesnfl7gpzfpkgpez05d2z9y3lya5sxvky0y", // Selfie Girls
"npub1ve4ztpqvlgu3v6hgrvc4lrdl2ernue7lq2h8tcgaksrkxlm7gnsqkjmz4e", // bluntkaraoke
"npub1kul999wnt8gwa6l2vyuewhnmmp25gq7dly9zmgsw52x8csmqjgts7278rx", // 𝓟𝓮𝓽𝓲𝓽𝓮 𝓟𝓻𝓲𝓷𝓬𝓮𝓼𝓼
"npub1ulafm4d3n7ukl7yzg4hfnhfjut74nym5p83e3d67l3j62yc6ysqqrancw2", // naked
"npub13806pd9p833wkgyemeqddjzdksunlq9gszq4yjnhw4l57sjjhwlq6m79nj", // Orvalho
"npub1pl0qa9x3n8wt55em0x3zwuy02rtl5t3jsretr0egjqgkx2f6jztqt0xwew", // nude
"npub1af9lxfzeq5rxmu9zz7d85tn2ex8zvvlx0duqcemcdhkz9cvlt29st3rcgd", // Happy Nut
"npub1mgusda7ujnyuhhudwkyrp763k4dd9xspktekl0tg5v0j76yph8ssyrfdpm", // anisyia
"npub1jge7z2kpmpdra6g58vg95uznve8ctcenmlyp9ntr3kjymscyuqpqty2cdh", // Storm
"npub1y77j6jm5hw34xl5m85aumltv88arh2s7q383allkpfe4muarzc5qzfgru0", // sexy-models
"npub1jp9v034z3a26cp5hajwyuzl0hety5akdpwdnjaqgfd7pm2ts4dwsc29va8", // curatedbliss
"npub1e4n8nah09he25slv00dz3kav3jsu5jvp83aya234ejumcmu2xseqwrp6pl", // Svenno(NSFW)
"npub1suddec4n2jv50pgn9eea35r4k83ahr4mcj0zv2uec36w6jeuwagq82xjgl" // quiet.enjoyer
].map((npub) => (nip19.decode(npub).data as string).toLowerCase());
export const spamAccounts = [];

View File

@ -1,10 +1,11 @@
import { NDKFilter, NDKUser } from "@nostr-dev-kit/ndk"; import { NDKFilter } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { appName, defaultHashTags } from "./env"; import { appName, defaultHashTags, nfswTags } from "./env";
export type NostrImage = { export type NostrImage = {
url: string; url: string;
author: NDKUser; author: string;
tags: string[];
content?: string; content?: string;
}; };
@ -66,3 +67,11 @@ export const hasContentWarning = (event: any) => {
event.tags.filter((t: string[]) => t[0] === "content-warning").length > 0 event.tags.filter((t: string[]) => t[0] === "content-warning").length > 0
); );
}; };
export const hasNsfwTag = (event: any) => {
// ["e", "aab5a68f29d76a04ad79fe7e489087b802ee0f946689d73b0e15931dd40a7af3", "", "reply"]
return (
event.tags.filter((t: string[]) => t[0] === "t" && nfswTags.includes(t[1]))
.length > 0
);
};