サムネイルを予め生成するように

This commit is contained in:
syuilo
2018-05-03 20:03:14 +09:00
parent 75764e59e1
commit 15e4cf1243
9 changed files with 182 additions and 107 deletions

View File

@ -6,7 +6,6 @@ import * as fs from 'fs';
import * as Koa from 'koa';
import * as cors from '@koa/cors';
import * as Router from 'koa-router';
import pour from './pour';
import sendDriveFile from './send-drive-file';
// Init app
@ -24,12 +23,14 @@ const router = new Router();
router.get('/default-avatar.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/avatar.jpg`);
pour(file, 'image/jpeg', ctx);
ctx.set('Content-Type', 'image/jpeg');
ctx.body = file;
});
router.get('/app-default.jpg', ctx => {
const file = fs.createReadStream(`${__dirname}/assets/dummy.png`);
pour(file, 'image/png', ctx);
ctx.set('Content-Type', 'image/jpeg');
ctx.body = file;
});
router.get('/:id', sendDriveFile);

View File

@ -1,88 +0,0 @@
import * as fs from 'fs';
import * as stream from 'stream';
import * as Koa from 'koa';
import * as Gm from 'gm';
const gm = Gm.subClass({
imageMagick: true
});
interface ISend {
contentType: string;
stream: stream.Readable;
}
function thumbnail(data: stream.Readable, type: string, resize: number): ISend {
const readable: stream.Readable = (() => {
// 動画であれば
if (/^video\/.*$/.test(type)) {
// TODO
// 使わないことになったストリームはしっかり取り壊す
data.destroy();
return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
// 画像であれば
// Note: SVGはapplication/xml
} else if (/^image\/.*$/.test(type) || type == 'application/xml') {
// 0フレーム目を送る
try {
return gm(data).selectFrame(0).stream();
// だめだったら
} catch (e) {
// 使わないことになったストリームはしっかり取り壊す
data.destroy();
return fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
}
// 動画か画像以外
} else {
data.destroy();
return fs.createReadStream(`${__dirname}/assets/not-an-image.png`);
}
})();
let g = gm(readable);
if (resize) {
g = g.resize(resize, resize);
}
const stream = g
.compress('jpeg')
.quality(80)
.interlace('line')
.stream();
return {
contentType: 'image/jpeg',
stream
};
}
const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => {
console.error(e);
ctx.status = 500;
};
export default function(readable: stream.Readable, type: string, ctx: Koa.Context): void {
readable.on('error', commonReadableHandlerGenerator(ctx));
const data = ((): ISend => {
if (ctx.query.thumbnail !== undefined) {
return thumbnail(readable, type, ctx.query.size);
}
return {
contentType: type,
stream: readable
};
})();
if (readable !== data.stream) {
data.stream.on('error', commonReadableHandlerGenerator(ctx));
}
if (ctx.query.download !== undefined) {
ctx.set('Content-Disposition', 'attachment');
}
ctx.set('Content-Type', data.contentType);
ctx.body = data.stream;
}

View File

@ -1,8 +1,15 @@
import * as fs from 'fs';
import * as Koa from 'koa';
import * as send from 'koa-send';
import * as mongodb from 'mongodb';
import DriveFile, { getGridFSBucket } from '../../models/drive-file';
import pour from './pour';
import DriveFile, { getDriveFileBucket } from '../../models/drive-file';
import DriveFileThumbnail, { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void => {
console.error(e);
ctx.status = 500;
};
export default async function(ctx: Koa.Context) {
// Validate id
@ -28,9 +35,33 @@ export default async function(ctx: Koa.Context) {
return;
}
const bucket = await getGridFSBucket();
if ('thumbnail' in ctx.query) {
// 動画か画像以外
if (!/^image\/.*$/.test(file.contentType) && !/^video\/.*$/.test(file.contentType)) {
const readable = fs.createReadStream(`${__dirname}/assets/thumbnail-not-available.png`);
ctx.set('Content-Type', 'image/png');
ctx.body = readable;
} else {
const thumb = await DriveFileThumbnail.findOne({ 'metadata.originalId': fileId });
if (thumb != null) {
ctx.set('Content-Type', 'image/jpeg');
const bucket = await getDriveFileThumbnailBucket();
ctx.body = bucket.openDownloadStream(thumb._id);
} else {
ctx.set('Content-Type', file.contentType);
const bucket = await getDriveFileBucket();
ctx.body = bucket.openDownloadStream(fileId);
}
}
} else {
if ('download' in ctx.query) {
ctx.set('Content-Disposition', 'attachment');
}
const readable = bucket.openDownloadStream(fileId);
pour(readable, file.contentType, ctx);
const bucket = await getDriveFileBucket();
const readable = bucket.openDownloadStream(fileId);
readable.on('error', commonReadableHandlerGenerator(ctx));
ctx.set('Content-Type', file.contentType);
ctx.body = readable;
}
}