@@ -15,21 +15,77 @@ export function getFaviconKey(env: Env) {
1515 return path_join ( env . S3_FOLDER || "" , "favicon.webp" ) ;
1616}
1717
18+ async function buildFaviconFromSource ( c : AppContext , sourceUrl : string , faviconKey : string ) {
19+ const env = c . get ( 'env' ) ;
20+ const s3 = createS3Client ( env ) ;
21+ const imageRequest = new Request ( sourceUrl , {
22+ headers : c . req . raw . headers ,
23+ } ) ;
24+
25+ const response = await fetch ( imageRequest , {
26+ cf : {
27+ image : {
28+ width : 144 ,
29+ height : 144 ,
30+ fit : "cover" ,
31+ format : "webp" ,
32+ quality : 100 ,
33+ } ,
34+ } ,
35+ } ) ;
36+
37+ if ( ! response . ok ) {
38+ return response ;
39+ }
40+
41+ const arrayBuffer = await response . arrayBuffer ( ) ;
42+ await putObject (
43+ s3 ,
44+ env ,
45+ faviconKey ,
46+ new Uint8Array ( arrayBuffer ) ,
47+ "image/webp" ,
48+ ) ;
49+
50+ return new Response ( arrayBuffer , {
51+ status : 200 ,
52+ headers : {
53+ "Content-Type" : "image/webp" ,
54+ "Cache-Control" : "public, max-age=31536000" ,
55+ } ,
56+ } ) ;
57+ }
58+
1859export function FaviconService ( ) : Hono {
1960 const app = new Hono ( ) ;
2061
2162 // GET /favicon
2263 app . get ( "/" , async ( c : AppContext ) => {
2364 const env = c . get ( 'env' ) ;
65+ const clientConfig = c . get ( 'clientConfig' ) ;
2466 const accessHost = env . S3_ACCESS_HOST || env . S3_ENDPOINT ;
2567 const faviconKey = getFaviconKey ( env ) ;
2668
2769 try {
2870 const response = await fetch ( new Request ( `${ accessHost } /${ faviconKey } ` ) ) ;
2971
3072 if ( ! response . ok ) {
31- c . status ( response . status as 200 | 400 | 401 | 403 | 404 | 500 ) ;
32- return c . text ( await response . text ( ) ) ;
73+ const avatar = await clientConfig . get ( "site.avatar" ) as string | undefined ;
74+ if ( ! avatar ) {
75+ c . status ( response . status as 200 | 400 | 401 | 403 | 404 | 500 ) ;
76+ return c . text ( await response . text ( ) ) ;
77+ }
78+
79+ const avatarUrl = new URL ( avatar , c . req . url ) . toString ( ) ;
80+ const generatedFavicon = await buildFaviconFromSource ( c , avatarUrl , faviconKey ) ;
81+ if ( ! generatedFavicon . ok ) {
82+ c . status ( generatedFavicon . status as 200 | 400 | 401 | 403 | 404 | 500 ) ;
83+ return c . text ( await generatedFavicon . text ( ) ) ;
84+ }
85+
86+ c . header ( "Content-Type" , generatedFavicon . headers . get ( "Content-Type" ) || "image/webp" ) ;
87+ c . header ( "Cache-Control" , generatedFavicon . headers . get ( "Cache-Control" ) || "public, max-age=31536000" ) ;
88+ return c . body ( await generatedFavicon . arrayBuffer ( ) ) ;
3389 }
3490
3591 c . header ( "Content-Type" , "image/webp" ) ;
0 commit comments