Generating thumbnails. Added site overview page.
This commit is contained in:
137
src/media.js
Normal file
137
src/media.js
Normal file
@@ -0,0 +1,137 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('config');
|
||||
const Promise = require('bluebird');
|
||||
const path = require('path');
|
||||
const fs = require('fs-extra');
|
||||
const bhttp = require('bhttp');
|
||||
const mime = require('mime');
|
||||
const sharp = require('sharp');
|
||||
const blake2 = require('blake2');
|
||||
|
||||
const knex = require('./knex');
|
||||
|
||||
function getHash(buffer) {
|
||||
const hash = blake2.createHash('blake2b', { digestLength: 24 });
|
||||
|
||||
hash.update(buffer);
|
||||
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
async function storePoster(release, releaseEntry) {
|
||||
console.log(`Storing poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
|
||||
|
||||
const res = await bhttp.get(release.poster);
|
||||
const thumbnail = await sharp(res.body)
|
||||
.resize({ width: Math.floor((config.media.thumbnailSize / 9) * 16), height: config.media.thumbnailSize }) // ensure thumbnail is 16:9
|
||||
.toBuffer();
|
||||
|
||||
if (res.statusCode === 200) {
|
||||
const { pathname } = new URL(release.poster);
|
||||
const mimetype = res.headers['content-type'] || mime.getType(pathname) || 'image/jpeg';
|
||||
const extension = mime.getExtension(mimetype);
|
||||
|
||||
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `poster.${extension}`);
|
||||
const thumbpath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `poster_thumb.${extension}`);
|
||||
const hash = getHash(res.body);
|
||||
|
||||
await Promise.all([
|
||||
fs.writeFile(path.join(config.media.path, filepath), res.body),
|
||||
fs.writeFile(path.join(config.media.path, thumbpath), thumbnail),
|
||||
]);
|
||||
|
||||
await knex('media').insert({
|
||||
path: filepath,
|
||||
thumbnail: thumbpath,
|
||||
mime: mimetype,
|
||||
hash,
|
||||
domain: 'releases',
|
||||
target_id: releaseEntry.id,
|
||||
role: 'poster',
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
console.warn(`Failed to store poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
|
||||
}
|
||||
|
||||
async function storePhotos(release, releaseEntry) {
|
||||
console.log(`Storing ${release.photos.length} photos for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
|
||||
|
||||
const files = await Promise.map(release.photos, async (photoUrl, index) => {
|
||||
const { pathname } = new URL(photoUrl);
|
||||
const mimetype = mime.getType(pathname);
|
||||
|
||||
const res = await bhttp.get(photoUrl);
|
||||
const thumbnail = await sharp(res.body).resize({ height: config.media.thumbnailSize }).toBuffer();
|
||||
|
||||
if (res.statusCode === 200) {
|
||||
const extension = mime.getExtension(mimetype);
|
||||
|
||||
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `${index + 1}.${extension}`);
|
||||
const thumbpath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `${index + 1}_thumb.${extension}`);
|
||||
const hash = getHash(res.body);
|
||||
|
||||
await Promise.all([
|
||||
fs.writeFile(path.join(config.media.path, filepath), res.body),
|
||||
fs.writeFile(path.join(config.media.path, thumbpath), thumbnail),
|
||||
]);
|
||||
|
||||
return {
|
||||
filepath,
|
||||
thumbpath,
|
||||
mimetype,
|
||||
hash,
|
||||
};
|
||||
}
|
||||
|
||||
console.warn(`Failed to store photo ${index + 1} for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
|
||||
|
||||
return null;
|
||||
}, {
|
||||
concurrency: 2,
|
||||
});
|
||||
|
||||
await knex('media')
|
||||
.insert(files.filter(file => file)
|
||||
.map((file, index) => ({
|
||||
path: file.filepath,
|
||||
thumbnail: file.thumbpath,
|
||||
mime: file.mimetype,
|
||||
hash: file.hash,
|
||||
index,
|
||||
domain: 'releases',
|
||||
target_id: releaseEntry.id,
|
||||
role: 'photo',
|
||||
})));
|
||||
}
|
||||
|
||||
async function storeTrailer(release, releaseEntry) {
|
||||
console.log(`Storing trailer for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
|
||||
|
||||
const { pathname } = new URL(release.trailer.src);
|
||||
const mimetype = release.trailer.type || mime.getType(pathname);
|
||||
|
||||
const res = await bhttp.get(release.trailer.src);
|
||||
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `trailer${release.trailer.quality ? `_${release.trailer.quality}` : ''}.${mime.getExtension(mimetype)}`);
|
||||
|
||||
await Promise.all([
|
||||
fs.writeFile(path.join(config.media.path, filepath), res.body),
|
||||
knex('media').insert({
|
||||
path: filepath,
|
||||
mime: mimetype,
|
||||
domain: 'releases',
|
||||
target_id: releaseEntry.id,
|
||||
role: 'trailer',
|
||||
quality: release.trailer.quality || null,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
storePoster,
|
||||
storePhotos,
|
||||
storeTrailer,
|
||||
};
|
||||
Reference in New Issue
Block a user