aboutsummaryrefslogtreecommitdiff
path: root/ext/js
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2021-07-06 22:00:18 -0400
committerGitHub <noreply@github.com>2021-07-06 22:00:18 -0400
commit1088c17503cd6f52019a094ac19f68b0e12ba007 (patch)
treed96b446ff7895d532077f13b493429527acf766a /ext/js
parent8d1596cdf86976362dc9ed0678412b7b8b1ff20c (diff)
Add support for injecting dictionary media into Anki cards (#1805)
Diffstat (limited to 'ext/js')
-rw-r--r--ext/js/background/backend.js76
-rw-r--r--ext/js/comm/api.js4
-rw-r--r--ext/js/data/anki-note-builder.js26
3 files changed, 88 insertions, 18 deletions
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 8ad6c19f..7f9fe7f8 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -490,14 +490,15 @@ class Backend {
return results;
}
- async _onApiInjectAnkiNoteMedia({timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails}) {
+ async _onApiInjectAnkiNoteMedia({timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails}) {
return await this._injectAnkNoteMedia(
this._anki,
timestamp,
definitionDetails,
audioDetails,
screenshotDetails,
- clipboardDetails
+ clipboardDetails,
+ dictionaryMediaDetails
);
}
@@ -1682,7 +1683,7 @@ class Backend {
}
}
- async _injectAnkNoteMedia(ankiConnect, timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails) {
+ async _injectAnkNoteMedia(ankiConnect, timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails) {
let screenshotFileName = null;
let clipboardImageFileName = null;
let clipboardText = null;
@@ -1721,14 +1722,25 @@ class Backend {
errors.push(serializeError(e));
}
+ let dictionaryMedia;
+ try {
+ let errors2;
+ ({results: dictionaryMedia, errors: errors2} = await this._injectAnkiNoteDictionaryMedia(ankiConnect, timestamp, definitionDetails, dictionaryMediaDetails));
+ for (const error of errors2) {
+ errors.push(serializeError(error));
+ }
+ } catch (e) {
+ dictionaryMedia = [];
+ errors.push(serializeError(e));
+ }
+
return {
- result: {
- screenshotFileName,
- clipboardImageFileName,
- clipboardText,
- audioFileName
- },
- errors
+ screenshotFileName,
+ clipboardImageFileName,
+ clipboardText,
+ audioFileName,
+ dictionaryMedia,
+ errors: errors
};
}
@@ -1801,6 +1813,50 @@ class Backend {
return fileName;
}
+ async _injectAnkiNoteDictionaryMedia(ankiConnect, timestamp, definitionDetails, dictionaryMediaDetails) {
+ const targets = [];
+ const detailsList = [];
+ const detailsMap = new Map();
+ for (const {dictionary, path} of dictionaryMediaDetails) {
+ const target = {dictionary, path};
+ const details = {dictionary, path, media: null};
+ const key = JSON.stringify(target);
+ targets.push(target);
+ detailsList.push(details);
+ detailsMap.set(key, details);
+ }
+ const mediaList = await this._dictionaryDatabase.getMedia(targets);
+
+ for (const media of mediaList) {
+ const {dictionary, path} = media;
+ const key = JSON.stringify({dictionary, path});
+ const details = detailsMap.get(key);
+ if (typeof details === 'undefined' || details.media !== null) { continue; }
+ details.media = media;
+ }
+
+ const errors = [];
+ const results = [];
+ for (let i = 0, ii = detailsList.length; i < ii; ++i) {
+ const {dictionary, path, media} = detailsList[i];
+ let fileName = null;
+ if (media !== null) {
+ const {content, mediaType} = media;
+ const extension = MediaUtil.getFileExtensionFromImageMediaType(mediaType);
+ fileName = this._generateAnkiNoteMediaFileName(`yomichan_dictionary_media_${i + 1}`, extension, timestamp, definitionDetails);
+ try {
+ await ankiConnect.storeMediaFile(fileName, content);
+ } catch (e) {
+ errors.push(e);
+ fileName = null;
+ }
+ }
+ results.push({dictionary, path, fileName});
+ }
+
+ return {results, errors};
+ }
+
_generateAnkiNoteMediaFileName(prefix, extension, timestamp, definitionDetails) {
let fileName = prefix;
diff --git a/ext/js/comm/api.js b/ext/js/comm/api.js
index 7e77180e..7c89f0c5 100644
--- a/ext/js/comm/api.js
+++ b/ext/js/comm/api.js
@@ -56,8 +56,8 @@ class API {
return this._invoke('getAnkiNoteInfo', {notes, fetchAdditionalInfo});
}
- injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails) {
- return this._invoke('injectAnkiNoteMedia', {timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails});
+ injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails) {
+ return this._invoke('injectAnkiNoteMedia', {timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails});
}
noteView(noteId) {
diff --git a/ext/js/data/anki-note-builder.js b/ext/js/data/anki-note-builder.js
index c69d6741..65740254 100644
--- a/ext/js/data/anki-note-builder.js
+++ b/ext/js/data/anki-note-builder.js
@@ -283,7 +283,7 @@ class AnkiNoteBuilder {
let injectScreenshot = false;
let injectClipboardImage = false;
let injectClipboardText = false;
- const injectDictionaryMedia = [];
+ const dictionaryMediaDetails = [];
for (const requirement of requirements) {
const {type} = requirement;
switch (type) {
@@ -291,7 +291,12 @@ class AnkiNoteBuilder {
case 'screenshot': injectScreenshot = true; break;
case 'clipboardImage': injectClipboardImage = true; break;
case 'clipboardText': injectClipboardText = true; break;
- case 'dictionaryMedia': injectDictionaryMedia.push(requirement); break;
+ case 'dictionaryMedia':
+ {
+ const {dictionary, path} = requirement;
+ dictionaryMediaDetails.push({dictionary, path});
+ }
+ break;
}
}
@@ -318,17 +323,26 @@ class AnkiNoteBuilder {
}
// Inject media
- // TODO : injectDictionaryMedia
- const {result: {audioFileName, screenshotFileName, clipboardImageFileName, clipboardText}, errors} = await yomichan.api.injectAnkiNoteMedia(
+ const {audioFileName, screenshotFileName, clipboardImageFileName, clipboardText, dictionaryMedia: dictionaryMediaArray, errors} = await yomichan.api.injectAnkiNoteMedia(
timestamp,
dictionaryEntryDetails,
audioDetails,
screenshotDetails,
- clipboardDetails
+ clipboardDetails,
+ dictionaryMediaDetails
);
// Format results
- const dictionaryMedia = {}; // TODO
+ const dictionaryMedia = {};
+ for (const {dictionary, path, fileName} of dictionaryMediaArray) {
+ if (fileName === null) { continue; }
+ const dictionaryMedia2 = (
+ Object.prototype.hasOwnProperty.call(dictionaryMedia, dictionary) ?
+ (dictionaryMedia[dictionary]) :
+ (dictionaryMedia[dictionary] = {})
+ );
+ dictionaryMedia2[path] = {fileName};
+ }
const media = {
audio: (typeof audioFileName === 'string' ? {fileName: audioFileName} : null),
screenshot: (typeof screenshotFileName === 'string' ? {fileName: screenshotFileName} : null),