Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offscreen db #316

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 56 additions & 5 deletions ext/js/background/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,35 @@ export class Backend {
constructor() {
this._japaneseUtil = new JapaneseUtil(wanakana);
this._environment = new Environment();
this._dictionaryDatabase = new DictionaryDatabase();
this._translator = new Translator({
japaneseUtil: this._japaneseUtil,
database: this._dictionaryDatabase
});
this._anki = new AnkiConnect();
this._mecab = new Mecab();

if (!chrome.offscreen) {
this._dictionaryDatabase = new DictionaryDatabase();
this._translator = new Translator({
japaneseUtil: this._japaneseUtil,
database: this._dictionaryDatabase
});
this._clipboardReader = new ClipboardReader({
// eslint-disable-next-line no-undef
document: (typeof document === 'object' && document !== null ? document : null),
pasteTargetSelector: '#clipboard-paste-target',
richContentPasteTargetSelector: '#clipboard-rich-content-paste-target'
});
} else {
this._dictionaryDatabase = {
prepare: () => this._sendMessagePromise({action: 'databasePrepareOffscreen'}),
getDictionaryInfo: () => this._sendMessagePromise({action: 'getDictionaryInfoOffscreen'}),
purge: () => this._sendMessagePromise({action: 'databasePurgeOffscreen'}),
getMedia: this._getMediaOffscreen.bind(this)
};
this._translator = {
prepare: (deinflectionReasons) => this._sendMessagePromise({action: 'translatorPrepareOffscreen', params: {deinflectionReasons}}),
findKanji: this._findKanjiOffscreen.bind(this),
findTerms: this._findTermsOffscreen.bind(this),
getTermFrequencies: this._getTermFrequenciesOffscreen.bind(this),
clearDatabaseCaches: () => this._sendMessagePromise({action: 'clearDatabaseCachesOffscreen'})
};
this._clipboardReader = {
getText: this._getTextOffscreen.bind(this),
getImage: this._getImageOffscreen.bind(this)
Expand Down Expand Up @@ -2240,6 +2253,44 @@ export class Backend {
return results;
}

async _getMediaOffscreen(targets) {
const serializedMedia = await this._sendMessagePromise({action: 'databaseGetMediaOffscreen', params: {targets}});
const media = serializedMedia.map((m) => ({...m, content: ArrayBufferUtil.base64ToArrayBuffer(m.content)}));
return media;
}

async _findKanjiOffscreen(text, findKanjiOptions) {
const enabledDictionaryMapList = [...findKanjiOptions.enabledDictionaryMap];
const modifiedKanjiOptions = {
...findKanjiOptions,
enabledDictionaryMap: enabledDictionaryMapList
};
return this._sendMessagePromise({action: 'findKanjiOffscreen', params: {text, findKanjiOptions: modifiedKanjiOptions}});
}

async _findTermsOffscreen(mode, text, findTermsOptions) {
const {enabledDictionaryMap, excludeDictionaryDefinitions, textReplacements} = findTermsOptions;
const enabledDictionaryMapList = [...enabledDictionaryMap];
const excludeDictionaryDefinitionsList = excludeDictionaryDefinitions ? [...excludeDictionaryDefinitions] : null;
const textReplacementsSerialized = textReplacements.map((group) => {
if (!group) {
return group;
}
return group.map((opt) => ({...opt, pattern: opt.pattern.toString()}));
});
const modifiedFindTermsOptions = {
...findTermsOptions,
enabledDictionaryMap: enabledDictionaryMapList,
excludeDictionaryDefinitions: excludeDictionaryDefinitionsList,
textReplacements: textReplacementsSerialized
};
return this._sendMessagePromise({action: 'findTermsOffscreen', params: {mode, text, findTermsOptions: modifiedFindTermsOptions}});
}

async _getTermFrequenciesOffscreen(termReadingList, dictionaries) {
return this._sendMessagePromise({action: 'getTermFrequenciesOffscreen', params: {termReadingList, dictionaries}});
}

async _getTextOffscreen(useRichText) {
return this._sendMessagePromise({action: 'clipboardGetTextOffscreen', params: {useRichText}});
}
Expand Down
81 changes: 80 additions & 1 deletion ext/js/background/offscreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

import * as wanakana from '../../lib/wanakana.js';
import {ClipboardReader} from '../comm/clipboard-reader.js';
import {invokeMessageHandler} from '../core.js';
import {ArrayBufferUtil} from '../data/sandbox/array-buffer-util.js';
import {DictionaryDatabase} from '../language/dictionary-database.js';
import {JapaneseUtil} from '../language/sandbox/japanese-util.js';
import {Translator} from '../language/translator.js';
import {yomitan} from '../yomitan.js';

/**
Expand All @@ -29,6 +34,12 @@ export class Offscreen {
* Creates a new instance.
*/
constructor() {
this._japaneseUtil = new JapaneseUtil(wanakana);
this._dictionaryDatabase = new DictionaryDatabase();
this._translator = new Translator({
japaneseUtil: this._japaneseUtil,
database: this._dictionaryDatabase
});
this._clipboardReader = new ClipboardReader({
// eslint-disable-next-line no-undef
document: (typeof document === 'object' && document !== null ? document : null),
Expand All @@ -38,11 +49,23 @@ export class Offscreen {

this._messageHandlers = new Map([
['clipboardGetTextOffscreen', {async: true, contentScript: true, handler: this._getTextHandler.bind(this)}],
['clipboardGetImageOffscreen', {async: true, contentScript: true, handler: this._getImageHandler.bind(this)}]
['clipboardGetImageOffscreen', {async: true, contentScript: true, handler: this._getImageHandler.bind(this)}],
['databasePrepareOffscreen', {async: true, contentScript: true, handler: this._prepareDatabaseHandler.bind(this)}],
['getDictionaryInfoOffscreen', {async: true, contentScript: true, handler: this._getDictionaryInfoHandler.bind(this)}],
['databasePurgeOffscreen', {async: true, contentScript: true, handler: this._purgeDatabaseHandler.bind(this)}],
['databaseGetMediaOffscreen', {async: true, contentScript: true, handler: this._getMediaHandler.bind(this)}],
['translatorPrepareOffscreen', {async: false, contentScript: true, handler: this._prepareTranslatorHandler.bind(this)}],
['findKanjiOffscreen', {async: true, contentScript: true, handler: this._findKanjiHandler.bind(this)}],
['findTermsOffscreen', {async: true, contentScript: true, handler: this._findTermsHandler.bind(this)}],
['getTermFrequenciesOffscreen', {async: true, contentScript: true, handler: this._getTermFrequenciesHandler.bind(this)}],
['clearDatabaseCachesOffscreen', {async: false, contentScript: true, handler: this._clearDatabaseCachesHandler.bind(this)}]

]);

const onMessage = this._onMessage.bind(this);
chrome.runtime.onMessage.addListener(onMessage);

this._prepareDatabasePromise = null;
}

_getTextHandler({useRichText}) {
Expand All @@ -53,6 +76,62 @@ export class Offscreen {
return this._clipboardReader.getImage();
}

_prepareDatabaseHandler() {
if (this._prepareDatabasePromise !== null) {
return this._prepareDatabasePromise;
}
this._prepareDatabasePromise = this._dictionaryDatabase.prepare();
return this._prepareDatabasePromise;
}

_getDictionaryInfoHandler() {
return this._dictionaryDatabase.getDictionaryInfo();
}

_purgeDatabaseHandler() {
return this._dictionaryDatabase.purge();
}

async _getMediaHandler({targets}) {
const media = await this._dictionaryDatabase.getMedia(targets);
const serializedMedia = media.map((m) => ({...m, content: ArrayBufferUtil.arrayBufferToBase64(m.content)}));
return serializedMedia;
}

_prepareTranslatorHandler({deinflectionReasons}) {
return this._translator.prepare(deinflectionReasons);
}

_findKanjiHandler({text, findKanjiOptions}) {
findKanjiOptions.enabledDictionaryMap = new Map(findKanjiOptions.enabledDictionaryMap);
return this._translator.findKanji(text, findKanjiOptions);
}

_findTermsHandler({mode, text, findTermsOptions}) {
findTermsOptions.enabledDictionaryMap = new Map(findTermsOptions.enabledDictionaryMap);
if (findTermsOptions.excludeDictionaryDefinitions) {
findTermsOptions.excludeDictionaryDefinitions = new Set(findTermsOptions.excludeDictionaryDefinitions);
}
findTermsOptions.textReplacements = findTermsOptions.textReplacements.map((group) => {
if (!group) {
return group;
}
return group.map((opt) => {
const [, pattern, flags] = opt.pattern.match(/\/(.*?)\/([a-z]*)?$/i); // https://stackoverflow.com/a/33642463
return {...opt, pattern: new RegExp(pattern, flags ?? '')};
});
});
return this._translator.findTerms(mode, text, findTermsOptions);
}

_getTermFrequenciesHandler({termReadingList, dictionaries}) {
return this._translator.getTermFrequencies(termReadingList, dictionaries);
}

_clearDatabaseCachesHandler() {
return this._translator.clearDatabaseCaches();
}

_onMessage({action, params}, sender, callback) {
const messageHandler = this._messageHandlers.get(action);
if (typeof messageHandler === 'undefined') { return false; }
Expand Down
Loading