feat: added video filter
This commit is contained in:
parent
9c2388c2b1
commit
d10d514ebf
@ -48,6 +48,7 @@ const Home = () => {
|
||||
className="topic"
|
||||
onClick={() =>
|
||||
nav({
|
||||
...currentSettings,
|
||||
tags: [],
|
||||
npubs: [],
|
||||
showReplies: false,
|
||||
|
@ -76,7 +76,7 @@ const MasonryImage = ({ image, onClick, index }: MasonryImageProps) => {
|
||||
loading="lazy"
|
||||
key={image.url}
|
||||
onClick={onClick}
|
||||
src={createImgProxyUrl(image.url, 320, -1)} // TODO make width dynamic, also with column sizes, and full screen image size
|
||||
src={createImgProxyUrl(image.url, 320, -1)}
|
||||
></img>
|
||||
{
|
||||
!loaded && <div style={{ height: 200 }}></div> // Spacer when image is not loaded yet
|
||||
|
@ -6,6 +6,7 @@ import useOnScreen from '../../utils/useOnScreen';
|
||||
import IconMicMuted from '../Icons/IconMicMuted';
|
||||
import IconMicOn from '../Icons/IconMicOn';
|
||||
import useWindowSize from '../../utils/useWindowSize';
|
||||
import useImageSizes from '../../utils/useImageSizes';
|
||||
|
||||
interface ScrollImageProps {
|
||||
image: NostrImage;
|
||||
@ -24,21 +25,7 @@ const ScrollImage = ({ image, currentImage, setCurrentImage, index }: ScrollImag
|
||||
const isVisible = useOnScreen(containerRef);
|
||||
const nearCurrentImage = useMemo(() => Math.abs((currentImage || 0) - index) < 3, [currentImage, index]);
|
||||
const mediaIsVideo = useMemo(() => isVideo(image.url), [image.url]);
|
||||
|
||||
const imageProxyUrl320 = useMemo(() => createImgProxyUrl(image.url, 320, -1), [image.url]);
|
||||
|
||||
const currentImageProxyUrl = useMemo(() => {
|
||||
const imageProxyUrl800 = createImgProxyUrl(image.url, 800, -1);
|
||||
const imageProxyUrl1920 = createImgProxyUrl(image.url, 1920, -1);
|
||||
|
||||
return width == undefined
|
||||
? imageProxyUrl320
|
||||
: width < 800
|
||||
? imageProxyUrl320
|
||||
: width < 1920
|
||||
? imageProxyUrl800
|
||||
: imageProxyUrl1920;
|
||||
}, [image.url, imageProxyUrl320, width]);
|
||||
const { optimalImageUrl, imageUrl320w } = useImageSizes(image.url);
|
||||
|
||||
const blurBgUrl = useMemo(() => {
|
||||
if (mediaIsVideo) return '';
|
||||
@ -48,9 +35,9 @@ const ScrollImage = ({ image, currentImage, setCurrentImage, index }: ScrollImag
|
||||
return createImgProxyUrl(image.url, 200, 200);
|
||||
} else {
|
||||
// on Desktop use the 320x masonry image
|
||||
return imageProxyUrl320;
|
||||
return imageUrl320w;
|
||||
}
|
||||
}, [image.url, imageProxyUrl320, isMobile, mediaIsVideo]);
|
||||
}, [image.url, imageUrl320w, isMobile, mediaIsVideo]);
|
||||
|
||||
/*
|
||||
const toggleVideoPause = (video: HTMLVideoElement | null) => {
|
||||
@ -126,7 +113,7 @@ const ScrollImage = ({ image, currentImage, setCurrentImage, index }: ScrollImag
|
||||
className={`image`}
|
||||
loading="lazy"
|
||||
key={image.url}
|
||||
src={currentImageProxyUrl}
|
||||
src={optimalImageUrl}
|
||||
></img>
|
||||
))}
|
||||
{isVisible && mediaIsVideo && (
|
||||
|
@ -23,11 +23,8 @@ const ScrollView = ({ settings, images, currentImage, setCurrentImage, setViewMo
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [state, setState] = useGlobalState();
|
||||
const [showInfoPanel, setShowInfoPanel] = useState(false);
|
||||
|
||||
// const sortedImages = useMemo(
|
||||
// () => images.sort((a, b) => (b.timestamp && a.timestamp ? b.timestamp - a.timestamp : 0)), // sort by timestamp descending
|
||||
// [images] // settings is not used here, but we need to include it to trigger a re-render when it changes
|
||||
// );
|
||||
const { activeProfile, activeNpub } = useActiveProfile(settings, state.activeImage);
|
||||
const title = useTitle(settings, activeProfile);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentImage) {
|
||||
@ -45,11 +42,8 @@ const ScrollView = ({ settings, images, currentImage, setCurrentImage, setViewMo
|
||||
}
|
||||
}, [images, currentImage, setState]);
|
||||
|
||||
const { activeProfile, activeNpub } = useActiveProfile(settings, state.activeImage);
|
||||
const title = useTitle(settings, activeProfile);
|
||||
|
||||
const infoPanelAvailable = state.activeImage && (state.activeImage.content || state.activeImage.tags.length > 0);
|
||||
// console.log(JSON.stringify([state?.activeImage?.content, state?.activeImage?.tags]));
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="scrollview" tabIndex={0}>
|
||||
<Helmet>
|
||||
|
@ -17,7 +17,7 @@ import SlideView from './SlideView';
|
||||
import { nip19 } from 'nostr-tools';
|
||||
import uniqBy from 'lodash/uniqBy';
|
||||
import AdultContentInfo from './AdultContentInfo';
|
||||
import useNav from '../utils/useNav';
|
||||
import useNav, { ContentType } from '../utils/useNav';
|
||||
import { useGlobalState } from '../utils/globalState';
|
||||
import ScrollView from './ScrollView/ScrollView';
|
||||
import IconPlay from './Icons/IconPlay';
|
||||
@ -238,25 +238,27 @@ const SlideShow = () => {
|
||||
|
||||
useEffect(() => {
|
||||
images.current = uniqBy(
|
||||
posts.flatMap(p => {
|
||||
return extractImageUrls(p.event.content)
|
||||
.filter(url => isImage(url) || isVideo(url))
|
||||
.filter(url => !url.startsWith('https://creatr.nostr.wine/')) // Filter our creatr.nostr.wine content, since we don't have NIP-98 auth yet.
|
||||
.map(url => ({
|
||||
post: p,
|
||||
url,
|
||||
author: nip19.npubEncode(p.event.pubkey),
|
||||
authorId: p.event.pubkey,
|
||||
content: prepareContent(p.event.content),
|
||||
type: isVideo(url) ? 'video' : 'image',
|
||||
timestamp: p.event.created_at,
|
||||
noteId: p.event.id || '',
|
||||
tags: p.event.tags?.filter((t: string[]) => t[0] === 't').map((t: string[]) => t[1].toLowerCase()) || [],
|
||||
}));
|
||||
}),
|
||||
posts
|
||||
.flatMap(p => {
|
||||
return extractImageUrls(p.event.content)
|
||||
.filter(url => isImage(url) || isVideo(url))
|
||||
.filter(url => !url.startsWith('https://creatr.nostr.wine/')) // Filter our creatr.nostr.wine content, since we don't have NIP-98 auth yet.
|
||||
.map(url => ({
|
||||
post: p,
|
||||
url,
|
||||
author: nip19.npubEncode(p.event.pubkey),
|
||||
authorId: p.event.pubkey,
|
||||
content: prepareContent(p.event.content),
|
||||
type: (isVideo(url) ? 'video' : 'image') as ContentType,
|
||||
timestamp: p.event.created_at,
|
||||
noteId: p.event.id || '',
|
||||
tags: p.event.tags?.filter((t: string[]) => t[0] === 't').map((t: string[]) => t[1].toLowerCase()) || [],
|
||||
}));
|
||||
})
|
||||
.filter(i => settings.type == 'all' || settings.type == i.type),
|
||||
'url'
|
||||
);
|
||||
}, [posts]);
|
||||
}, [posts, settings.type]);
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (showSettings) return;
|
||||
@ -322,7 +324,9 @@ const SlideShow = () => {
|
||||
onClick={() => {
|
||||
if (viewMode == 'scroll' || viewMode == 'slideshow') {
|
||||
setViewMode('grid');
|
||||
} else navigate('/');
|
||||
} else {
|
||||
navigate(`/${settings.type !== 'all' ? `?type=${settings.type}` : ''}`);
|
||||
}
|
||||
}}
|
||||
>
|
||||
✕
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { useEffect } from 'react';
|
||||
import SlideImage from './SlideImage';
|
||||
import SlideVideo from './SlideVideo';
|
||||
import { ContentType } from '@/utils/useNav';
|
||||
|
||||
type SlideProps = {
|
||||
url: string;
|
||||
paused: boolean;
|
||||
type: 'image' | 'video';
|
||||
type: ContentType;
|
||||
onAnimationEnded?: () => void;
|
||||
animationDuration?: number;
|
||||
noteId: string;
|
||||
|
@ -9,6 +9,8 @@ type SlideImageProps = {
|
||||
|
||||
const SlideImage = ({ url, paused, style, noteId }: SlideImageProps) => {
|
||||
const loaded = useImageLoaded(url);
|
||||
// const { optimalImageUrl } = useImageSizes(url);
|
||||
|
||||
return (
|
||||
loaded && (
|
||||
<div
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { nip19 } from 'nostr-tools';
|
||||
|
||||
export const imageProxy = import.meta.env.VITE_IMAGE_PROXY || 'https://imgproxy.slidestr.net';
|
||||
export const imageProxy = import.meta.env.VITE_IMAGE_PROXY || 'https://images.slidestr.net';
|
||||
|
||||
export const appName = import.meta.env.VITE_APP_NAME || 'slidestr.net';
|
||||
|
||||
@ -90,7 +90,7 @@ export const topics: { [key: string]: Topic } = {
|
||||
'stablediffusion',
|
||||
],
|
||||
},
|
||||
bitcoin: { name: '₿itcoin', tags: ['bitcoin', 'plebchain'] },
|
||||
bitcoin: { name: '₿itcoin', tags: ['bitcoin', 'plebchain', 'hfsp', 'btfd', 'buythedip'] },
|
||||
nostr: { name: 'Nostr', tags: ['coffeechain', 'nostr', 'zapathon', 'grownostr', 'freedom', 'purple'] },
|
||||
animals: { name: 'Animals', tags: ['catstr', 'dogstr', 'animal', 'animals', 'bird', 'birds', 'pets'] },
|
||||
photography: {
|
||||
|
@ -2,6 +2,7 @@ import { NDKEvent, NDKFilter, NDKTag } from '@nostr-dev-kit/ndk';
|
||||
import { adultContentTags, adultPublicKeys, imageProxy, mixedAdultNPubs } from './env';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { unixNow } from '../ngine/time';
|
||||
import { ContentType } from '../utils/useNav';
|
||||
|
||||
export type Post = {
|
||||
event: NDKEvent;
|
||||
@ -17,7 +18,7 @@ export type NostrImage = {
|
||||
content?: string;
|
||||
timestamp?: number;
|
||||
noteId: string;
|
||||
type: 'image' | 'video';
|
||||
type: ContentType;
|
||||
post: Post;
|
||||
};
|
||||
|
||||
@ -71,7 +72,9 @@ export const extractImageUrls = (text: string): string[] => {
|
||||
if (text == undefined) return [];
|
||||
|
||||
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
||||
const matchedUrls = (text.match(urlRegex) || []).map(u => urlFix(u));
|
||||
const matchedUrls = (text.match(urlRegex) || [])
|
||||
.map(u => urlFix(u))
|
||||
.filter(u => !u.startsWith('https://commons.wikimedia.org/wiki/')); // the url ends with .jpg but these are wiki media web pages, not image urls
|
||||
return uniq(matchedUrls);
|
||||
};
|
||||
|
||||
|
24
src/utils/useImageSizes.ts
Normal file
24
src/utils/useImageSizes.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { createImgProxyUrl } from '../components/nostrImageDownload';
|
||||
import useWindowSize from './useWindowSize';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const useImageSizes = (imageUrl: string) => {
|
||||
const { width } = useWindowSize();
|
||||
|
||||
const imageUrl320w = useMemo(() => createImgProxyUrl(imageUrl, 320, -1), [imageUrl]);
|
||||
const imageUrl800w = useMemo(() => createImgProxyUrl(imageUrl, 800, -1), [imageUrl]);
|
||||
const imageUrl1920w = useMemo(() => createImgProxyUrl(imageUrl, 1920, -1), [imageUrl]);
|
||||
|
||||
const optimalImageUrl = useMemo(() => {
|
||||
return width == undefined ? imageUrl320w : width < 800 ? imageUrl320w : width < 1920 ? imageUrl800w : imageUrl1920w;
|
||||
}, [width, imageUrl320w, imageUrl800w, imageUrl1920w]);
|
||||
|
||||
return {
|
||||
optimalImageUrl,
|
||||
imageUrl320w,
|
||||
imageUrl800w,
|
||||
imageUrl1920w,
|
||||
};
|
||||
};
|
||||
|
||||
export default useImageSizes;
|
@ -10,8 +10,11 @@ export type Settings = {
|
||||
follows: boolean;
|
||||
list?: string;
|
||||
topic?: string;
|
||||
type: ContentType;
|
||||
};
|
||||
|
||||
export type ContentType = 'image' | 'video' | 'all';
|
||||
|
||||
const useNav = () => {
|
||||
const { tags, npub, list, topic } = useParams();
|
||||
const [searchParams] = useSearchParams();
|
||||
@ -21,6 +24,8 @@ const useNav = () => {
|
||||
const adult = searchParams.get('adult') === 'true' || searchParams.get('nsfw') === 'true';
|
||||
const replies = searchParams.get('replies') === 'true';
|
||||
const reposts = searchParams.get('reposts') === 'true';
|
||||
const type = searchParams.get('type') as ContentType || 'all';
|
||||
|
||||
const follows = window.location.pathname.startsWith('/follows');
|
||||
const useTags = tags?.split(',') || [];
|
||||
|
||||
@ -31,6 +36,7 @@ const useNav = () => {
|
||||
showReplies: replies,
|
||||
showReposts: reposts,
|
||||
follows,
|
||||
type,
|
||||
list,
|
||||
topic,
|
||||
};
|
||||
@ -50,6 +56,9 @@ const useNav = () => {
|
||||
if (settings.showReposts) {
|
||||
searchParams.push('reposts=true');
|
||||
}
|
||||
if (settings.type && settings.type != 'all') {
|
||||
searchParams.push(`type=${settings.type}`);
|
||||
}
|
||||
|
||||
const postfix = searchParams.length > 0 ? `?${searchParams.join('&')}` : '';
|
||||
console.log(settings);
|
||||
|
Loading…
Reference in New Issue
Block a user