diff --git a/public/images/bh2024nostriga.jpg b/public/images/bh2024nostriga.jpg
new file mode 100644
index 0000000..e863899
Binary files /dev/null and b/public/images/bh2024nostriga.jpg differ
diff --git a/public/images/nostriga.jpg b/public/images/nostriga.jpg
deleted file mode 100644
index b84ad5d..0000000
Binary files a/public/images/nostriga.jpg and /dev/null differ
diff --git a/src/components/GridView/index.tsx b/src/components/GridView/index.tsx
index 5b921fe..c2ebc39 100644
--- a/src/components/GridView/index.tsx
+++ b/src/components/GridView/index.tsx
@@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { NostrImage, urlFix } from '../nostrImageDownload';
import './GridView.css';
import GridImage from './GridImage';
-import { Settings } from '../../utils/useNav';
+import useNav, { Settings } from '../../utils/useNav';
import AuthorProfile from '../AuthorProfile/AuthorProfile';
import { useSwipeable } from 'react-swipeable';
import { Helmet } from 'react-helmet';
@@ -26,6 +26,7 @@ const GridView = ({ settings, images, currentImage, setCurrentImage, setViewMode
const showNextImage = () => {
setCurrentImage(idx => (idx !== undefined ? idx + 1 : 0));
};
+ const { nav, currentSettings } = useNav();
const showPreviousImage = () => {
setCurrentImage(idx => (idx !== undefined && idx > 0 ? idx - 1 : idx));
@@ -38,11 +39,15 @@ const GridView = ({ settings, images, currentImage, setCurrentImage, setViewMode
if (event.key === 'ArrowLeft') {
showPreviousImage();
}
- /*
if (event.key === 'Escape') {
- setCurrentImage(undefined);
+ nav({
+ ...currentSettings,
+ topic: undefined,
+ npubs: [],
+ tags: [],
+ list: undefined,
+ });
}
- */
};
const swipeHandlers = useSwipeable({
diff --git a/src/components/MasonryView/MasonryImage.tsx b/src/components/MasonryView/MasonryImage.tsx
index a89675c..f22a3ed 100644
--- a/src/components/MasonryView/MasonryImage.tsx
+++ b/src/components/MasonryView/MasonryImage.tsx
@@ -40,7 +40,12 @@ const MasonryImage = ({ image, onClick, index }: MasonryImageProps) => {
const showAuthor = currentSettings.npubs == undefined || currentSettings.npubs.length != 1; // if we are looking at a single profile, don't show the author
- const description = image.content && image.content?.substring(0, 60) + (image.content.length > 60 ? ' ... ' : ' ');
+ const description = useMemo(
+ () =>
+ image.content &&
+ image.content.replace(/nostr:[a-z0-9]+/, '').substring(0, 60) + (image.content.length > 60 ? ' ... ' : ' '),
+ [image.content]
+ );
const showTags = useMemo(() => uniq(image.tags).slice(0, 5), [image.tags]);
const now = unixNow();
const showInfo = true;
diff --git a/src/components/MasonryView/MasonryView.tsx b/src/components/MasonryView/MasonryView.tsx
index 4718721..8446535 100644
--- a/src/components/MasonryView/MasonryView.tsx
+++ b/src/components/MasonryView/MasonryView.tsx
@@ -80,11 +80,9 @@ const MasonryView = ({ settings, images, currentImage, setCurrentImage, setViewM
if (event.key === 'ArrowLeft') {
showPreviousImage();
}
- /*
if (event.key === 'Escape') {
setCurrentImage(undefined);
}
- */
};
const swipeHandlers = useSwipeable({
diff --git a/src/components/SlideShow.tsx b/src/components/SlideShow.tsx
index 21f3e37..1e14dfb 100644
--- a/src/components/SlideShow.tsx
+++ b/src/components/SlideShow.tsx
@@ -10,8 +10,9 @@ import {
Post,
isReply,
isAdultRelated,
+ hasBlockedTag,
} from './nostrImageDownload';
-import { adultContentTags, adultNPubs, blockedPublicKeys, mixedAdultNPubs, topics } from './env';
+import { adultContentTagsMap, adultNPubs, blockedPublicKeysMap, mixedAdultNPubs, topics } from './env';
import Settings from './Settings';
import SlideView from './SlideView';
import { nip19 } from 'nostr-tools';
@@ -135,7 +136,8 @@ const SlideShow = () => {
events
.filter(
event =>
- !blockedPublicKeys.includes(event.pubkey.toLowerCase()) && // remove blocked authors
+ !blockedPublicKeysMap[event.pubkey.toLowerCase()] && // remove blocked authors
+ !hasBlockedTag(event) &&
(settings.showReplies || !isReply(event)) &&
(settings.showAdult || !isAdultRelated(event, settings.tags.length > 0))
)
@@ -309,10 +311,9 @@ const SlideShow = () => {
const fullScreen = document.fullscreenElement !== null;
const showAdultContentWarning =
- !settings.showAdult &&
- (adultContentTags.some(t => settings.tags.includes(t)) ||
- adultNPubs.some(p => settings.npubs.includes(p)) ||
- mixedAdultNPubs.some(p => settings.npubs.includes(p)));
+ !settings.showAdult && (settings.tags.some(t => adultContentTagsMap[t]) ||
+ adultNPubs.some(p => settings.npubs.includes(p)) ||
+ mixedAdultNPubs.some(p => settings.npubs.includes(p)));
if (showAdultContentWarning) {
return ;
diff --git a/src/components/env.ts b/src/components/env.ts
index 2983ff7..2aaac34 100644
--- a/src/components/env.ts
+++ b/src/components/env.ts
@@ -17,7 +17,7 @@ type Topic = {
by default. Users can enable this content through the adult content flag
in the UI or through a URL parameter.
*/
-export const adultContentTags = [
+const adultContentTags = [
'adult',
'ass',
'blowjob',
@@ -63,11 +63,15 @@ export const adultContentTags = [
'masturbation',
];
-export const topics: { [key: string]: Topic } = {
- nostriga: {
- name: 'Baltic Honey Badger 2024 / NOSTRIGA',
- tags: ['nostriga', 'balticbadger', 'honeybadger', 'riga', 'bh2024', 'hb2024'],
+export const adultContentTagsMap = adultContentTags.reduce(
+ (acc, tag) => {
+ acc[tag.toLocaleLowerCase()] = true;
+ return acc;
},
+ {} as Record
+);
+
+export const topics: { [key: string]: Topic } = {
art: {
name: 'Art',
tags: [
@@ -199,9 +203,13 @@ export const topics: { [key: string]: Topic } = {
},
btcprague: {
name: 'BTC Prague',
- tags: ['btcprague', 'BTCPrague', 'devhackday', 'prague', 'praha'],
+ tags: ['btcprague', 'BTCPrague', 'devhackday'],
description: 'All images/videos with related hashtags #btcprague #prague #praha',
},
+ bh2024nostriga: {
+ name: 'Baltic Honey Badger 2024 / NOSTRIGA',
+ tags: ['nostriga', 'balticbadger', 'honeybadger', 'riga', 'bh2024', 'hb2024'],
+ },
nsfw: {
name: 'NSFW / Adult Content',
tags: adultContentTags,
@@ -381,14 +389,32 @@ export const adultNPubs = [
'npub1rxsxj8egpr3emylfdld0wgh63w048tjh5zaua84h2qjscswn68ysdlt68s',
'npub13lpdphw06d5hy5h7n0xsun9sfpwqsna9gsg0y0d4ukktks048nrseedtx9',
'npub1lrxxjtq7zyp2d4n44tllwqj4q20kk7dslh2xrq0qkwng5lldxqesmvvgyt',
+ 'npub163nprvuh3y36l7we66hs6jhl92xymlnyq29mh3p86upe2828x7mqt8xdwf',
+ 'npub16fsxfvylsvlmv9fz3k7rga3wxl50plm8q708wgkwdr555lczlc5qu7xw8z',
];
-export const adultPublicKeys = adultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
+const adultPublicKeys = adultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
-export const mixedAdultPublicKeys = mixedAdultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
+export const adultPublicKeysMap = adultPublicKeys.reduce(
+ (acc, key) => {
+ acc[key.toLocaleLowerCase()] = true;
+ return acc;
+ },
+ {} as Record
+);
+
+const mixedAdultPublicKeys = mixedAdultNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
+
+export const mixedAdultPublicMaps = mixedAdultPublicKeys.reduce(
+ (acc, key) => {
+ acc[key.toLocaleLowerCase()] = true;
+ return acc;
+ },
+ {} as Record
+);
/* The following profiles have questionable content and are blocked completely on slidestr.net */
-export const blockedNPubs = [
+const blockedNPubs = [
'npub10m6d9ynzzx0w07spu2n5cx36z77smmyn7rs9gsvta57etrcyh68swace67',
'npub10xrnm6sy804cakmeew4g7kd4fl3dfvvsqfk6m3v4c6j4smrh9mlsdwpz7a', // CISAM
'npub125wcpwdn0zmt3accu3jlkv349jgw9d8htk4cjx2spc9qfvusl7hs6np5pt',
@@ -415,9 +441,20 @@ export const blockedNPubs = [
'npub1tt3n7nm548jf4jsgy9vwt25khz2n47d8um0lam0nmpk034zzlp2sfpc7tq',
'npub1yrqtnr4qxvjqj4zs45sw3xlrflzks86dhy0y4hzj9jweujflksfszhsp06',
'npub13mnfsm49p8hka246khma4gdzd9w8ygyt3udrcxmgmmhd5cyt5y3q879pvy',
+ 'npub13yn69pulpr6clwpzfj06rshu7kzj7zqvhf7d3mkyppynzrlnjjzqgsma3m',
];
-export const blockedPublicKeys = blockedNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
+const blockedPublicKeys = blockedNPubs.map(npub => (nip19.decode(npub).data as string).toLowerCase());
+
+export const blockedPublicKeysMap = blockedPublicKeys.reduce(
+ (acc, key) => {
+ acc[key] = true;
+ return acc;
+ },
+ {} as Record
+);
+
+export const blockedHashtags = ['loli'];
export const spamAccounts = [];
diff --git a/src/components/nostrImageDownload.ts b/src/components/nostrImageDownload.ts
index bfb08f2..f280640 100644
--- a/src/components/nostrImageDownload.ts
+++ b/src/components/nostrImageDownload.ts
@@ -1,5 +1,5 @@
import { NDKEvent, NDKFilter, NDKTag } from '@nostr-dev-kit/ndk';
-import { adultContentTags, adultPublicKeys, imageProxy, mixedAdultNPubs } from './env';
+import { adultContentTagsMap, adultPublicKeysMap, blockedHashtags, imageProxy, mixedAdultPublicMaps } from './env';
import uniq from 'lodash/uniq';
import { unixNow } from '../ngine/time';
import { ContentType } from '../utils/useNav';
@@ -94,21 +94,26 @@ export const hasContentWarning = ({ tags }: { tags?: NDKTag[] }) => {
export const hasAdultTag = ({ tags }: { tags?: NDKTag[] }) => {
if (!tags) return false;
// ["e", "aab5a68f29d76a04ad79fe7e489087b802ee0f946689d73b0e15931dd40a7af3", "", "reply"]
- return tags.filter((t: string[]) => t[0] === 't' && adultContentTags.includes(t[1])).length > 0;
+ return tags.some((t: string[]) => t[0] === 't' && adultContentTagsMap[t[1]]);
+};
+
+export const hasBlockedTag = ({ tags }: { tags?: NDKTag[] }) => {
+ if (!tags) return false;
+ return tags.filter((t: string[]) => t[0] === 't' && blockedHashtags.includes(t[1])).length > 0;
};
export const isAdultRelated = ({ tags, pubkey }: { tags?: NDKTag[]; pubkey: string }, isTagSearch: boolean) => {
// if we search for a specific non adult tag and the user in the mixed category
// allow as non adult
- if (isTagSearch && mixedAdultNPubs.includes(pubkey.toLowerCase()) && !hasAdultTag({ tags })) {
+ if (isTagSearch && mixedAdultPublicMaps[pubkey.toLowerCase()] && !hasAdultTag({ tags })) {
return false;
}
return (
hasContentWarning({ tags }) || // block content warning
hasAdultTag({ tags }) || // block adult tags
- mixedAdultNPubs.includes(pubkey.toLowerCase()) || // block mixed adult authors
- adultPublicKeys.includes(pubkey.toLowerCase()) // block adult authors
+ mixedAdultPublicMaps[pubkey.toLowerCase()] || // block mixed adult authors
+ adultPublicKeysMap[pubkey.toLowerCase()] // block adult authors
);
};