From ac603d54a3a53bec2881199756f3dd6a1aa44057 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 11 Apr 2020 14:23:49 -0400 Subject: Add support for displaying images --- ext/mixed/js/media-loader.js | 107 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 ext/mixed/js/media-loader.js (limited to 'ext/mixed/js/media-loader.js') diff --git a/ext/mixed/js/media-loader.js b/ext/mixed/js/media-loader.js new file mode 100644 index 00000000..c89c4f12 --- /dev/null +++ b/ext/mixed/js/media-loader.js @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2020 Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* global + * apiGetMedia + */ + +class MediaLoader { + constructor() { + this._token = {}; + this._mediaCache = new Map(); + this._loadMediaData = []; + } + + async loadMedia(path, dictionaryName, onLoad, onUnload) { + const token = this.token; + const data = {onUnload, loaded: false}; + + this._loadMediaData.push(data); + + const media = await this.getMedia(path, dictionaryName); + if (token !== this.token) { return; } + + onLoad(media.url); + data.loaded = true; + } + + unloadAll() { + for (const {onUnload, loaded} of this._loadMediaData) { + if (typeof onUnload === 'function') { + onUnload(loaded); + } + } + this._loadMediaData = []; + + for (const map of this._mediaCache.values()) { + for (const {url} of map.values()) { + if (url !== null) { + URL.revokeObjectURL(url); + } + } + } + this._mediaCache.clear(); + + this._token = {}; + } + + async getMedia(path, dictionaryName) { + let cachedData; + let dictionaryCache = this._mediaCache.get(dictionaryName); + if (typeof dictionaryCache !== 'undefined') { + cachedData = dictionaryCache.get(path); + } else { + dictionaryCache = new Map(); + this._mediaCache.set(dictionaryName, dictionaryCache); + } + + if (typeof cachedData === 'undefined') { + cachedData = { + promise: null, + data: null, + url: null + }; + dictionaryCache.set(path, cachedData); + cachedData.promise = this._getMediaData(path, dictionaryName, cachedData); + } + + return cachedData.promise; + } + + async _getMediaData(path, dictionaryName, cachedData) { + const token = this._token; + const data = (await apiGetMedia([{path, dictionaryName}]))[0]; + if (token === this._token && data !== null) { + const sourceArrayBuffer = this._base64ToArrayBuffer(data.source); + const blob = new Blob([sourceArrayBuffer], {type: data.mediaType}); + const url = URL.createObjectURL(blob); + cachedData.data = data; + cachedData.url = url; + } + return cachedData; + } + + _base64ToArrayBuffer(source) { + const binarySource = window.atob(source); + const length = binarySource.length; + const array = new Uint8Array(length); + for (let i = 0; i < length; ++i) { + array[i] = binarySource.charCodeAt(i); + } + return array.buffer; + } +} -- cgit v1.2.3 From 7faaf4e45737dd06ab3fdf189bd9c1d26ad1349d Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:16:59 -0400 Subject: Use 'content' instead of 'source' to contain media file data --- ext/bg/js/dictionary-importer.js | 6 +++--- ext/bg/js/media-utility.js | 4 ++-- ext/mixed/js/media-loader.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'ext/mixed/js/media-loader.js') diff --git a/ext/bg/js/dictionary-importer.js b/ext/bg/js/dictionary-importer.js index 8a4497a3..b5c535bb 100644 --- a/ext/bg/js/dictionary-importer.js +++ b/ext/bg/js/dictionary-importer.js @@ -323,7 +323,7 @@ class DictionaryImporter { throw new Error(`Could not find image at path ${JSON.stringify(path)} for ${errorSource}`); } - const source = await file.async('base64'); + const content = await file.async('base64'); const mediaType = mediaUtility.getImageMediaTypeFromFileName(path); if (mediaType === null) { throw new Error(`Could not determine media type for image at path ${JSON.stringify(path)} for ${errorSource}`); @@ -331,7 +331,7 @@ class DictionaryImporter { let image; try { - image = await mediaUtility.loadImage(mediaType, source); + image = await mediaUtility.loadImage(mediaType, content); } catch (e) { throw new Error(`Could not load image at path ${JSON.stringify(path)} for ${errorSource}`); } @@ -346,7 +346,7 @@ class DictionaryImporter { mediaType, width, height, - source + content }; context.media.set(path, mediaData); diff --git a/ext/bg/js/media-utility.js b/ext/bg/js/media-utility.js index 24686838..febc509a 100644 --- a/ext/bg/js/media-utility.js +++ b/ext/bg/js/media-utility.js @@ -52,7 +52,7 @@ const mediaUtility = (() => { } } - function loadImage(mediaType, base64Source) { + function loadImage(mediaType, content) { return new Promise((resolve, reject) => { const image = new Image(); const eventListeners = new EventListenerCollection(); @@ -64,7 +64,7 @@ const mediaUtility = (() => { eventListeners.removeAllEventListeners(); reject(new Error('Image failed to load')); }, false); - image.src = `data:${mediaType};base64,${base64Source}`; + image.src = `data:${mediaType};base64,${content}`; }); } diff --git a/ext/mixed/js/media-loader.js b/ext/mixed/js/media-loader.js index c89c4f12..5e3177fc 100644 --- a/ext/mixed/js/media-loader.js +++ b/ext/mixed/js/media-loader.js @@ -86,7 +86,7 @@ class MediaLoader { const token = this._token; const data = (await apiGetMedia([{path, dictionaryName}]))[0]; if (token === this._token && data !== null) { - const sourceArrayBuffer = this._base64ToArrayBuffer(data.source); + const sourceArrayBuffer = this._base64ToArrayBuffer(data.content); const blob = new Blob([sourceArrayBuffer], {type: data.mediaType}); const url = URL.createObjectURL(blob); cachedData.data = data; @@ -95,8 +95,8 @@ class MediaLoader { return cachedData; } - _base64ToArrayBuffer(source) { - const binarySource = window.atob(source); + _base64ToArrayBuffer(content) { + const binarySource = window.atob(content); const length = binarySource.length; const array = new Uint8Array(length); for (let i = 0; i < length; ++i) { -- cgit v1.2.3 From ba68616d809800aa40165a8913e55d6fe05a5502 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 19 Apr 2020 10:57:23 -0400 Subject: Change some more variables using 'source' instead of 'content' --- ext/mixed/js/media-loader.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'ext/mixed/js/media-loader.js') diff --git a/ext/mixed/js/media-loader.js b/ext/mixed/js/media-loader.js index 5e3177fc..64ccd715 100644 --- a/ext/mixed/js/media-loader.js +++ b/ext/mixed/js/media-loader.js @@ -86,8 +86,8 @@ class MediaLoader { const token = this._token; const data = (await apiGetMedia([{path, dictionaryName}]))[0]; if (token === this._token && data !== null) { - const sourceArrayBuffer = this._base64ToArrayBuffer(data.content); - const blob = new Blob([sourceArrayBuffer], {type: data.mediaType}); + const contentArrayBuffer = this._base64ToArrayBuffer(data.content); + const blob = new Blob([contentArrayBuffer], {type: data.mediaType}); const url = URL.createObjectURL(blob); cachedData.data = data; cachedData.url = url; @@ -96,11 +96,11 @@ class MediaLoader { } _base64ToArrayBuffer(content) { - const binarySource = window.atob(content); - const length = binarySource.length; + const binaryContent = window.atob(content); + const length = binaryContent.length; const array = new Uint8Array(length); for (let i = 0; i < length; ++i) { - array[i] = binarySource.charCodeAt(i); + array[i] = binaryContent.charCodeAt(i); } return array.buffer; } -- cgit v1.2.3