Add support for injecting dictionary media into Anki cards (#1805)

This commit is contained in:
toasted-nutbread 2021-07-06 22:00:18 -04:00 committed by GitHub
parent 8d1596cdf8
commit 1088c17503
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 18 deletions

View File

@ -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;

View File

@ -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) {

View File

@ -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),