enhance: Proxy custom emojis to reduce image size and accelerate the frontend (#9431)
* fix(server): /emoji to accept `@.` host expression
* fix(client): use MkEmoji for custom emoji in MkEmojiPicker
* change convertToWebp
* nanka iroiro
* remove
* fix
* nearLosslessは労多くして益少なしなのでやめる
* do not cleanup tmp for development
* update sharp.js to 0.31.3
* mixed: true
* fix MkAutocomplete of 912791b3ab
* clean up
* https://github.com/misskey-dev/misskey/pull/9431#discussion_r1059215943
			
			
This commit is contained in:
		| @@ -9,7 +9,7 @@ import type { Config } from '@/config.js'; | ||||
| import { isMimeImage } from '@/misc/is-mime-image.js'; | ||||
| import { createTemp } from '@/misc/create-temp.js'; | ||||
| import { DownloadService } from '@/core/DownloadService.js'; | ||||
| import { ImageProcessingService } from '@/core/ImageProcessingService.js'; | ||||
| import { ImageProcessingService, webpDefault } from '@/core/ImageProcessingService.js'; | ||||
| import type { IImage } from '@/core/ImageProcessingService.js'; | ||||
| import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; | ||||
| import { StatusError } from '@/misc/status-error.js'; | ||||
| @@ -81,8 +81,21 @@ export class MediaProxyServerService { | ||||
| 			const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image'); | ||||
| 	 | ||||
| 			let image: IImage; | ||||
| 	 | ||||
| 			if ('static' in request.query && isConvertibleImage) { | ||||
| 			if ('emoji' in request.query && isConvertibleImage) { | ||||
| 				const data = await sharp(path, { animated: !('static' in request.query) }) | ||||
| 					.resize({ | ||||
| 						height: 128, | ||||
| 						withoutEnlargement: true, | ||||
| 					}) | ||||
| 					.webp(webpDefault) | ||||
| 					.toBuffer(); | ||||
|  | ||||
| 				image = { | ||||
| 					data, | ||||
| 					ext: 'webp', | ||||
| 					type: 'image/webp', | ||||
| 				}; | ||||
| 			} else if ('static' in request.query && isConvertibleImage) { | ||||
| 				image = await this.imageProcessingService.convertToWebp(path, 498, 280); | ||||
| 			} else if ('preview' in request.query && isConvertibleImage) { | ||||
| 				image = await this.imageProcessingService.convertToWebp(path, 200, 200); | ||||
| @@ -91,7 +104,7 @@ export class MediaProxyServerService { | ||||
| 					// 画像でないなら404でお茶を濁す | ||||
| 					throw new StatusError('Unexpected mime', 404); | ||||
| 				} | ||||
| 	 | ||||
|  | ||||
| 				const mask = sharp(path) | ||||
| 					.resize(96, 96, { | ||||
| 						fit: 'inside', | ||||
| @@ -121,8 +134,8 @@ export class MediaProxyServerService { | ||||
| 					ext: 'png', | ||||
| 					type: 'image/png', | ||||
| 				}; | ||||
| 			}	else if (mime === 'image/svg+xml') { | ||||
| 				image = await this.imageProcessingService.convertToWebp(path, 2048, 2048, 1); | ||||
| 			} else if (mime === 'image/svg+xml') { | ||||
| 				image = await this.imageProcessingService.convertToWebp(path, 2048, 2048, webpDefault); | ||||
| 			} else if (!mime.startsWith('image/') || !FILE_TYPE_BROWSERSAFE.includes(mime)) { | ||||
| 				throw new StatusError('Rejected type', 403, 'Rejected type'); | ||||
| 			} else { | ||||
|   | ||||
| @@ -220,7 +220,7 @@ export class ClientServerService { | ||||
| 			return reply.sendFile('/apple-touch-icon.png', staticAssets); | ||||
| 		}); | ||||
|  | ||||
| 		fastify.get<{ Params: { path: string } }>('/emoji/:path(.*)', async (request, reply) => { | ||||
| 		fastify.get<{ Params: { path: string }; Querystring: { static?: any; }; }>('/emoji/:path(.*)', async (request, reply) => { | ||||
| 			const path = request.params.path; | ||||
|  | ||||
| 			if (!path.match(/^[a-zA-Z0-9\-_@\.]+?\.webp$/)) { | ||||
| @@ -244,8 +244,15 @@ export class ClientServerService { | ||||
|  | ||||
| 			reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\''); | ||||
|  | ||||
| 			// ?? emoji.originalUrl してるのは後方互換性のため | ||||
| 			return await reply.redirect(301, emoji.publicUrl ?? emoji.originalUrl); | ||||
| 			const url = new URL("/proxy/emoji.webp", this.config.url); | ||||
| 			url.searchParams.set('url', emoji.publicUrl ?? emoji.originalUrl); // ?? emoji.originalUrl してるのは後方互換性のため | ||||
| 			url.searchParams.set('emoji', '1'); | ||||
| 			if ('static' in request.query) url.searchParams.set('static', '1'); | ||||
|  | ||||
| 			return await reply.redirect( | ||||
| 				301, | ||||
| 				url.toString(), | ||||
| 			); | ||||
| 		}); | ||||
|  | ||||
| 		fastify.get<{ Params: { path: string } }>('/fluent-emoji/:path(.*)', async (request, reply) => { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 tamaina
					tamaina