your personal website on atproto - mirror blento.app
26
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #301 from polijn/main

fix secret image in edit

authored by

Florian and committed by
GitHub
13f84dca a4fe224a

+49 -3
+49 -3
src/lib/cards/media/SecretImageCard/EditingSecretImageCard.svelte
··· 1 1 <script lang="ts"> 2 + import { page } from '$app/state'; 3 + import { getDidContext } from '$lib/website/context'; 4 + import { getBlobURL } from '$lib/atproto'; 5 + import { decryptBlob } from './crypto'; 2 6 import type { ContentComponentProps } from '../../types'; 3 7 import { compressImage } from '$lib/atproto/image-helper'; 4 8 5 9 let { item = $bindable() }: ContentComponentProps = $props(); 10 + 11 + const did = getDidContext(); 6 12 7 13 let fileInput = $state<HTMLInputElement | undefined>(undefined); 8 14 let dragOver = $state(false); 15 + let decryptedUrl = $state<string | null>(null); 16 + 17 + const imageUrl = $derived( 18 + item.cardData.rawImage?.objectUrl || decryptedUrl || item.cardData.preview 19 + ); 20 + const hasImage = $derived(!!imageUrl); 21 + const showPixelated = $derived( 22 + !item.cardData.rawImage?.objectUrl && !decryptedUrl && !!item.cardData.preview 23 + ); 24 + 25 + $effect(() => { 26 + const secret = page.url.searchParams.get('secret'); 27 + const blob = item.cardData.encryptedImage; 28 + if (!secret || !blob || typeof blob !== 'object' || blob.$type !== 'blob') return; 29 + if (item.cardData.rawImage?.objectUrl) return; 30 + 31 + decryptImage(secret, blob); 9 32 10 - const hasImage = $derived(item.cardData.rawImage?.objectUrl || item.cardData.preview); 33 + return () => { 34 + if (decryptedUrl) { 35 + URL.revokeObjectURL(decryptedUrl); 36 + decryptedUrl = null; 37 + } 38 + }; 39 + }); 11 40 12 - const imageUrl = $derived(item.cardData.rawImage?.objectUrl || item.cardData.preview); 41 + // eslint-disable-next-line @typescript-eslint/no-explicit-any 42 + async function decryptImage(password: string, blob: any) { 43 + try { 44 + const url = await getBlobURL({ did, blob }); 45 + const response = await fetch(url); 46 + if (!response.ok) throw new Error('Failed to fetch blob'); 47 + const encryptedBlob = await response.blob(); 48 + const decrypted = await decryptBlob(encryptedBlob, password); 49 + decryptedUrl = URL.createObjectURL(decrypted); 50 + } catch { 51 + // wrong password or fetch error - stay pixelated 52 + } 53 + } 13 54 14 55 async function handleFile(file: File) { 15 56 const { blob } = await compressImage(file); ··· 68 109 onclick={() => fileInput?.click()} 69 110 > 70 111 {#if hasImage} 71 - <img class="absolute inset-0 h-full w-full object-cover" src={imageUrl} alt="" /> 112 + <img 113 + class="absolute inset-0 h-full w-full object-cover" 114 + style={showPixelated ? 'image-rendering: pixelated;' : ''} 115 + src={imageUrl} 116 + alt="" 117 + /> 72 118 <div 73 119 class="absolute inset-0 flex items-center justify-center bg-black/0 transition-colors hover:bg-black/30" 74 120 >