mirror of
https://github.com/cupcakearmy/morphus.git
synced 2024-12-22 08:06:30 +00:00
also use accept header as source of auto format
This commit is contained in:
parent
6f3f9dd9d9
commit
3a80516401
@ -9,8 +9,9 @@ import {
|
|||||||
IsUrl,
|
IsUrl,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from 'class-validator'
|
} from 'class-validator'
|
||||||
import { RouteHandlerMethod } from 'fastify'
|
import type { RouteHandlerMethod } from 'fastify'
|
||||||
import { flatten, unflatten } from 'flat'
|
import { flatten, unflatten } from 'flat'
|
||||||
|
import type { IncomingHttpHeaders } from 'http2'
|
||||||
import ms from 'ms'
|
import ms from 'ms'
|
||||||
import sharp, { FitEnum, FormatEnum } from 'sharp'
|
import sharp, { FitEnum, FormatEnum } from 'sharp'
|
||||||
|
|
||||||
@ -116,7 +117,7 @@ export class TransformQueryBase {
|
|||||||
@ValidateNested()
|
@ValidateNested()
|
||||||
op: ComplexParameter[] = []
|
op: ComplexParameter[] = []
|
||||||
|
|
||||||
constructor(data: any, options: { ua?: string }) {
|
constructor(data: any, options: { headers: IncomingHttpHeaders }) {
|
||||||
Object.assign(this, data)
|
Object.assign(this, data)
|
||||||
|
|
||||||
if (this.width) this.width = parseInt(this.width as any)
|
if (this.width) this.width = parseInt(this.width as any)
|
||||||
@ -128,8 +129,9 @@ export class TransformQueryBase {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
this.format = new ComplexParameter((this.format as any) || 'auto')
|
this.format = new ComplexParameter((this.format as any) || 'auto')
|
||||||
if ((this.format.name as string) === 'auto') {
|
if ((this.format.name as string) === 'auto') {
|
||||||
if (!options.ua) throw new Error('cannot use auto format without user agent')
|
if (!options.headers) throw new Error('cannot use auto format without user agent')
|
||||||
this.autoFormat(options.ua)
|
|
||||||
|
this.autoFormat(options.headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
validateSyncOrFail(this)
|
validateSyncOrFail(this)
|
||||||
@ -157,10 +159,29 @@ export class TransformQueryBase {
|
|||||||
return new URLSearchParams(sortObjectByKeys(data)).toString()
|
return new URLSearchParams(sortObjectByKeys(data)).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
autoFormat(ua: string) {
|
autoFormat(headers: IncomingHttpHeaders) {
|
||||||
if (supportsAvif(ua)) this.format!.name = 'avif'
|
const ua = headers['user-agent']
|
||||||
else if (supportsWebP(ua)) this.format!.name = 'webp'
|
const accept = headers['accept'] // Accept: image/avif,image/webp,*/*
|
||||||
else this.format!.name = 'jpeg'
|
if (accept) {
|
||||||
|
const acceptTypes = accept.split(',')
|
||||||
|
for (const type of acceptTypes) {
|
||||||
|
if (type.startsWith('image/')) {
|
||||||
|
this.format!.name = type.split('/')[1] as any
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ua) {
|
||||||
|
if (supportsAvif(ua)) {
|
||||||
|
this.format!.name = 'avif'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (supportsWebP(ua)) {
|
||||||
|
this.format!.name = 'webp'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.format!.name = 'jpeg'
|
||||||
}
|
}
|
||||||
|
|
||||||
get hash(): string {
|
get hash(): string {
|
||||||
@ -170,7 +191,7 @@ export class TransformQueryBase {
|
|||||||
|
|
||||||
export const image: RouteHandlerMethod = async (request, reply) => {
|
export const image: RouteHandlerMethod = async (request, reply) => {
|
||||||
try {
|
try {
|
||||||
const q = new TransformQueryBase(request.query, { ua: request.headers['user-agent'] })
|
const q = new TransformQueryBase(request.query, { headers: request.headers })
|
||||||
|
|
||||||
if (Config.allowedDomains) {
|
if (Config.allowedDomains) {
|
||||||
if (!testForPrefixOrRegexp(q.url, Config.allowedDomains))
|
if (!testForPrefixOrRegexp(q.url, Config.allowedDomains))
|
||||||
@ -183,14 +204,17 @@ export const image: RouteHandlerMethod = async (request, reply) => {
|
|||||||
return ForbiddenError(reply, 'origin not allowed')
|
return ForbiddenError(reply, 'origin not allowed')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hash = q.hash
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
reply.etag(q.hash)
|
reply.etag(hash)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
reply.expires(new Date(Date.now() + ms(Config.maxAge)))
|
reply.expires(new Date(Date.now() + ms(Config.maxAge)))
|
||||||
|
|
||||||
let stream: NodeJS.ReadableStream
|
let stream: NodeJS.ReadableStream
|
||||||
|
App.log.debug('Serving image. Hash: ' + hash)
|
||||||
try {
|
try {
|
||||||
stream = await storage.readStream(q.hash)
|
stream = await storage.readStream(hash)
|
||||||
} catch {
|
} catch {
|
||||||
App.log.debug(`Transforming`)
|
App.log.debug(`Transforming`)
|
||||||
stream = await transform(q)
|
stream = await transform(q)
|
||||||
|
Loading…
Reference in New Issue
Block a user