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; return results;
} }
async _onApiInjectAnkiNoteMedia({timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails}) { async _onApiInjectAnkiNoteMedia({timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails}) {
return await this._injectAnkNoteMedia( return await this._injectAnkNoteMedia(
this._anki, this._anki,
timestamp, timestamp,
definitionDetails, definitionDetails,
audioDetails, audioDetails,
screenshotDetails, 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 screenshotFileName = null;
let clipboardImageFileName = null; let clipboardImageFileName = null;
let clipboardText = null; let clipboardText = null;
@ -1721,14 +1722,25 @@ class Backend {
errors.push(serializeError(e)); 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 { return {
result: { screenshotFileName,
screenshotFileName, clipboardImageFileName,
clipboardImageFileName, clipboardText,
clipboardText, audioFileName,
audioFileName dictionaryMedia,
}, errors: errors
errors
}; };
} }
@ -1801,6 +1813,50 @@ class Backend {
return fileName; 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) { _generateAnkiNoteMediaFileName(prefix, extension, timestamp, definitionDetails) {
let fileName = prefix; let fileName = prefix;

View File

@ -56,8 +56,8 @@ class API {
return this._invoke('getAnkiNoteInfo', {notes, fetchAdditionalInfo}); return this._invoke('getAnkiNoteInfo', {notes, fetchAdditionalInfo});
} }
injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails) { injectAnkiNoteMedia(timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails) {
return this._invoke('injectAnkiNoteMedia', {timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails}); return this._invoke('injectAnkiNoteMedia', {timestamp, definitionDetails, audioDetails, screenshotDetails, clipboardDetails, dictionaryMediaDetails});
} }
noteView(noteId) { noteView(noteId) {

View File

@ -283,7 +283,7 @@ class AnkiNoteBuilder {
let injectScreenshot = false; let injectScreenshot = false;
let injectClipboardImage = false; let injectClipboardImage = false;
let injectClipboardText = false; let injectClipboardText = false;
const injectDictionaryMedia = []; const dictionaryMediaDetails = [];
for (const requirement of requirements) { for (const requirement of requirements) {
const {type} = requirement; const {type} = requirement;
switch (type) { switch (type) {
@ -291,7 +291,12 @@ class AnkiNoteBuilder {
case 'screenshot': injectScreenshot = true; break; case 'screenshot': injectScreenshot = true; break;
case 'clipboardImage': injectClipboardImage = true; break; case 'clipboardImage': injectClipboardImage = true; break;
case 'clipboardText': injectClipboardText = 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 // Inject media
// TODO : injectDictionaryMedia const {audioFileName, screenshotFileName, clipboardImageFileName, clipboardText, dictionaryMedia: dictionaryMediaArray, errors} = await yomichan.api.injectAnkiNoteMedia(
const {result: {audioFileName, screenshotFileName, clipboardImageFileName, clipboardText}, errors} = await yomichan.api.injectAnkiNoteMedia(
timestamp, timestamp,
dictionaryEntryDetails, dictionaryEntryDetails,
audioDetails, audioDetails,
screenshotDetails, screenshotDetails,
clipboardDetails clipboardDetails,
dictionaryMediaDetails
); );
// Format results // 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 = { const media = {
audio: (typeof audioFileName === 'string' ? {fileName: audioFileName} : null), audio: (typeof audioFileName === 'string' ? {fileName: audioFileName} : null),
screenshot: (typeof screenshotFileName === 'string' ? {fileName: screenshotFileName} : null), screenshot: (typeof screenshotFileName === 'string' ? {fileName: screenshotFileName} : null),