// ==UserScript==
// @name Duolingo HearEverything
// @namespace http://tampermonkey.net/
// @version 0.7
// @description Let's you hear phrases and words from single choice questions based on your browsers speech synthesis (right now only phrases).
// @author You
// @match https://*.duolingo.com/*
// @grant none
// @downloadURL none
// ==/UserScript==
// TODO: Voice selector (automagic)
// 0.7: Mutation Observer instead of setInterval
// 0.6: Add voice to choices on click
// TODO: Add autoplay selector
// 0.6.1: check why not the innerText of the answer is displayed in the full sentence?
var voiceSelect = 10; // insert voice number here
/* Find your language number here
0: SpeechSynthesisVoice {voiceURI: "Microsoft Katja Online (Natural) - German (Germany)", name: "Microsoft Katja Online (Natural) - German (Germany)", lang: "de-DE", localService: false, default: true}
1: SpeechSynthesisVoice {voiceURI: "Microsoft Natasha Online (Natural) - English (Australia)", name: "Microsoft Natasha Online (Natural) - English (Australia)", lang: "en-AU", localService: false, default: false}
2: SpeechSynthesisVoice {voiceURI: "Microsoft Clara Online (Natural) - English (Canada)", name: "Microsoft Clara Online (Natural) - English (Canada)", lang: "en-CA", localService: false, default: false}
3: SpeechSynthesisVoice {voiceURI: "Microsoft Mia Online (Natural) - English (United Kingdom)", name: "Microsoft Mia Online (Natural) - English (United Kingdom)", lang: "en-GB", localService: false, default: false}
4: SpeechSynthesisVoice {voiceURI: "Microsoft Neerja Online (Natural) - English (India)", name: "Microsoft Neerja Online (Natural) - English (India)", lang: "en-IN", localService: false, default: false}
5: SpeechSynthesisVoice {voiceURI: "Microsoft Aria Online (Natural) - English (United States)", name: "Microsoft Aria Online (Natural) - English (United States)", lang: "en-US", localService: false, default: false}
6: SpeechSynthesisVoice {voiceURI: "Microsoft Guy Online (Natural) - English (United States)", name: "Microsoft Guy Online (Natural) - English (United States)", lang: "en-US", localService: false, default: false}
7: SpeechSynthesisVoice {voiceURI: "Microsoft Elvira Online (Natural) - Spanish (Spain)", name: "Microsoft Elvira Online (Natural) - Spanish (Spain)", lang: "es-ES", localService: false, default: false}
8: SpeechSynthesisVoice {voiceURI: "Microsoft Dalia Online (Natural) - Spanish (Mexico)", name: "Microsoft Dalia Online (Natural) - Spanish (Mexico)", lang: "es-MX", localService: false, default: false}
9: SpeechSynthesisVoice {voiceURI: "Microsoft Sylvie Online (Natural) - French (Canada)", name: "Microsoft Sylvie Online (Natural) - French (Canada)", lang: "fr-CA", localService: false, default: false}
10: SpeechSynthesisVoice {voiceURI: "Microsoft Denise Online (Natural) - French (France)", name: "Microsoft Denise Online (Natural) - French (France)", lang: "fr-FR", localService: false, default: false}
11: SpeechSynthesisVoice {voiceURI: "Microsoft Swara Online (Natural) - Hindi (India)", name: "Microsoft Swara Online (Natural) - Hindi (India)", lang: "hi-IN", localService: false, default: false}
12: SpeechSynthesisVoice {voiceURI: "Microsoft Elsa Online (Natural) - Italian (Italy)", name: "Microsoft Elsa Online (Natural) - Italian (Italy)", lang: "it-IT", localService: false, default: false}
13: SpeechSynthesisVoice {voiceURI: "Microsoft Nanami Online (Natural) - Japanese (Japan)", name: "Microsoft Nanami Online (Natural) - Japanese (Japan)", lang: "ja-JP", localService: false, default: false}
14: SpeechSynthesisVoice {voiceURI: "Microsoft SunHi Online (Natural) - Korean (Korea)", name: "Microsoft SunHi Online (Natural) - Korean (Korea)", lang: "ko-KR", localService: false, default: false}
15: SpeechSynthesisVoice {voiceURI: "Microsoft Colette Online (Natural) - Dutch (Netherlands)", name: "Microsoft Colette Online (Natural) - Dutch (Netherlands)", lang: "nl-NL", localService: false, default: false}
16: SpeechSynthesisVoice {voiceURI: "Microsoft Zofia Online (Natural) - Polish (Poland)", name: "Microsoft Zofia Online (Natural) - Polish (Poland)", lang: "pl-PL", localService: false, default: false}
17: SpeechSynthesisVoice {voiceURI: "Microsoft Francisca Online (Natural) - Portuguese (Brazil)", name: "Microsoft Francisca Online (Natural) - Portuguese (Brazil)", lang: "pt-BR", localService: false, default: false}
18: SpeechSynthesisVoice {voiceURI: "Microsoft Svetlana Online (Natural) - Russian (Russia)", name: "Microsoft Svetlana Online (Natural) - Russian (Russia)", lang: "ru-RU", localService: false, default: false}
19: SpeechSynthesisVoice {voiceURI: "Microsoft Emel Online (Natural) - Turkish (Turkey)", name: "Microsoft Emel Online (Natural) - Turkish (Turkey)", lang: "tr-TR", localService: false, default: false}
20: SpeechSynthesisVoice {voiceURI: "Microsoft Xiaoxiao Online (Natural) - Chinese (Mainland)", name: "Microsoft Xiaoxiao Online (Natural) - Chinese (Mainland)", lang: "zh-CN", localService: false, default: false}
21: SpeechSynthesisVoice {voiceURI: "Microsoft Yunyang Online (Natural) - Chinese (Mainland)", name: "Microsoft Yunyang Online (Natural) - Chinese (Mainland)", lang: "zh-CN", localService: false, default: false}
22: SpeechSynthesisVoice {voiceURI: "Microsoft HiuGaai Online (Natural) - Chinese (Hong Kong)", name: "Microsoft HiuGaai Online (Natural) - Chinese (Hong Kong)", lang: "zh-HK", localService: false, default: false}
23: SpeechSynthesisVoice {voiceURI: "Microsoft HsiaoYu Online (Natural) - Chinese (Taiwan)", name: "Microsoft HsiaoYu Online (Natural) - Chinese (Taiwan)", lang: "zh-TW", localService: false, default: false}
24: SpeechSynthesisVoice {voiceURI: "Microsoft Hedda - German (Germany)", name: "Microsoft Hedda - German (Germany)", lang: "de-DE", localService: true, default: false}
25: SpeechSynthesisVoice {voiceURI: "Microsoft Katja - German (Germany)", name: "Microsoft Katja - German (Germany)", lang: "de-DE", localService: true, default: false}
26: SpeechSynthesisVoice {voiceURI: "Microsoft Stefan - German (Germany)", name: "Microsoft Stefan - German (Germany)", lang: "de-DE", localService: true, default: false}
*/
var synth = window.speechSynthesis;
var voices = [];
//let parent = HTMLElement;
var newPage = true;
var addedSpeech = false;
function start() {
if(document.querySelector('[data-test="challenge-form-prompt"]')!=null) {
if (newPage === true) {
// if answer (right or wrong) is displayed
if (document.querySelector('._1UqAr')!=null) {
let dataPrompt = document.querySelector('[data-test="challenge-form-prompt"]');
let solution = document.querySelector('._1UqAr');
let read = '';
// if it's the right solution, we get it from the selected choise
if (solution.classList.contains('_1Nmv6')) {
read = dataPrompt.getAttribute('data-prompt').replace(/_+/,document.querySelector('[aria-checked="true"] div').innerText);
} else {
// if it's wrong, we have to get it from the right solution display
read = dataPrompt.getAttribute('data-prompt').replace(/_+/,solution.innerText);
}
// let checked = document.querySelector('[aria-checked="true"] div').innerText;
// let read = "";
// if(checked!="") {
// read = dataPrompt.getAttribute('data-prompt').replace(/_+/,checked);
// } else {
// // TODO: problem with selection - probably remove checked
// let solution = document.querySelector('._1UqAr');
// read = dataPrompt.getAttribute('data-prompt').replace(/_+/,solution.innerText);
// }
// alert(read);
let utter = new SpeechSynthesisUtterance(read);
utter.voice = voices[voiceSelect];
// synth.speak(utter);
//dataPrompt.insertAdjacentHTML('afterend',``);
updateText(read);
document.querySelector('#speak').addEventListener('click',function(){synth.speak(utter);});
newPage = false;
addedSpeech = false;
} else if((addedSpeech===false)&&(document.querySelectorAll('[aria-checked]').length!==0)) {
// if eventListeners were not bound yet
addSpeech();
addedSpeech = true;
}
}
} else {
newPage = true;
}
}
window.onload = function() {
//_1UqAr - class for answer
// data-test="challenge-form-prompt" - tag with fill-ins
//data-prompt
//aria-checked tag with fill-in options
// _1Nmv6 - class for right answer
// _1sqiF - class for wrong answer
'use strict';
// console.log('---------------------onload-------------------------');
voices = window.speechSynthesis.getVoices();
console.log(voices);
new MutationObserver(start).observe(document.body, {
childList: true,
subtree: true
});
};
function addSpeech() {
let options = document.querySelectorAll('[aria-checked]');
for (let i=0; i
${t}
`;
}
}