server-ts: Port services/image

This commit is contained in:
Elian Doran 2024-02-20 23:29:03 +02:00
parent 29d37c40c1
commit fa0ed35752
11 changed files with 39 additions and 31 deletions

View File

@ -95,7 +95,7 @@ class Becca {
return this.notes[noteId]; return this.notes[noteId];
} }
getNoteOrThrow(noteId: string): BNote | null { getNoteOrThrow(noteId: string): BNote {
const note = this.notes[noteId]; const note = this.notes[noteId];
if (!note) { if (!note) {
throw new NotFoundError(`Note '${noteId}' doesn't exist.`); throw new NotFoundError(`Note '${noteId}' doesn't exist.`);

View File

@ -1,7 +1,7 @@
const becca = require('../../becca/becca'); const becca = require('../../becca/becca');
const blobService = require('../../services/blob'); const blobService = require('../../services/blob');
const ValidationError = require('../../errors/validation_error'); const ValidationError = require('../../errors/validation_error');
const imageService = require("../../services/image.js"); const imageService = require("../../services/image");
function getAttachmentBlob(req) { function getAttachmentBlob(req) {
const preview = req.query.preview === 'true'; const preview = req.query.preview === 'true';

View File

@ -5,7 +5,7 @@ const cloneService = require('../../services/cloning');
const noteService = require('../../services/notes'); const noteService = require('../../services/notes');
const dateNoteService = require('../../services/date_notes'); const dateNoteService = require('../../services/date_notes');
const dateUtils = require('../../services/date_utils'); const dateUtils = require('../../services/date_utils');
const imageService = require('../../services/image.js'); const imageService = require('../../services/image');
const appInfo = require('../../services/app_info'); const appInfo = require('../../services/app_info');
const ws = require('../../services/ws'); const ws = require('../../services/ws');
const log = require('../../services/log'); const log = require('../../services/log');

View File

@ -1,6 +1,6 @@
"use strict"; "use strict";
const imageService = require('../../services/image.js'); const imageService = require('../../services/image');
const becca = require('../../becca/becca'); const becca = require('../../becca/becca');
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR; const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
const fs = require('fs'); const fs = require('fs');

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
const imageType = require('image-type'); const imageType = require('image-type');
const imageService = require('../../services/image.js'); const imageService = require('../../services/image');
const noteService = require('../../services/notes'); const noteService = require('../../services/notes');
const {sanitizeAttributeName} = require('../../services/sanitize_attribute_name'); const {sanitizeAttributeName} = require('../../services/sanitize_attribute_name');
const specialNotesService = require('../../services/special_notes.js'); const specialNotesService = require('../../services/special_notes.js');

View File

@ -41,7 +41,7 @@ const importRoute = require('./api/import.js');
const setupApiRoute = require('./api/setup.js'); const setupApiRoute = require('./api/setup.js');
const sqlRoute = require('./api/sql'); const sqlRoute = require('./api/sql');
const databaseRoute = require('./api/database.js'); const databaseRoute = require('./api/database.js');
const imageRoute = require('./api/image.js'); const imageRoute = require('./api/image');
const attributesRoute = require('./api/attributes'); const attributesRoute = require('./api/attributes');
const scriptRoute = require('./api/script.js'); const scriptRoute = require('./api/script.js');
const senderRoute = require('./api/sender.js'); const senderRoute = require('./api/sender.js');

View File

@ -1,19 +1,19 @@
"use strict"; "use strict";
const becca = require('../becca/becca'); import becca = require('../becca/becca');
const log = require('./log'); import log = require('./log');
const protectedSessionService = require('./protected_session'); import protectedSessionService = require('./protected_session');
const noteService = require('./notes'); import noteService = require('./notes');
const optionService = require('./options'); import optionService = require('./options');
const sql = require('./sql'); import sql = require('./sql');
const jimp = require('jimp'); import jimp = require('jimp');
const imageType = require('image-type'); import imageType = require('image-type');
const sanitizeFilename = require('sanitize-filename'); import sanitizeFilename = require('sanitize-filename');
const isSvg = require('is-svg'); import isSvg = require('is-svg');
const isAnimated = require('is-animated'); import isAnimated = require('is-animated');
const htmlSanitizer = require('./html_sanitizer'); import htmlSanitizer = require('./html_sanitizer');
async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { async function processImage(uploadBuffer: Buffer, originalName: string, shrinkImageSwitch: boolean) {
const compressImages = optionService.getOptionBool("compressImages"); const compressImages = optionService.getOptionBool("compressImages");
const origImageFormat = getImageType(uploadBuffer); const origImageFormat = getImageType(uploadBuffer);
@ -44,7 +44,7 @@ async function processImage(uploadBuffer, originalName, shrinkImageSwitch) {
}; };
} }
function getImageType(buffer) { function getImageType(buffer: Buffer) {
if (isSvg(buffer)) { if (isSvg(buffer)) {
return { return {
ext: 'svg' ext: 'svg'
@ -57,18 +57,19 @@ function getImageType(buffer) {
} }
} }
function getImageMimeFromExtension(ext) { function getImageMimeFromExtension(ext: string) {
ext = ext.toLowerCase(); ext = ext.toLowerCase();
return `image/${ext === 'svg' ? 'svg+xml' : ext}`; return `image/${ext === 'svg' ? 'svg+xml' : ext}`;
} }
function updateImage(noteId, uploadBuffer, originalName) { function updateImage(noteId: string, uploadBuffer: Buffer, originalName: string) {
log.info(`Updating image ${noteId}: ${originalName}`); log.info(`Updating image ${noteId}: ${originalName}`);
originalName = htmlSanitizer.sanitize(originalName); originalName = htmlSanitizer.sanitize(originalName);
const note = becca.getNote(noteId); const note = becca.getNote(noteId);
if (!note) { throw new Error("Unable to find note."); }
note.saveRevision(); note.saveRevision();
@ -85,7 +86,7 @@ function updateImage(noteId, uploadBuffer, originalName) {
}); });
} }
function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch, trimFilename = false) { function saveImage(parentNoteId: string, uploadBuffer: Buffer, originalName: string, shrinkImageSwitch: boolean, trimFilename = false) {
log.info(`Saving image ${originalName} into parent ${parentNoteId}`); log.info(`Saving image ${originalName} into parent ${parentNoteId}`);
if (trimFilename && originalName.length > 40) { if (trimFilename && originalName.length > 40) {
@ -95,6 +96,7 @@ function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch,
const fileName = sanitizeFilename(originalName); const fileName = sanitizeFilename(originalName);
const parentNote = becca.getNote(parentNoteId); const parentNote = becca.getNote(parentNoteId);
if (!parentNote) { throw new Error("Unable to find parent note."); }
const {note} = noteService.createNewNote({ const {note} = noteService.createNewNote({
parentNoteId, parentNoteId,
@ -131,7 +133,7 @@ function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch,
}; };
} }
function saveImageToAttachment(noteId, uploadBuffer, originalName, shrinkImageSwitch, trimFilename = false) { function saveImageToAttachment(noteId: string, uploadBuffer: Buffer, originalName: string, shrinkImageSwitch: boolean, trimFilename = false) {
log.info(`Saving image '${originalName}' as attachment into note '${noteId}'`); log.info(`Saving image '${originalName}' as attachment into note '${noteId}'`);
if (trimFilename && originalName.length > 40) { if (trimFilename && originalName.length > 40) {
@ -163,6 +165,7 @@ function saveImageToAttachment(noteId, uploadBuffer, originalName, shrinkImageSw
processImage(uploadBuffer, originalName, shrinkImageSwitch).then(({buffer, imageFormat}) => { processImage(uploadBuffer, originalName, shrinkImageSwitch).then(({buffer, imageFormat}) => {
sql.transactional(() => { sql.transactional(() => {
// re-read, might be changed in the meantime // re-read, might be changed in the meantime
if (!attachment.attachmentId) { throw new Error("Missing attachment ID."); }
attachment = becca.getAttachmentOrThrow(attachment.attachmentId); attachment = becca.getAttachmentOrThrow(attachment.attachmentId);
attachment.mime = getImageMimeFromExtension(imageFormat.ext); attachment.mime = getImageMimeFromExtension(imageFormat.ext);
@ -179,7 +182,7 @@ function saveImageToAttachment(noteId, uploadBuffer, originalName, shrinkImageSw
return attachment; return attachment;
} }
async function shrinkImage(buffer, originalName) { async function shrinkImage(buffer: Buffer, originalName: string) {
let jpegQuality = optionService.getOptionInt('imageJpegQuality', 0); let jpegQuality = optionService.getOptionInt('imageJpegQuality', 0);
if (jpegQuality < 10 || jpegQuality > 100) { if (jpegQuality < 10 || jpegQuality > 100) {
@ -190,7 +193,7 @@ async function shrinkImage(buffer, originalName) {
try { try {
finalImageBuffer = await resize(buffer, jpegQuality); finalImageBuffer = await resize(buffer, jpegQuality);
} }
catch (e) { catch (e: any) {
log.error(`Failed to resize image '${originalName}', stack: ${e.stack}`); log.error(`Failed to resize image '${originalName}', stack: ${e.stack}`);
finalImageBuffer = buffer; finalImageBuffer = buffer;
@ -205,7 +208,7 @@ async function shrinkImage(buffer, originalName) {
return finalImageBuffer; return finalImageBuffer;
} }
async function resize(buffer, quality) { async function resize(buffer: Buffer, quality: number) {
const imageMaxWidthHeight = optionService.getOptionInt('imageMaxWidthHeight'); const imageMaxWidthHeight = optionService.getOptionInt('imageMaxWidthHeight');
const start = Date.now(); const start = Date.now();

View File

@ -5,7 +5,7 @@ const log = require('../log');
const utils = require('../utils'); const utils = require('../utils');
const sql = require('../sql'); const sql = require('../sql');
const noteService = require('../notes'); const noteService = require('../notes');
const imageService = require('../image.js'); const imageService = require('../image');
const protectedSessionService = require('../protected_session'); const protectedSessionService = require('../protected_session');
const htmlSanitizer = require('../html_sanitizer'); const htmlSanitizer = require('../html_sanitizer');
const {sanitizeAttributeName} = require('../sanitize_attribute_name'); const {sanitizeAttributeName} = require('../sanitize_attribute_name');

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
const noteService = require('../../services/notes'); const noteService = require('../../services/notes');
const imageService = require('../../services/image.js'); const imageService = require('../../services/image');
const protectedSessionService = require('../protected_session'); const protectedSessionService = require('../protected_session');
const markdownService = require('./markdown.js'); const markdownService = require('./markdown.js');
const mimeService = require('./mime.js'); const mimeService = require('./mime.js');

View File

@ -506,7 +506,7 @@ async function downloadImage(noteId: string, imageUrl: string) {
const parsedUrl = url.parse(unescapedUrl); const parsedUrl = url.parse(unescapedUrl);
const title = path.basename(parsedUrl.pathname || ""); const title = path.basename(parsedUrl.pathname || "");
const imageService = require('../services/image.js'); const imageService = require('../services/image');
const attachment = imageService.saveImageToAttachment(noteId, imageBuffer, title, true, true); const attachment = imageService.saveImageToAttachment(noteId, imageBuffer, title, true, true);
imageUrlToAttachmentIdMapping[imageUrl] = attachment.attachmentId; imageUrlToAttachmentIdMapping[imageUrl] = attachment.attachmentId;
@ -539,7 +539,7 @@ function downloadImages(noteId: string, content: string) {
const imageBase64 = url.substr(inlineImageMatch[0].length); const imageBase64 = url.substr(inlineImageMatch[0].length);
const imageBuffer = Buffer.from(imageBase64, 'base64'); const imageBuffer = Buffer.from(imageBase64, 'base64');
const imageService = require('../services/image.js'); const imageService = require('../services/image');
const attachment = imageService.saveImageToAttachment(noteId, imageBuffer, "inline image", true, true); const attachment = imageService.saveImageToAttachment(noteId, imageBuffer, "inline image", true, true);
const encodedTitle = encodeURIComponent(attachment.title); const encodedTitle = encodeURIComponent(attachment.title);

5
src/types.d.ts vendored
View File

@ -24,4 +24,9 @@ declare module 'joplin-turndown-plugin-gfm' {
function gfm(service: TurndownService): void; function gfm(service: TurndownService): void;
} }
export = gfm; export = gfm;
}
declare module 'is-animated' {
function isAnimated(buffer: Buffer): boolean;
export = isAnimated;
} }