Merge pull request #174 from v0l/img-proxy

Image proxy service
This commit is contained in:
Kieran 2023-01-31 09:33:21 +00:00 committed by GitHub
commit c82fcd63ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 57 deletions

View File

@ -2,22 +2,27 @@ import "./Avatar.css";
import Nostrich from "../nostrich.jpg"; import Nostrich from "../nostrich.jpg";
import { CSSProperties } from "react"; import { CSSProperties } from "react";
import type { UserMetadata } from "Nostr"; import type { UserMetadata } from "Nostr";
import { useSelector } from "react-redux";
import { RootState } from "State/Store";
import { ApiHost } from "Const";
const Avatar = ({ user, ...rest }: { user?: UserMetadata, onClick?: () => void }) => {
const useImageProxy = useSelector((s: RootState) => s.login.preferences.useImageProxy);
const Avatar = ({ user, ...rest }: { user?: UserMetadata, onClick?: () => void}) => { const avatarUrl = (user?.picture?.length ?? 0) === 0 ? Nostrich :
const avatarUrl = (user?.picture?.length ?? 0) === 0 ? Nostrich : user?.picture (useImageProxy ? `${ApiHost}/api/v1/imgproxy/${window.btoa(user!.picture!)}` : user?.picture)
const backgroundImage = `url(${avatarUrl})` const backgroundImage = `url(${avatarUrl})`
const domain = user?.nip05 && user.nip05.split('@')[1] const domain = user?.nip05 && user.nip05.split('@')[1]
const style = { '--img-url': backgroundImage } as CSSProperties const style = { '--img-url': backgroundImage } as CSSProperties
return ( return (
<div <div
{...rest} {...rest}
style={style} style={style}
className="avatar" className="avatar"
data-domain={domain?.toLowerCase()} data-domain={domain?.toLowerCase()}
> >
</div> </div>
) )
} }
export default Avatar export default Avatar

View File

@ -39,7 +39,7 @@ export default function NoteReaction(props: NoteReactionProps) {
* Some clients embed the reposted note in the content * Some clients embed the reposted note in the content
*/ */
function extractRoot() { function extractRoot() {
if (ev?.Kind === EventKind.Repost && ev.Content.length > 0) { if (ev?.Kind === EventKind.Repost && ev.Content.length > 0 && ev.Content !== "#[0]") {
try { try {
let r: RawEvent = JSON.parse(ev.Content); let r: RawEvent = JSON.parse(ev.Content);
return r as TaggedRawEvent; return r as TaggedRawEvent;

View File

@ -71,6 +71,15 @@ const PreferencesPage = () => {
</select> </select>
</div> </div>
</div> </div>
<div className="card flex">
<div className="flex f-col f-grow">
<div>Image proxy</div>
<small>Use the caching image proxy to load avatars</small>
</div>
<div>
<input type="checkbox" checked={perf.useImageProxy} onChange={e => dispatch(setPreferences({ ...perf, useImageProxy: e.target.checked }))} />
</div>
</div>
<div className="card flex"> <div className="card flex">
<div className="flex f-col f-grow"> <div className="flex f-col f-grow">
<div>Debug Menus</div> <div>Debug Menus</div>

View File

@ -13,10 +13,10 @@ const RelayListKey = "last-relays";
const FollowList = "last-follows"; const FollowList = "last-follows";
export interface NotificationRequest { export interface NotificationRequest {
title: string title: string
body: string body: string
icon: string icon: string
timestamp: number timestamp: number
} }
export interface UserPreferences { export interface UserPreferences {
@ -50,10 +50,15 @@ export interface UserPreferences {
*/ */
showDebugMenus: boolean, showDebugMenus: boolean,
/** /**
* File uploading service to upload attachments to * File uploading service to upload attachments to
*/ */
fileUploader: "void.cat" | "nostr.build" fileUploader: "void.cat" | "nostr.build",
/**
* Use image proxy service to compress avatars
*/
useImageProxy: boolean,
} }
export interface LoginStore { export interface LoginStore {
@ -155,7 +160,8 @@ const InitState = {
confirmReposts: false, confirmReposts: false,
showDebugMenus: false, showDebugMenus: false,
autoShowLatest: false, autoShowLatest: false,
fileUploader: "void.cat" fileUploader: "void.cat",
useImageProxy: true
} }
} as LoginStore; } as LoginStore;
@ -279,21 +285,21 @@ const LoginSlice = createSlice({
window.localStorage.setItem(FollowList, JSON.stringify(state.follows)); window.localStorage.setItem(FollowList, JSON.stringify(state.follows));
}, },
setMuted(state, action: PayloadAction<{createdAt: number, keys: HexKey[]}>) { setMuted(state, action: PayloadAction<{ createdAt: number, keys: HexKey[] }>) {
const { createdAt, keys } = action.payload const { createdAt, keys } = action.payload
if (createdAt >= state.latestMuted) { if (createdAt >= state.latestMuted) {
const muted = new Set([...keys]) const muted = new Set([...keys])
state.muted = Array.from(muted) state.muted = Array.from(muted)
state.latestMuted = createdAt state.latestMuted = createdAt
} }
}, },
setBlocked(state, action: PayloadAction<{createdAt: number, keys: HexKey[]}>) { setBlocked(state, action: PayloadAction<{ createdAt: number, keys: HexKey[] }>) {
const { createdAt, keys } = action.payload const { createdAt, keys } = action.payload
if (createdAt >= state.latestMuted) { if (createdAt >= state.latestMuted) {
const blocked = new Set([...keys]) const blocked = new Set([...keys])
state.blocked = Array.from(blocked) state.blocked = Array.from(blocked)
state.latestMuted = createdAt state.latestMuted = createdAt
} }
}, },
addDirectMessage: (state, action: PayloadAction<TaggedRawEvent | Array<TaggedRawEvent>>) => { addDirectMessage: (state, action: PayloadAction<TaggedRawEvent | Array<TaggedRawEvent>>) => {
let n = action.payload; let n = action.payload;
@ -352,26 +358,26 @@ export const {
} = LoginSlice.actions; } = LoginSlice.actions;
export function sendNotification({ title, body, icon, timestamp }: NotificationRequest) { export function sendNotification({ title, body, icon, timestamp }: NotificationRequest) {
return async (dispatch: AppDispatch, getState: () => RootState) => { return async (dispatch: AppDispatch, getState: () => RootState) => {
const state = getState() const state = getState()
const { readNotifications } = state.login const { readNotifications } = state.login
const hasPermission = "Notification" in window && Notification.permission === "granted" const hasPermission = "Notification" in window && Notification.permission === "granted"
const shouldShowNotification = hasPermission && timestamp > readNotifications const shouldShowNotification = hasPermission && timestamp > readNotifications
if (shouldShowNotification) { if (shouldShowNotification) {
try { try {
let worker = await navigator.serviceWorker.ready; let worker = await navigator.serviceWorker.ready;
worker.showNotification(title, { worker.showNotification(title, {
tag: "notification", tag: "notification",
vibrate: [500], vibrate: [500],
body, body,
icon, icon,
timestamp, timestamp,
}); });
} catch (error) { } catch (error) {
console.warn(error) console.warn(error)
} }
}
} }
}
} }
export const reducer = LoginSlice.reducer; export const reducer = LoginSlice.reducer;