summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/FileServerService.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server/FileServerService.ts')
-rw-r--r--packages/backend/src/server/FileServerService.ts73
1 files changed, 45 insertions, 28 deletions
diff --git a/packages/backend/src/server/FileServerService.ts b/packages/backend/src/server/FileServerService.ts
index 40024270ae..39bc4c1d96 100644
--- a/packages/backend/src/server/FileServerService.ts
+++ b/packages/backend/src/server/FileServerService.ts
@@ -137,38 +137,38 @@ export class FileServerService {
try {
if (file.state === 'remote') {
- const convertFile = async () => {
- if (file.fileRole === 'thumbnail') {
- if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(file.mime)) {
- return this.imageProcessingService.convertToWebpStream(
- file.path,
- 498,
- 280
- );
- } else if (file.mime.startsWith('video/')) {
- return await this.videoProcessingService.generateVideoThumbnail(file.path);
- }
+ let image: IImageStreamable | null = null;
+
+ if (file.fileRole === 'thumbnail') {
+ if (isMimeImage(file.mime, 'sharp-convertible-image')) {
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+
+ const url = new URL(`${this.config.mediaProxy}/static.webp`);
+ url.searchParams.set('url', file.url);
+ url.searchParams.set('static', '1');
+ return await reply.redirect(301, url.toString());
+ } else if (file.mime.startsWith('video/')) {
+ image = await this.videoProcessingService.generateVideoThumbnail(file.path);
}
+ }
- if (file.fileRole === 'webpublic') {
- if (['image/svg+xml'].includes(file.mime)) {
- return this.imageProcessingService.convertToWebpStream(
- file.path,
- 2048,
- 2048,
- { ...webpDefault, lossless: true }
- )
- }
+ if (file.fileRole === 'webpublic') {
+ if (['image/svg+xml'].includes(file.mime)) {
+ reply.header('Cache-Control', 'max-age=31536000, immutable');
+
+ const url = new URL(`${this.config.mediaProxy}/svg.webp`);
+ url.searchParams.set('url', file.url);
+ return await reply.redirect(301, url.toString());
}
+ }
- return {
+ if (!image) {
+ image = {
data: fs.createReadStream(file.path),
ext: file.ext,
type: file.mime,
};
- };
-
- const image = await convertFile();
+ }
if ('pipe' in image.data && typeof image.data.pipe === 'function') {
// image.dataがstreamなら、stream終了後にcleanup
@@ -180,7 +180,6 @@ export class FileServerService {
}
reply.header('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
- reply.header('Cache-Control', 'max-age=31536000, immutable');
return image.data;
}
@@ -217,6 +216,23 @@ export class FileServerService {
return;
}
+ if (this.config.externalMediaProxyEnabled) {
+ // 外部のメディアプロキシが有効なら、そちらにリダイレクト
+
+ reply.header('Cache-Control', 'public, max-age=259200'); // 3 days
+
+ const url = new URL(`${this.config.mediaProxy}/${request.params.url || ''}`);
+
+ for (const [key, value] of Object.entries(request.query)) {
+ url.searchParams.append(key, value);
+ }
+
+ return await reply.redirect(
+ 301,
+ url.toString(),
+ );
+ }
+
// Create temp file
const file = await this.getStreamAndTypeFromUrl(url);
if (file === '404') {
@@ -236,7 +252,7 @@ export class FileServerService {
const isAnimationConvertibleImage = isMimeImage(file.mime, 'sharp-animation-convertible-image');
let image: IImageStreamable | null = null;
- if ('emoji' in request.query && isConvertibleImage) {
+ if (('emoji' in request.query || 'avatar' in request.query) && isConvertibleImage) {
if (!isAnimationConvertibleImage && !('static' in request.query)) {
image = {
data: fs.createReadStream(file.path),
@@ -246,7 +262,7 @@ export class FileServerService {
} else {
const data = sharp(file.path, { animated: !('static' in request.query) })
.resize({
- height: 128,
+ height: 'emoji' in request.query ? 128 : 320,
withoutEnlargement: true,
})
.webp(webpDefault);
@@ -370,7 +386,7 @@ export class FileServerService {
@bindThis
private async getFileFromKey(key: string): Promise<
- { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; cleanup: () => void; }
+ { state: 'remote'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; url: string; mime: string; ext: string | null; path: string; cleanup: () => void; }
| { state: 'stored_internal'; fileRole: 'thumbnail' | 'webpublic' | 'original'; file: DriveFile; mime: string; ext: string | null; path: string; }
| '404'
| '204'
@@ -392,6 +408,7 @@ export class FileServerService {
const result = await this.downloadAndDetectTypeFromUrl(file.uri);
return {
...result,
+ url: file.uri,
fileRole: isThumbnail ? 'thumbnail' : isWebpublic ? 'webpublic' : 'original',
file,
}