summaryrefslogtreecommitdiff
path: root/packages/backend/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'packages/backend/src/server')
-rw-r--r--packages/backend/src/server/FileServerService.ts73
-rw-r--r--packages/backend/src/server/ServerService.ts2
-rw-r--r--packages/backend/src/server/api/endpoints/meta.ts6
-rw-r--r--packages/backend/src/server/web/UrlPreviewService.ts2
4 files changed, 53 insertions, 30 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,
}
diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts
index beb3a34ecd..c7a2c99f94 100644
--- a/packages/backend/src/server/ServerService.ts
+++ b/packages/backend/src/server/ServerService.ts
@@ -106,7 +106,7 @@ export class ServerService {
}
}
- const url = new URL('/proxy/emoji.webp', this.config.url);
+ const url = new URL(`${this.config.mediaProxy}/emoji.webp`);
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
url.searchParams.set('emoji', '1');
diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts
index 3baf945323..2fa7a09d49 100644
--- a/packages/backend/src/server/api/endpoints/meta.ts
+++ b/packages/backend/src/server/api/endpoints/meta.ts
@@ -181,6 +181,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
+ mediaProxy: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
features: {
type: 'object',
optional: true, nullable: false,
@@ -307,6 +311,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
policies: { ...DEFAULT_POLICIES, ...instance.policies },
+ mediaProxy: this.config.mediaProxy,
+
...(ps.detail ? {
pinnedPages: instance.pinnedPages,
pinnedClipId: instance.pinnedClipId,
diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts
index 802b404ce6..1bf88fe434 100644
--- a/packages/backend/src/server/web/UrlPreviewService.ts
+++ b/packages/backend/src/server/web/UrlPreviewService.ts
@@ -33,7 +33,7 @@ export class UrlPreviewService {
private wrap(url?: string): string | null {
return url != null
? url.match(/^https?:\/\//)
- ? `${this.config.url}/proxy/preview.webp?${query({
+ ? `${this.config.mediaProxy}/preview.webp?${query({
url,
preview: '1',
})}`