Generate video thumbnails (#4084)
* Generate video thumbnails * import order
This commit is contained in:
parent
170b1bb4cc
commit
3040700005
@ -226,6 +226,7 @@
|
|||||||
"url-loader": "1.1.2",
|
"url-loader": "1.1.2",
|
||||||
"uuid": "3.3.2",
|
"uuid": "3.3.2",
|
||||||
"v-animate-css": "0.0.3",
|
"v-animate-css": "0.0.3",
|
||||||
|
"video-thumbnail-generator": "1.1.3",
|
||||||
"vue": "2.5.17",
|
"vue": "2.5.17",
|
||||||
"vue-color": "2.7.0",
|
"vue-color": "2.7.0",
|
||||||
"vue-content-loading": "1.5.3",
|
"vue-content-loading": "1.5.3",
|
||||||
|
@ -41,7 +41,7 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
imageStyle(): any {
|
imageStyle(): any {
|
||||||
return {
|
return {
|
||||||
'background-image': null // TODO `url(${this.video.thumbnailUrl})`
|
'background-image': `url(${this.video.thumbnailUrl})`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -35,7 +35,7 @@ export default Vue.extend({
|
|||||||
computed: {
|
computed: {
|
||||||
imageStyle(): any {
|
imageStyle(): any {
|
||||||
return {
|
return {
|
||||||
'background-image': null // TODO `url(${this.video.thumbnailUrl})`
|
'background-image': `url(${this.video.thumbnailUrl})`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ export default function(file: IDriveFile, thumbnail = false): string {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
return isImage ? `${config.drive_url}/${file._id}?thumbnail` : null;
|
return `${config.drive_url}/${file._id}?thumbnail`;
|
||||||
} else {
|
} else {
|
||||||
return `${config.drive_url}/${file._id}?web`;
|
return `${config.drive_url}/${file._id}?web`;
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,12 @@ export default async function(ctx: Koa.BaseContext) {
|
|||||||
const bucket = await getDriveFileThumbnailBucket();
|
const bucket = await getDriveFileThumbnailBucket();
|
||||||
ctx.body = bucket.openDownloadStream(thumb._id);
|
ctx.body = bucket.openDownloadStream(thumb._id);
|
||||||
} else {
|
} else {
|
||||||
|
if (file.contentType.startsWith('image/')) {
|
||||||
await sendRaw();
|
await sendRaw();
|
||||||
|
} else {
|
||||||
|
ctx.status = 404;
|
||||||
|
await send(ctx as any, '/dummy.png', { root: assets });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ('web' in ctx.query) {
|
} else if ('web' in ctx.query) {
|
||||||
const web = await DriveFileWebpublic.findOne({
|
const web = await DriveFileWebpublic.findOne({
|
||||||
|
@ -22,6 +22,7 @@ import { getDriveFileThumbnailBucket } from '../../models/drive-file-thumbnail';
|
|||||||
import driveChart from '../../chart/drive';
|
import driveChart from '../../chart/drive';
|
||||||
import perUserDriveChart from '../../chart/per-user-drive';
|
import perUserDriveChart from '../../chart/per-user-drive';
|
||||||
import fetchMeta from '../../misc/fetch-meta';
|
import fetchMeta from '../../misc/fetch-meta';
|
||||||
|
import { GenerateVideoThumbnail } from './generate-video-thumbnail';
|
||||||
|
|
||||||
const log = debug('misskey:drive:add-file');
|
const log = debug('misskey:drive:add-file');
|
||||||
|
|
||||||
@ -118,6 +119,14 @@ async function save(path: string, name: string, type: string, hash: string, size
|
|||||||
|
|
||||||
thumbnailExt = 'png';
|
thumbnailExt = 'png';
|
||||||
thumbnailType = 'image/png';
|
thumbnailType = 'image/png';
|
||||||
|
} else if (type.startsWith('video/')) {
|
||||||
|
try {
|
||||||
|
thumbnail = await GenerateVideoThumbnail(path);
|
||||||
|
thumbnailExt = 'png';
|
||||||
|
thumbnailType = 'image/png';
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`GenerateVideoThumbnail failed: ${e}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// #endregion thumbnail
|
// #endregion thumbnail
|
||||||
|
|
||||||
|
32
src/services/drive/generate-video-thumbnail.ts
Normal file
32
src/services/drive/generate-video-thumbnail.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import * as fs from 'fs';
|
||||||
|
import * as tmp from 'tmp';
|
||||||
|
const ThumbnailGenerator = require('video-thumbnail-generator').default;
|
||||||
|
|
||||||
|
export async function GenerateVideoThumbnail(path: string): Promise<Buffer> {
|
||||||
|
const [outDir, cleanup] = await new Promise<[string, any]>((res, rej) => {
|
||||||
|
tmp.dir((e, path, cleanup) => {
|
||||||
|
if (e) return rej(e);
|
||||||
|
res([path, cleanup]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const tg = new ThumbnailGenerator({
|
||||||
|
sourcePath: path,
|
||||||
|
thumbnailPath: outDir,
|
||||||
|
});
|
||||||
|
|
||||||
|
await tg.generateOneByPercent(10, {
|
||||||
|
size: '498x280',
|
||||||
|
filename: 'output.png',
|
||||||
|
});
|
||||||
|
|
||||||
|
const outPath = `${outDir}/output.png`;
|
||||||
|
|
||||||
|
const buffer = fs.readFileSync(outPath);
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
fs.unlinkSync(outPath);
|
||||||
|
cleanup();
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user