Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

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

at main 117 lines 3.0 kB view raw
1import React from 'react' 2 3import * as persisted from '#/state/persisted' 4 5type StateContext = persisted.Schema['imageCdnHost'] 6type SetContext = (v: persisted.Schema['imageCdnHost']) => void 7 8const stateContext = React.createContext<StateContext>( 9 persisted.defaults.imageCdnHost, 10) 11const setContext = React.createContext<SetContext>( 12 (_: persisted.Schema['imageCdnHost']) => {}, 13) 14 15const DEFAULT_IMAGE_CDN_ORIGIN = normalizeOrigin( 16 persisted.defaults.imageCdnHost ?? '', 17) 18 19export function Provider({children}: React.PropsWithChildren<{}>) { 20 const [state, setState] = React.useState(persisted.get('imageCdnHost')) 21 22 const setStateWrapped = React.useCallback( 23 (imageCdnHost: persisted.Schema['imageCdnHost']) => { 24 setState(imageCdnHost) 25 persisted.write('imageCdnHost', imageCdnHost) 26 }, 27 [setState], 28 ) 29 30 React.useEffect(() => { 31 return persisted.onUpdate('imageCdnHost', nextImageCdnHost => { 32 setState(nextImageCdnHost) 33 }) 34 }, [setStateWrapped]) 35 36 return ( 37 <stateContext.Provider value={state}> 38 <setContext.Provider value={setStateWrapped}> 39 {children} 40 </setContext.Provider> 41 </stateContext.Provider> 42 ) 43} 44 45export function useImageCdnHost() { 46 return React.useContext(stateContext) ?? persisted.defaults.imageCdnHost! 47} 48 49export function useSetImageCdnHost() { 50 return React.useContext(setContext) 51} 52 53function normalizeOrigin(input: string) { 54 try { 55 return new URL(input).origin 56 } catch { 57 return null 58 } 59} 60 61function modifyImageCdnHost(src: string, imageCdnHost: string) { 62 try { 63 const srcUrl = new URL(src) 64 if (srcUrl.protocol !== 'https:' && srcUrl.protocol !== 'http:') { 65 return null 66 } 67 if (!srcUrl.pathname.startsWith('/img/')) { 68 return null 69 } 70 71 const cdnUrl = new URL(imageCdnHost) 72 srcUrl.protocol = cdnUrl.protocol 73 srcUrl.hostname = cdnUrl.hostname 74 srcUrl.port = cdnUrl.port 75 76 return srcUrl.toString() 77 } catch { 78 return null 79 } 80} 81 82export function maybeModifyImageCdnHost(src: string, imageCdnHost?: string) { 83 if (!imageCdnHost) { 84 return src 85 } 86 87 const nextOrigin = normalizeOrigin(imageCdnHost) 88 if (!nextOrigin || nextOrigin === DEFAULT_IMAGE_CDN_ORIGIN) { 89 return src 90 } 91 92 return modifyImageCdnHost(src, nextOrigin) ?? src 93} 94 95/** 96 * Combined image transformation pipeline: applies high-quality image format 97 * transformation first (on original CDN), then applies CDN host rewrite. 98 */ 99export function applyImageTransforms( 100 src: string, 101 options: { 102 imageCdnHost?: string 103 highQualityImages?: boolean 104 }, 105) { 106 // Import is deferred to avoid circular dependency 107 const {maybeModifyHighQualityImage} = 108 require('./high-quality-images') as typeof import('./high-quality-images') 109 110 // First apply quality transformation on original CDN 111 const withQuality = maybeModifyHighQualityImage( 112 src, 113 options.highQualityImages, 114 ) 115 // Then apply CDN host replacement 116 return maybeModifyImageCdnHost(withQuality, options.imageCdnHost) 117}