audio thumbnails

merge-requests/208/head
some random guy 4 years ago
parent 2adff07989
commit da8522faec
  1. 5
      configs/main.js.example
  2. 13
      gulp/res/js/expand.js
  3. 22
      helpers/files/audiothumbnail.js
  4. 30
      models/forms/makepost.js
  5. 4
      views/mixins/catalogtile.pug
  6. 4
      views/mixins/post.pug

@ -58,7 +58,7 @@ module.exports = {
distortion: 9, distortion: 9,
}, },
/* dnsbl, will add a small delay for uncached requests. You could also install some /* dnsbl, will add a small delay for uncached requests. You could also install some
kind of dns cache e.g. unbound to improve performance. DNSBL only checked for posting */ kind of dns cache e.g. unbound to improve performance. DNSBL only checked for posting */
dnsbl: { dnsbl: {
enabled: false, enabled: false,
@ -127,6 +127,9 @@ module.exports = {
//if animatedGifThumbnails is true, use ffmpeg for better animated gif thumbnailing. RECOMMENDED //if animatedGifThumbnails is true, use ffmpeg for better animated gif thumbnailing. RECOMMENDED
ffmpegGifThumbnails: true, ffmpegGifThumbnails: true,
//generate waveform thumbnails for audio
audioThumbnails: false,
//max thumb dimensions (square) in px //max thumb dimensions (square) in px
thumbSize: 250, thumbSize: 250,

@ -165,8 +165,17 @@ window.addEventListener('DOMContentLoaded', (event) => {
expandedElement.controls = 'true'; expandedElement.controls = 'true';
source = document.createElement('source'); source = document.createElement('source');
expandedElement.appendChild(source); expandedElement.appendChild(source);
expandedElement.style.minWidth = fileAnchor.offsetWidth+'px'; console.log(this);
expandedElement.style.minHeight = fileAnchor.offsetHeight+'px'; if (type === 'audio' && thumbElement.nodeName === 'IMG') {
expandedElement.style.backgroundImage =
`url("${encodeURI(thumbElement.src)}")`;
expandedElement.style.backgroundRepeat = 'no-repeat';
expandedElement.style.minWidth = thumbElement.width+'px';
expandedElement.style.minHeight = thumbElement.height+'px';
} else {
expandedElement.style.minWidth = fileAnchor.offsetWidth+'px';
expandedElement.style.minHeight = fileAnchor.offsetHeight+'px';
}
pfs.appendChild(expandedElement); pfs.appendChild(expandedElement);
fileAnchor.appendChild(closeSpan); fileAnchor.appendChild(closeSpan);
toggle(thumbElement, expandedElement, fileName, pfs); toggle(thumbElement, expandedElement, fileName, pfs);

@ -0,0 +1,22 @@
const ffmpeg = require('fluent-ffmpeg')
, { thumbSize } = require(__dirname+'/../../configs/main.js')
, uploadDirectory = require(__dirname+'/uploadDirectory.js');
module.exports = (file) => {
return new Promise((resolve, reject) => {
ffmpeg(`${uploadDirectory}/file/${file.filename}`)
.on('end', () => {
return resolve();
})
.on('error', function(err, stdout, stderr) {
return reject(err);
})
.complexFilter([{
filter: 'showwavespic',
options: { split_channels: 1, s: `${thumbSize}x${thumbSize}` }
}])
.save(`${uploadDirectory}/file/thumb-${file.hash}${file.thumbextension}`);
});
};

@ -17,6 +17,7 @@ const path = require('path')
, imageThumbnail = require(__dirname+'/../../helpers/files/imagethumbnail.js') , imageThumbnail = require(__dirname+'/../../helpers/files/imagethumbnail.js')
, imageIdentify = require(__dirname+'/../../helpers/files/imageidentify.js') , imageIdentify = require(__dirname+'/../../helpers/files/imageidentify.js')
, videoThumbnail = require(__dirname+'/../../helpers/files/videothumbnail.js') , videoThumbnail = require(__dirname+'/../../helpers/files/videothumbnail.js')
, audioThumbnail = require(__dirname+'/../../helpers/files/audiothumbnail.js')
, ffprobe = require(__dirname+'/../../helpers/files/ffprobe.js') , ffprobe = require(__dirname+'/../../helpers/files/ffprobe.js')
, formatSize = require(__dirname+'/../../helpers/files/formatsize.js') , formatSize = require(__dirname+'/../../helpers/files/formatsize.js')
, deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js') , deleteTempFiles = require(__dirname+'/../../helpers/files/deletetempfiles.js')
@ -25,7 +26,8 @@ const path = require('path')
, deletePosts = require(__dirname+'/deletepost.js') , deletePosts = require(__dirname+'/deletepost.js')
, spamCheck = require(__dirname+'/../../helpers/checks/spamcheck.js') , spamCheck = require(__dirname+'/../../helpers/checks/spamcheck.js')
, { checkRealMimeTypes, thumbSize, thumbExtension, videoThumbPercentage, , { checkRealMimeTypes, thumbSize, thumbExtension, videoThumbPercentage,
postPasswordSecret, strictFiltering, animatedGifThumbnails } = require(__dirname+'/../../configs/main.js') postPasswordSecret, strictFiltering, animatedGifThumbnails,
audioThumbnails } = require(__dirname+'/../../configs/main.js')
, buildQueue = require(__dirname+'/../../queue.js') , buildQueue = require(__dirname+'/../../queue.js')
, dynamicResponse = require(__dirname+'/../../helpers/dynamic.js') , dynamicResponse = require(__dirname+'/../../helpers/dynamic.js')
, { buildThread } = require(__dirname+'/../../helpers/tasks.js'); , { buildThread } = require(__dirname+'/../../helpers/tasks.js');
@ -239,12 +241,11 @@ module.exports = async (req, res, next) => {
//type and subtype //type and subtype
const [type, subtype] = processedFile.mimetype.split('/'); const [type, subtype] = processedFile.mimetype.split('/');
if (type !== 'audio') { //audio doesnt need thumb
processedFile.thumbextension = thumbExtension;
}
let imageData; let imageData;
let firstFrameOnly = true; let firstFrameOnly = true;
if (type === 'image') { if (type === 'image') {
processedFile.thumbextension = thumbExtension;
///detect images with opacity for PNG thumbnails, set thumbextension before increment ///detect images with opacity for PNG thumbnails, set thumbextension before increment
try { try {
imageData = await imageIdentify(req.files.file[i].tempFilePath, null, true); imageData = await imageIdentify(req.files.file[i].tempFilePath, null, true);
@ -278,6 +279,13 @@ module.exports = async (req, res, next) => {
firstFrameOnly = false; firstFrameOnly = false;
processedFile.thumbextension = '.gif'; processedFile.thumbextension = '.gif';
} }
} else if (type === 'audio') {
if (audioThumbnails) {
// waveform has a transparent background, so force png
processedFile.thumbextension = '.png';
}
} else {
processedFile.thumbextension = thumbExtension;
} }
//increment file count //increment file count
@ -295,9 +303,9 @@ module.exports = async (req, res, next) => {
await moveUpload(file, processedFile.filename, 'file'); await moveUpload(file, processedFile.filename, 'file');
} }
} else { } else {
const existsThumb = await pathExists(`${uploadDirectory}/file/thumb-${processedFile.hash}${processedFile.thumbextension}`);
switch (type) { switch (type) {
case 'image': { case 'image': {
const existsThumb = await pathExists(`${uploadDirectory}/file/thumb-${processedFile.hash}${processedFile.thumbextension}`);
if (!existsFull) { if (!existsFull) {
await moveUpload(file, processedFile.filename, 'file'); await moveUpload(file, processedFile.filename, 'file');
} }
@ -308,7 +316,6 @@ module.exports = async (req, res, next) => {
break; break;
} }
case 'video': { case 'video': {
const existsThumb = await pathExists(`${uploadDirectory}/file/thumb-${processedFile.hash}${processedFile.thumbextension}`);
//video metadata //video metadata
const videoData = await ffprobe(req.files.file[i].tempFilePath, null, true); const videoData = await ffprobe(req.files.file[i].tempFilePath, null, true);
videoData.streams = videoData.streams.filter(stream => stream.width != null); //filter to only video streams or something with a resolution videoData.streams = videoData.streams.filter(stream => stream.width != null); //filter to only video streams or something with a resolution
@ -351,10 +358,17 @@ module.exports = async (req, res, next) => {
const audioData = await ffprobe(req.files.file[i].tempFilePath, null, true); const audioData = await ffprobe(req.files.file[i].tempFilePath, null, true);
processedFile.duration = audioData.format.duration; processedFile.duration = audioData.format.duration;
processedFile.durationString = timeUtils.durationString(audioData.format.duration*1000); processedFile.durationString = timeUtils.durationString(audioData.format.duration*1000);
processedFile.hasThumb = false; processedFile.hasThumb = audioThumbnails;
if (!existsFull) { if (!existsFull) {
await moveUpload(file, processedFile.filename, 'file'); await moveUpload(file, processedFile.filename, 'file');
} }
if (audioThumbnails && !existsThumb) {
await audioThumbnail(processedFile);
// audio thumbnail is always thumbSize x thumbSize
processedFile.geometry = {
thumbWidth: thumbSize, thumbHeight: thumbSize,
};
}
break; break;
} }
default: default:
@ -362,7 +376,7 @@ module.exports = async (req, res, next) => {
} }
} }
if (processedFile.hasThumb === true) { if (processedFile.hasThumb === true && type !== 'audio') {
if (processedFile.geometry.width < thumbSize && processedFile.geometry.height < thumbSize) { if (processedFile.geometry.width < thumbSize && processedFile.geometry.height < thumbSize) {
//dont scale up thumbnail for smaller images //dont scale up thumbnail for smaller images
processedFile.geometry.thumbwidth = processedFile.geometry.width; processedFile.geometry.thumbwidth = processedFile.geometry.width;

@ -28,12 +28,12 @@ mixin catalogtile(board, post, index)
- const file = post.files[0] - const file = post.files[0]
if post.spoiler || file.spoiler if post.spoiler || file.spoiler
div.spoilerimg.catalog-thumb div.spoilerimg.catalog-thumb
else if file.hasThumb
img.catalog-thumb(src=`/file/thumb-${file.hash}${file.thumbextension}` width=file.geometry.thumbwidth height=file.geometry.thumbheight loading='lazy')
else if file.attachment else if file.attachment
div.attachmentimg.catalog-thumb div.attachmentimg.catalog-thumb
else if file.mimetype.startsWith('audio') else if file.mimetype.startsWith('audio')
div.audioimg.catalog-thumb div.audioimg.catalog-thumb
else if file.hasThumb
img.catalog-thumb(src=`/file/thumb-${file.hash}${file.thumbextension}` width=file.geometry.thumbwidth height=file.geometry.thumbheight loading='lazy')
else else
img.catalog-thumb(src=`/file/${file.filename}` width=file.geometry.width height=file.geometry.height loading='lazy') img.catalog-thumb(src=`/file/${file.filename}` width=file.geometry.width height=file.geometry.height loading='lazy')
if post.message if post.message

@ -83,12 +83,12 @@ mixin post(post, truncate, manage=false, globalmanage=false, ban=false)
a(target='_blank' href=`/file/${file.filename}`) a(target='_blank' href=`/file/${file.filename}`)
if post.spoiler || file.spoiler if post.spoiler || file.spoiler
div.spoilerimg.file-thumb div.spoilerimg.file-thumb
else if file.hasThumb
img.file-thumb(src=`/file/thumb-${file.hash}${file.thumbextension}` height=file.geometry.thumbheight width=file.geometry.thumbwidth loading='lazy')
else if file.attachment else if file.attachment
div.attachmentimg.file-thumb div.attachmentimg.file-thumb
else if type === 'audio' else if type === 'audio'
div.audioimg.file-thumb div.audioimg.file-thumb
else if file.hasThumb
img.file-thumb(src=`/file/thumb-${file.hash}${file.thumbextension}` height=file.geometry.thumbheight width=file.geometry.thumbwidth loading='lazy')
else else
img.file-thumb(src=`/file/${file.filename}` height=file.geometry.height width=file.geometry.width loading='lazy') img.file-thumb(src=`/file/${file.filename}` height=file.geometry.height width=file.geometry.width loading='lazy')
- if (post.message && modview) { post.message = post.message.replace(new RegExp(`<a class="quote" href="/${post.board}`, 'g'), `<a class="quote" href="/${post.board}/manage`); } //quick & dirty solution to a bigger problem/design issue - if (post.message && modview) { post.message = post.message.replace(new RegExp(`<a class="quote" href="/${post.board}`, 'g'), `<a class="quote" href="/${post.board}/manage`); } //quick & dirty solution to a bigger problem/design issue

Loading…
Cancel
Save