Save previews locally.

pull/186/head
Mikunj 6 years ago
parent a1e4b740f2
commit a989a1a818

@ -1,9 +1,10 @@
/* global /* global
Signal, Signal,
textsecure, textsecure,
dcodeIO,
*/ */
/* eslint-disable no-bitwise */
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
(function() { (function() {
'use strict'; 'use strict';
@ -11,29 +12,6 @@
window.Signal = window.Signal || {}; window.Signal = window.Signal || {};
window.Signal.LinkPreviews = window.Signal.LinkPreviews || {}; window.Signal.LinkPreviews = window.Signal.LinkPreviews || {};
const base64ImageCache = {};
function getBase64Image(preview) {
const { url, image } = preview;
if (!url || !image || !image.data) return null;
// Return the cached value
if (base64ImageCache[url]) return base64ImageCache[url];
// Set the cache and return the value
try {
const contentType = image.contentType || 'image/jpeg';
const base64 = dcodeIO.ByteBuffer.wrap(image.data).toString('base64');
const data = `data:${contentType};base64, ${base64}`;
base64ImageCache[url] = data;
return data;
} catch (e) {
return null;
}
}
async function makeChunkedRequest(url) { async function makeChunkedRequest(url) {
const PARALLELISM = 3; const PARALLELISM = 3;
const size = await textsecure.messaging.getProxiedSize(url); const size = await textsecure.messaging.getProxiedSize(url);
@ -83,6 +61,19 @@
}; };
} }
function hashCode(string) {
let hash = 0;
if (string.length === 0) {
return hash;
}
for (let i = 0; i < string.length; i += 1) {
const char = string.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash &= hash; // Convert to 32bit integer
}
return hash;
}
async function getPreview(url) { async function getPreview(url) {
let html; let html;
try { try {
@ -145,11 +136,11 @@
title, title,
url, url,
image, image,
hash: hashCode(url),
}; };
} }
window.Signal.LinkPreviews.helper = { window.Signal.LinkPreviews.helper = {
getPreview, getPreview,
getBase64Image,
}; };
})(); })();

@ -17,7 +17,12 @@
window.Whisper = window.Whisper || {}; window.Whisper = window.Whisper || {};
const { Message: TypedMessage, Contact, PhoneNumber } = Signal.Types; const {
Message: TypedMessage,
Contact,
PhoneNumber,
Attachment,
} = Signal.Types;
const { const {
deleteAttachmentData, deleteAttachmentData,
deleteExternalMessageFiles, deleteExternalMessageFiles,
@ -26,6 +31,7 @@
loadQuoteData, loadQuoteData,
loadPreviewData, loadPreviewData,
writeNewAttachmentData, writeNewAttachmentData,
writeAttachment,
} = window.Signal.Migrations; } = window.Signal.Migrations;
window.AccountCache = Object.create(null); window.AccountCache = Object.create(null);
@ -85,7 +91,7 @@
this.on('expired', this.onExpired); this.on('expired', this.onExpired);
this.setToExpire(); this.setToExpire();
this.updatePreviews(); this.updatePreview();
}, },
idForLogging() { idForLogging() {
return `${this.get('source')}.${this.get('sourceDevice')} ${this.get( return `${this.get('source')}.${this.get('sourceDevice')} ${this.get(
@ -111,7 +117,7 @@
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
return !!(this.get('flags') & flag); return !!(this.get('flags') & flag);
}, },
async updatePreviews() { async updatePreview() {
// Don't generate link previews if user has turned them off // Don't generate link previews if user has turned them off
if (!storage.get('linkPreviews', false)) { if (!storage.get('linkPreviews', false)) {
return; return;
@ -141,15 +147,36 @@
try { try {
const result = await Signal.LinkPreviews.helper.getPreview(firstLink); const result = await Signal.LinkPreviews.helper.getPreview(firstLink);
const { image, title, hash } = result;
// A link preview isn't worth showing unless we have either a title or an image // A link preview isn't worth showing unless we have either a title or an image
if (!result || !(result.image || result.title)) { if (!result || !(image || title)) {
this.updatingPreview = false; this.updatingPreview = false;
return; return;
} }
// We don't want to save the base64 url in the message as // Save the image to disk
// it will increase the size of it, Rather we fetch the base64 later const { data } = image;
const extension = Attachment.getFileExtension(image);
if (data && extension) {
try {
const filePath = await writeAttachment({
data,
path: `previews/${hash}.${extension}`,
});
// return the image without the data
result.image = _.omit({ ...image, path: filePath }, 'data');
} catch (e) {
window.log.warn('Failed to write preview to disk', e);
}
}
// Save it!!
this.set({ preview: [result] }); this.set({ preview: [result] });
await window.Signal.Data.saveMessage(this.attributes, {
Message: Whisper.Message,
});
} catch (e) { } catch (e) {
window.log.warn(`Failed to load previews for message: ${this.id}`); window.log.warn(`Failed to load previews for message: ${this.id}`);
} finally { } finally {
@ -669,25 +696,13 @@
const previews = this.get('preview') || []; const previews = this.get('preview') || [];
return previews.map(preview => { return previews.map(preview => {
let image = {}; let image = null;
try {
// Try set the image from the attachment otherwise just pass in the object if (preview.image) {
if (preview.image) { image = this.getPropsForAttachment(preview.image);
try {
const attachmentProps = this.getPropsForAttachment(preview.image);
if (attachmentProps.url) {
image = attachmentProps;
}
} catch (e) {
// Only set the image if we have a url to display
const url = Signal.LinkPreviews.helper.getBase64Image(preview);
if (preview.image.url || url) {
image = {
...preview.image,
url: preview.image.url || url,
};
}
} }
} catch (e) {
window.log.info('Failed to show preview');
} }
return { return {
@ -1383,7 +1398,7 @@
}); });
// Update the previews if we need to // Update the previews if we need to
message.updatePreviews(); message.updatePreview();
if (type === 'outgoing') { if (type === 'outgoing') {
const receipts = Whisper.DeliveryReceipts.forMessage( const receipts = Whisper.DeliveryReceipts.forMessage(

@ -169,6 +169,8 @@ function initializeMigrations({
logger, logger,
}), }),
writeNewAttachmentData: createWriterForNew(attachmentsPath), writeNewAttachmentData: createWriterForNew(attachmentsPath),
writeAttachment: ({ data, path }) =>
createWriterForExisting(attachmentsPath)({ data, path }),
}; };
} }

@ -208,6 +208,7 @@ exports.deleteData = deleteOnDisk => {
exports.isVoiceMessage = AttachmentTS.isVoiceMessage; exports.isVoiceMessage = AttachmentTS.isVoiceMessage;
exports.save = AttachmentTS.save; exports.save = AttachmentTS.save;
exports.getFileExtension = AttachmentTS.getFileExtension;
const THUMBNAIL_SIZE = 150; const THUMBNAIL_SIZE = 150;
const THUMBNAIL_CONTENT_TYPE = 'image/png'; const THUMBNAIL_CONTENT_TYPE = 'image/png';

Loading…
Cancel
Save