parent
85b7eb1fb8
commit
e37840d870
5 changed files with 37 additions and 29 deletions
|
@ -42,7 +42,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
previewable(file) {
|
previewable(file) {
|
||||||
return file.type.startsWith('video') || file.type.startsWith('image');
|
return (file.type.startsWith('video') || file.type.startsWith('image')) && file.thumbnailUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { DriveFiles } from '../../models';
|
||||||
import { InternalStorage } from '../../services/drive/internal-storage';
|
import { InternalStorage } from '../../services/drive/internal-storage';
|
||||||
import { downloadUrl } from '../../misc/donwload-url';
|
import { downloadUrl } from '../../misc/donwload-url';
|
||||||
import { detectMine } from '../../misc/detect-mine';
|
import { detectMine } from '../../misc/detect-mine';
|
||||||
import { convertToJpeg, convertToPng, convertToGif, convertToApng } from '../../services/drive/image-processor';
|
import { convertToJpeg, convertToPng } from '../../services/drive/image-processor';
|
||||||
import { GenerateVideoThumbnail } from '../../services/drive/generate-video-thumbnail';
|
import { GenerateVideoThumbnail } from '../../services/drive/generate-video-thumbnail';
|
||||||
|
|
||||||
const assets = `${__dirname}/../../server/file/assets/`;
|
const assets = `${__dirname}/../../server/file/assets/`;
|
||||||
|
@ -60,10 +60,6 @@ export default async function(ctx: Koa.Context) {
|
||||||
return await convertToJpeg(path, 498, 280);
|
return await convertToJpeg(path, 498, 280);
|
||||||
} else if (['image/png'].includes(type)) {
|
} else if (['image/png'].includes(type)) {
|
||||||
return await convertToPng(path, 498, 280);
|
return await convertToPng(path, 498, 280);
|
||||||
} else if (['image/gif'].includes(type)) {
|
|
||||||
return await convertToGif(path);
|
|
||||||
} else if (['image/apng', 'image/vnd.mozilla.apng'].includes(type)) {
|
|
||||||
return await convertToApng(path);
|
|
||||||
} else if (type.startsWith('video/')) {
|
} else if (type.startsWith('video/')) {
|
||||||
return await GenerateVideoThumbnail(path);
|
return await GenerateVideoThumbnail(path);
|
||||||
}
|
}
|
||||||
|
@ -101,22 +97,23 @@ export default async function(ctx: Koa.Context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isThumbnail) {
|
if (isThumbnail || isWebpublic) {
|
||||||
|
const [mime, ext] = await detectMine(InternalStorage.resolvePath(key));
|
||||||
|
const filename = rename(file.name, {
|
||||||
|
suffix: isThumbnail ? '-thumb' : '-web',
|
||||||
|
extname: ext ? `.${ext}` : undefined
|
||||||
|
}).toString();
|
||||||
|
|
||||||
ctx.body = InternalStorage.read(key);
|
ctx.body = InternalStorage.read(key);
|
||||||
ctx.set('Content-Type', 'image/jpeg');
|
ctx.set('Content-Type', mime);
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
||||||
ctx.set('Content-Disposition', contentDisposition('inline', `${rename(file.name, { suffix: '-thumb', extname: '.jpeg' })}`));
|
ctx.set('Content-Disposition', contentDisposition('inline', filename));
|
||||||
} else if (isWebpublic) {
|
|
||||||
ctx.body = InternalStorage.read(key);
|
|
||||||
ctx.set('Content-Type', file.type === 'image/apng' ? 'image/png' : file.type);
|
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
|
||||||
ctx.set('Content-Disposition', contentDisposition('inline', `${rename(file.name, { suffix: '-web' })}`));
|
|
||||||
} else {
|
} else {
|
||||||
const readable = InternalStorage.read(file.accessKey!);
|
const readable = InternalStorage.read(file.accessKey!);
|
||||||
readable.on('error', commonReadableHandlerGenerator(ctx));
|
readable.on('error', commonReadableHandlerGenerator(ctx));
|
||||||
ctx.body = readable;
|
ctx.body = readable;
|
||||||
ctx.set('Content-Type', file.type);
|
ctx.set('Content-Type', file.type);
|
||||||
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
ctx.set('Cache-Control', 'max-age=31536000, immutable');
|
||||||
ctx.set('Content-Disposition', contentDisposition('inline', `${file.name}`));
|
ctx.set('Content-Disposition', contentDisposition('inline', file.name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,8 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
|
||||||
webpublic = await convertToWebp(path, 2048, 2048);
|
webpublic = await convertToWebp(path, 2048, 2048);
|
||||||
} else if (['image/png'].includes(type)) {
|
} else if (['image/png'].includes(type)) {
|
||||||
webpublic = await convertToPng(path, 2048, 2048);
|
webpublic = await convertToPng(path, 2048, 2048);
|
||||||
|
} else {
|
||||||
|
logger.debug(`web image not created (not an required image)`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(`web image not created (an error occured)`, e);
|
logger.warn(`web image not created (an error occured)`, e);
|
||||||
|
@ -180,8 +182,10 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
|
||||||
try {
|
try {
|
||||||
thumbnail = await GenerateVideoThumbnail(path);
|
thumbnail = await GenerateVideoThumbnail(path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`GenerateVideoThumbnail failed: ${e}`);
|
logger.warn(`GenerateVideoThumbnail failed: ${e}`);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug(`thumbnail not created (not an required file)`);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(`thumbnail not created (an error occured)`, e);
|
logger.warn(`thumbnail not created (an error occured)`, e);
|
||||||
|
@ -351,7 +355,7 @@ export default async function(
|
||||||
|
|
||||||
let propPromises: Promise<void>[] = [];
|
let propPromises: Promise<void>[] = [];
|
||||||
|
|
||||||
const isImage = ['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp'].includes(mime);
|
const isImage = ['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/svg+xml'].includes(mime);
|
||||||
|
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
const img = sharp(path);
|
const img = sharp(path);
|
||||||
|
@ -374,15 +378,21 @@ export default async function(
|
||||||
logger.debug('calculating average color...');
|
logger.debug('calculating average color...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const info = await (img as any).stats();
|
const info = await img.stats();
|
||||||
|
|
||||||
const r = Math.round(info.channels[0].mean);
|
if (info.isOpaque) {
|
||||||
const g = Math.round(info.channels[1].mean);
|
const r = Math.round(info.channels[0].mean);
|
||||||
const b = Math.round(info.channels[2].mean);
|
const g = Math.round(info.channels[1].mean);
|
||||||
|
const b = Math.round(info.channels[2].mean);
|
||||||
|
|
||||||
logger.debug(`average color is calculated: ${r}, ${g}, ${b}`);
|
logger.debug(`average color is calculated: ${r}, ${g}, ${b}`);
|
||||||
|
|
||||||
properties['avgColor'] = `rgb(${r},${g},${b})`;
|
properties['avgColor'] = `rgb(${r},${g},${b})`;
|
||||||
|
} else {
|
||||||
|
logger.debug(`this image is not opaque so average color is 255, 255, 255`);
|
||||||
|
|
||||||
|
properties['avgColor'] = `rgb(255,255,255)`;
|
||||||
|
}
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as sharp from 'sharp';
|
import * as sharp from 'sharp';
|
||||||
import * as fs from 'fs';
|
|
||||||
|
|
||||||
export type IImage = {
|
export type IImage = {
|
||||||
data: Buffer;
|
data: Buffer;
|
||||||
|
|
|
@ -3,25 +3,27 @@ import * as Path from 'path';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
|
||||||
export class InternalStorage {
|
export class InternalStorage {
|
||||||
private static readonly path = Path.resolve(`${__dirname}/../../../files`);
|
private static readonly path = Path.resolve(__dirname, '../../../files');
|
||||||
|
|
||||||
|
public static resolvePath = (key: string) => Path.resolve(InternalStorage.path, key);
|
||||||
|
|
||||||
public static read(key: string) {
|
public static read(key: string) {
|
||||||
return fs.createReadStream(`${InternalStorage.path}/${key}`);
|
return fs.createReadStream(InternalStorage.resolvePath(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static saveFromPath(key: string, srcPath: string) {
|
public static saveFromPath(key: string, srcPath: string) {
|
||||||
fs.mkdirSync(InternalStorage.path, { recursive: true });
|
fs.mkdirSync(InternalStorage.path, { recursive: true });
|
||||||
fs.copyFileSync(srcPath, `${InternalStorage.path}/${key}`);
|
fs.copyFileSync(srcPath, InternalStorage.resolvePath(key));
|
||||||
return `${config.url}/files/${key}`;
|
return `${config.url}/files/${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static saveFromBuffer(key: string, data: Buffer) {
|
public static saveFromBuffer(key: string, data: Buffer) {
|
||||||
fs.mkdirSync(InternalStorage.path, { recursive: true });
|
fs.mkdirSync(InternalStorage.path, { recursive: true });
|
||||||
fs.writeFileSync(`${InternalStorage.path}/${key}`, data);
|
fs.writeFileSync(InternalStorage.resolvePath(key), data);
|
||||||
return `${config.url}/files/${key}`;
|
return `${config.url}/files/${key}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static del(key: string) {
|
public static del(key: string) {
|
||||||
fs.unlink(`${InternalStorage.path}/${key}`, () => {});
|
fs.unlink(InternalStorage.resolvePath(key), () => {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue