Add support for injecting dictionary media into Anki cards (#1805)
This commit is contained in:
parent
8d1596cdf8
commit
1088c17503
@ -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;
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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),
|
||||||
|
Loading…
Reference in New Issue
Block a user