aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Yatskov <alex@foosoft.net>2017-04-02 12:08:15 -0700
committerAlex Yatskov <alex@foosoft.net>2017-04-02 12:08:15 -0700
commit9ac55fb5d11e5037e808939598591d55d1368b43 (patch)
tree8cd4d6452f83c279f1ecb23a1fce9039f40a09ef
parent4eb3e2f06cd83ef0721557f8559fc0a6d70ad4f5 (diff)
support for multiple audio sources, version bump1.1.11
-rw-r--r--ext/bg/js/options.js4
-rw-r--r--ext/bg/js/util.js90
-rw-r--r--ext/bg/js/yomichan.js2
-rw-r--r--ext/bg/options.html11
-rw-r--r--ext/manifest.json2
-rw-r--r--ext/mixed/js/display.js4
-rw-r--r--ext/mixed/js/util.js101
7 files changed, 85 insertions, 129 deletions
diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js
index 75f39d24..ad8d83d8 100644
--- a/ext/bg/js/options.js
+++ b/ext/bg/js/options.js
@@ -25,7 +25,7 @@ function formRead() {
return optionsLoad().then(optionsOld => {
const optionsNew = $.extend(true, {}, optionsOld);
- optionsNew.general.audioPlayback = $('#audio-playback-buttons').prop('checked');
+ optionsNew.general.audioSource = $('#audio-playback-source').val();
optionsNew.general.audioVolume = $('#audio-playback-volume').val();
optionsNew.general.groupResults = $('#group-terms-results').prop('checked');
optionsNew.general.softKatakana = $('#soft-katakana-search').prop('checked');
@@ -111,7 +111,7 @@ $(document).ready(() => {
handlebarsRegister();
optionsLoad().then(options => {
- $('#audio-playback-buttons').prop('checked', options.general.audioPlayback);
+ $('#audio-playback-source').val(options.general.audioSource);
$('#audio-playback-volume').val(options.general.audioVolume);
$('#group-terms-results').prop('checked', options.general.groupResults);
$('#soft-katakana-search').prop('checked', options.general.softKatakana);
diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js
index 78258c97..05c7ff27 100644
--- a/ext/bg/js/util.js
+++ b/ext/bg/js/util.js
@@ -25,9 +25,6 @@ function promiseCallback(promise, callback) {
return promise.then(result => {
callback({result});
}).catch(error => {
- /* eslint-disable */
- console.log(error);
- /* eslint-enable */
callback({error});
});
}
@@ -84,7 +81,7 @@ function optionsSetDefaults(options) {
const defaults = {
general: {
enable: true,
- audioPlayback: true,
+ audioSource: 'jpod101',
audioVolume: 100,
groupResults: true,
softKatakana: true,
@@ -137,84 +134,15 @@ function optionsSetDefaults(options) {
function optionsVersion(options) {
const fixups = [
+ () => { },
+ () => { },
+ () => { },
+ () => { },
() => {
- const copy = (targetDict, targetKey, sourceDict, sourceKey) => {
- targetDict[targetKey] = sourceDict.hasOwnProperty(sourceKey) ? sourceDict[sourceKey] : targetDict[targetKey];
- };
-
- copy(options.general, 'autoStart', options, 'activateOnStartup');
- copy(options.general, 'audioPlayback', options, 'enableAudioPlayback');
- copy(options.general, 'softKatakana', options, 'enableSoftKatakanaSearch');
- copy(options.general, 'groupResults', options, 'groupTermResults');
- copy(options.general, 'showAdvanced', options, 'showAdvancedOptions');
-
- copy(options.scanning, 'requireShift', options, 'holdShiftToScan');
- copy(options.scanning, 'selectText', options, 'selectMatchedText');
- copy(options.scanning, 'delay', options, 'scanDelay');
- copy(options.scanning, 'length', options, 'scanLength');
-
- options.anki.enable = options.ankiMethod === 'ankiconnect';
-
- copy(options.anki, 'tags', options, 'ankiCardTags');
- copy(options.anki, 'sentenceExt', options, 'sentenceExtent');
- copy(options.anki.terms, 'deck', options, 'ankiTermDeck');
- copy(options.anki.terms, 'model', options, 'ankiTermModel');
- copy(options.anki.terms, 'fields', options, 'ankiTermFields');
- copy(options.anki.kanji, 'deck', options, 'ankiKanjiDeck');
- copy(options.anki.kanji, 'model', options, 'ankiKanjiModel');
- copy(options.anki.kanji, 'fields', options, 'ankiKanjiFields');
-
- for (const title in options.dictionaries) {
- const dictionary = options.dictionaries[title];
- dictionary.enabled = dictionary.enableTerms || dictionary.enableKanji;
- dictionary.priority = 0;
- }
- },
- () => {
- const fixupFields = fields => {
- const fixups = {
- '{expression-furigana}': '{furigana}',
- '{glossary-list}': '{glossary}'
- };
-
- for (const name in fields) {
- for (const fixup in fixups) {
- fields[name] = fields[name].replace(fixup, fixups[fixup]);
- }
- }
- };
-
- fixupFields(options.anki.terms.fields);
- fixupFields(options.anki.kanji.fields);
- },
- () => {
- let hasEnabledDict = false;
- for (const title in options.dictionaries) {
- if (options.dictionaries[title].enabled) {
- hasEnabledDict = true;
- break;
- }
- }
-
- if (!hasEnabledDict) {
- for (const title in options.dictionaries) {
- options.dictionaries[title].enabled = true;
- }
- }
- },
- () => {
- let hasEnabledDict = false;
- for (const title in options.dictionaries) {
- if (options.dictionaries[title].enabled) {
- hasEnabledDict = true;
- break;
- }
- }
-
- if (!hasEnabledDict) {
- for (const title in options.dictionaries) {
- options.dictionaries[title].enabled = true;
- }
+ if (options.general.audioPlayback) {
+ options.general.audioSource = 'jpod101';
+ } else {
+ options.general.audioSource = 'disabled';
}
}
];
diff --git a/ext/bg/js/yomichan.js b/ext/bg/js/yomichan.js
index 7a26d6c7..feb74b6e 100644
--- a/ext/bg/js/yomichan.js
+++ b/ext/bg/js/yomichan.js
@@ -121,7 +121,7 @@ window.yomichan = new class {
definitionAdd(definition, mode) {
let promise = Promise.resolve();
if (mode !== 'kanji') {
- promise = audioInject(definition, this.options.anki.terms.fields);
+ promise = audioInject(definition, this.options.anki.terms.fields, this.options.general.audioSource);
}
return promise.then(() => {
diff --git a/ext/bg/options.html b/ext/bg/options.html
index c483c656..939227b0 100644
--- a/ext/bg/options.html
+++ b/ext/bg/options.html
@@ -37,8 +37,13 @@
<label><input type="checkbox" id="soft-katakana-search"> Soft Katakana search</label>
</div>
- <div class="checkbox">
- <label><input type="checkbox" id="audio-playback-buttons"> Audio playback buttons</label>
+ <div class="form-group">
+ <label for="audio-playback-source">Audio playback source</label>
+ <select class="form-control" id="audio-playback-source">
+ <option value="disabled">Disabled</option>
+ <option value="jpod101">JapanesePod101</option>
+ <option value="jpod101-alternate">JapanesePod101 (Alternate)</option>
+ </select>
</div>
<div class="form-group options-advanced">
@@ -52,7 +57,7 @@
</div>
<div class="form-group options-advanced">
- <label>Popup size (in pixels)</label>
+ <label>Popup size (width x height, in pixels)</label>
<div class="row">
<div class="col-xs-6"><input type="number" min="1" id="popup-width" class="form-control"></div>
<div class="col-xs-6"><input type="number" min="1" id="popup-height" class="form-control"></div>
diff --git a/ext/manifest.json b/ext/manifest.json
index 62a70f9c..b2752172 100644
--- a/ext/manifest.json
+++ b/ext/manifest.json
@@ -1,7 +1,7 @@
{
"manifest_version": 2,
"name": "Yomichan",
- "version": "1.1.10",
+ "version": "1.1.11",
"description": "Japanese dictionary with Anki integration",
"icons": {"16": "mixed/img/icon16.png", "48": "mixed/img/icon48.png", "128": "mixed/img/icon128.png"},
diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js
index 36609525..f5ad4849 100644
--- a/ext/mixed/js/display.js
+++ b/ext/mixed/js/display.js
@@ -69,7 +69,7 @@ class Display {
definitions,
addable: options.anki.enable,
grouped: options.general.groupResults,
- playback: options.general.audioPlayback
+ playback: options.general.audioSource !== 'disabled'
};
if (context) {
@@ -335,7 +335,7 @@ class Display {
this.audioCache[key].pause();
}
- audioBuildUrl(definition, this.responseCache).then(url => {
+ audioBuildUrl(definition, this.options.general.audioSource, this.responseCache).then(url => {
if (!url) {
url = '/mixed/mp3/button.mp3';
}
diff --git a/ext/mixed/js/util.js b/ext/mixed/js/util.js
index 4ce60e4f..edd49873 100644
--- a/ext/mixed/js/util.js
+++ b/ext/mixed/js/util.js
@@ -21,48 +21,71 @@
* Audio
*/
-function audioBuildUrl(definition, cache={}) {
- return new Promise((resolve, reject) => {
- const response = cache[definition.expression];
- if (response) {
- resolve(response);
- } else {
- const data = {
- post: 'dictionary_reference',
- match_type: 'exact',
- search_query: definition.expression
- };
+function audioBuildUrl(definition, mode, cache={}) {
+ if (mode === 'jpod101') {
+ let kana = definition.reading;
+ let kanji = definition.expression;
- const params = [];
- for (const key in data) {
- params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`);
- }
-
- const xhr = new XMLHttpRequest();
- xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
- xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
- xhr.addEventListener('error', () => reject('failed to scrape audio data'));
- xhr.addEventListener('load', () => {
- cache[definition.expression] = xhr.responseText;
- resolve(xhr.responseText);
- });
+ if (!kana && wanakana.isHiragana(kanji)) {
+ kana = kanji;
+ kanji = null;
+ }
- xhr.send(params.join('&'));
+ const params = [];
+ if (kanji) {
+ params.push(`kanji=${encodeURIComponent(kanji)}`);
}
- }).then(response => {
- const dom = new DOMParser().parseFromString(response, 'text/html');
- for (const row of dom.getElementsByClassName('dc-result-row')) {
- try {
- const url = row.getElementsByClassName('ill-onebuttonplayer').item(0).getAttribute('data-url');
- const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText;
- if (url && reading && (!definition.reading || definition.reading === reading)) {
- return url;
+ if (kana) {
+ params.push(`kana=${encodeURIComponent(kana)}`);
+ }
+
+ const url = `https://assets.languagepod101.com/dictionary/japanese/audiomp3.php?${params.join('&')}`;
+ return Promise.resolve(url);
+ } else if (mode === 'jpod101-alternate') {
+ return new Promise((resolve, reject) => {
+ const response = cache[definition.expression];
+ if (response) {
+ resolve(response);
+ } else {
+ const data = {
+ post: 'dictionary_reference',
+ match_type: 'exact',
+ search_query: definition.expression
+ };
+
+ const params = [];
+ for (const key in data) {
+ params.push(`${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`);
}
- } catch (e) {
- // NOP
+
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', 'https://www.japanesepod101.com/learningcenter/reference/dictionary_post');
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ xhr.addEventListener('error', () => reject('failed to scrape audio data'));
+ xhr.addEventListener('load', () => {
+ cache[definition.expression] = xhr.responseText;
+ resolve(xhr.responseText);
+ });
+
+ xhr.send(params.join('&'));
}
- }
- });
+ }).then(response => {
+ const dom = new DOMParser().parseFromString(response, 'text/html');
+ for (const row of dom.getElementsByClassName('dc-result-row')) {
+ try {
+ const url = row.getElementsByClassName('ill-onebuttonplayer').item(0).getAttribute('data-url');
+ const reading = row.getElementsByClassName('dc-vocab_kana').item(0).innerText;
+ if (url && reading && (!definition.reading || definition.reading === reading)) {
+ return url;
+ }
+ } catch (e) {
+ // NOP
+ }
+ }
+ });
+ } else {
+ return Promise.reject('unsupported audio source');
+ }
}
function audioBuildFilename(definition) {
@@ -79,7 +102,7 @@ function audioBuildFilename(definition) {
}
}
-function audioInject(definition, fields) {
+function audioInject(definition, fields, mode) {
const filename = audioBuildFilename(definition);
if (!filename) {
return Promise.resolve(true);
@@ -97,7 +120,7 @@ function audioInject(definition, fields) {
return Promise.resolve(true);
}
- return audioBuildUrl(definition).then(url => {
+ return audioBuildUrl(definition, mode).then(url => {
definition.audio = {url, filename};
return true;
}).catch(() => false);