diff --git a/dashboard-ui/scripts/librarymenu.js b/dashboard-ui/scripts/librarymenu.js
index 185bddba79..fe7661e666 100644
--- a/dashboard-ui/scripts/librarymenu.js
+++ b/dashboard-ui/scripts/librarymenu.js
@@ -165,7 +165,7 @@
function showVoice() {
require(['voice/voice'], function (voice) {
- voice.startListening();
+ voice.showDialog();
});
}
diff --git a/dashboard-ui/voice/commands/controlcommands.js b/dashboard-ui/voice/commands/controlcommands.js
index 46d27418f0..621bb6fde3 100644
--- a/dashboard-ui/voice/commands/controlcommands.js
+++ b/dashboard-ui/voice/commands/controlcommands.js
@@ -1,5 +1,4 @@
-
-define([], function () {
+define([], function () {
return function (result) {
result.success = true;
diff --git a/dashboard-ui/voice/commands/disablecommands.js b/dashboard-ui/voice/commands/disablecommands.js
index 6338fecd5f..b6cbd120be 100644
--- a/dashboard-ui/voice/commands/disablecommands.js
+++ b/dashboard-ui/voice/commands/disablecommands.js
@@ -1,5 +1,4 @@
-
-define([], function () {
+define([], function () {
return function (result) {
result.success = true;
diff --git a/dashboard-ui/voice/commands/enablecommands.js b/dashboard-ui/voice/commands/enablecommands.js
index e790731f48..5fc5eff211 100644
--- a/dashboard-ui/voice/commands/enablecommands.js
+++ b/dashboard-ui/voice/commands/enablecommands.js
@@ -1,5 +1,4 @@
-
-define([], function () {
+define([], function () {
return function (result) {
result.success = true;
diff --git a/dashboard-ui/voice/commands/searchcommands.js b/dashboard-ui/voice/commands/searchcommands.js
index 6338fecd5f..59ed4d3ea9 100644
--- a/dashboard-ui/voice/commands/searchcommands.js
+++ b/dashboard-ui/voice/commands/searchcommands.js
@@ -1,12 +1,7 @@
-
-define([], function () {
+define([], function () {
return function (result) {
- result.success = true;
switch (result.item.deviceid) {
- case 'displaymirroring':
- MediaController.enableDisplayMirroring(false);
- break;
default:
result.success = false;
return;
diff --git a/dashboard-ui/voice/commands/showcommands.js b/dashboard-ui/voice/commands/showcommands.js
index 81850a657d..ebfb7dd5f9 100644
--- a/dashboard-ui/voice/commands/showcommands.js
+++ b/dashboard-ui/voice/commands/showcommands.js
@@ -1,5 +1,4 @@
-
-define([], function () {
+define([], function () {
return function (result) {
result.success = true;
diff --git a/dashboard-ui/voice/commands/togglecommands.js b/dashboard-ui/voice/commands/togglecommands.js
index 526668229c..1bc588d771 100644
--- a/dashboard-ui/voice/commands/togglecommands.js
+++ b/dashboard-ui/voice/commands/togglecommands.js
@@ -1,5 +1,4 @@
-
-define([], function () {
+define([], function () {
return function (result) {
result.success = true;
@@ -12,5 +11,4 @@ define([], function () {
return;
}
}
-
});
\ No newline at end of file
diff --git a/dashboard-ui/voice/grammar/en-US.json b/dashboard-ui/voice/grammar/en-US.json
index 7c3e4f07e9..5c79188a01 100644
--- a/dashboard-ui/voice/grammar/en-US.json
+++ b/dashboard-ui/voice/grammar/en-US.json
@@ -139,7 +139,7 @@
"commandtemplates": [
"Play music",
"Play my music",
- "Listen to my music "
+ "Listen to my music"
]
},
{
@@ -188,7 +188,7 @@
"commandtemplates": [
"Play music",
"Play my music",
- "Listen to my music "
+ "Listen to my music"
]
},
{
@@ -200,7 +200,7 @@
"commandtemplates": [
"Play music",
"Play my music",
- "Listen to my music ",
+ "Listen to my music",
"shuffle my favorite songs"
]
}
diff --git a/dashboard-ui/voice/voice.css b/dashboard-ui/voice/voice.css
index 307b3e0036..a155574a86 100644
--- a/dashboard-ui/voice/voice.css
+++ b/dashboard-ui/voice/voice.css
@@ -1,5 +1,5 @@
.voiceHelpContent {
- max-width: 600px;
+ max-width: 700px;
margin: auto;
}
diff --git a/dashboard-ui/voice/voice.js b/dashboard-ui/voice/voice.js
index b48664f3c1..6d38fc2684 100644
--- a/dashboard-ui/voice/voice.js
+++ b/dashboard-ui/voice/voice.js
@@ -18,9 +18,9 @@ define([], function () {
window.msSpeechRecognition;
},
- startListening: function () {
+ showDialog: function () {
require(['voice/voicedialog'], function (voicedialog) {
- voicedialog.startListening();
+ voicedialog.showDialog();
});
}
};
diff --git a/dashboard-ui/voice/voicedialog.js b/dashboard-ui/voice/voicedialog.js
index 64445c2a35..308b8efbfe 100644
--- a/dashboard-ui/voice/voicedialog.js
+++ b/dashboard-ui/voice/voicedialog.js
@@ -1,37 +1,7 @@
-define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
+define(['dialogHelper', 'voice/voicereceiver', 'voice/voiceprocessor', 'globalize', 'emby-button', 'css!./voice.css', 'material-icons'], function (dialogHelper, voicereceiver, voiceprocessor, globalize) {
- var currentRecognition;
var lang = 'en-US';
- var commandgroups;
-
- function getCommandGroups() {
-
- if (commandgroups) {
- return Promise.resolve(commandgroups);
- }
-
- return new Promise(function (resolve, reject) {
-
- var file = "grammar";
- //if (language && language.length > 0)
- // file = language;
-
- var xhr = new XMLHttpRequest();
- xhr.open('GET', "voice/grammar/" + file + ".json", true);
-
- xhr.onload = function (e) {
-
- commandgroups = JSON.parse(this.response);
- resolve(commandgroups);
- }
-
- xhr.onerror = reject;
-
- xhr.send();
- });
- }
-
/// Shuffle array.
/// The array.
/// array
@@ -58,7 +28,7 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// The sample commands.
function getSampleCommands(groupid) {
- return getCommandGroups().then(function (commandGroups) {
+ return voiceprocessor.getCommandGroups().then(function (commandGroups) {
groupid = typeof (groupid) !== 'undefined' ? groupid : '';
var commands = [];
@@ -86,17 +56,20 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// The groupid.
/// The command group.
function getCommandGroup(groupid) {
- if (commandgroups) {
- var idx = -1;
- idx = commandgroups.map(function (e) { return e.groupid; }).indexOf(groupid);
+ return voicereceiver.getCommandGroups()
+ .then(function (commandgroups) {
+ if (commandgroups) {
+ var idx = -1;
- if (idx > -1)
- return commandgroups[idx];
- else
- return null;
- }
- else
- return null;
+ idx = commandgroups.map(function (e) { return e.groupid; }).indexOf(groupid);
+
+ if (idx > -1)
+ return commandgroups[idx];
+ else
+ return null;
+ } else
+ return null;
+ });
}
/// Renders the sample commands.
@@ -113,7 +86,7 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
}).join('');
- $('.exampleCommands', elem).html(commands);
+ elem.querySelector('.exampleCommands').innerHTML = commands;
}
var currentDialog;
@@ -121,212 +94,179 @@ define(['dialogHelper', 'jQuery', 'emby-button'], function (dialogHelper, $) {
/// .
function showVoiceHelp(groupid, title) {
- var dlg = dialogHelper.createDialog({
- size: 'medium',
- removeOnClose: true
- });
+ console.log("Showing Voice Help", groupid, title);
- dlg.classList.add('ui-body-b');
- dlg.classList.add('background-theme-b');
+ var isNewDialog = false;
+ var dlg;
- var html = '';
- html += '
';
- html += '';
+ dlg = currentDialog;
- var getCommandsPromise = getSampleCommands(groupid);
+ if (groupid) {
+ getCommandGroup(groupid)
+ .then(
+ function (grp) {
+ dlg.querySelector('#voiceDialogGroupName').innerText = ' ' + grp.name;
+ });
- html += '
';
- html += '
';
+ getSampleCommands(groupid)
+ .then(function (commands) {
+ renderSampleCommands(currentDialog, commands);
+ listen();
+ })
+ .catch(function (e) { console.log("Error", e); });
+ } else if (isNewDialog) {
+ getSampleCommands()
+ .then(function (commands) {
+ renderSampleCommands(currentDialog, commands);
+ });
- html += '
' + Globalize.translate('HeaderSaySomethingLike') + '
';
-
- html += '
';
- html += '
';
-
- // defaultVoiceHelp
- html += '
';
-
- html += '
';
- html += '
' + Globalize.translate('HeaderYouSaid') + '
';
- html += '
';
- html += '
' + Globalize.translate('MessageWeDidntRecognizeCommand') + '
';
-
- html += '
';
- html += '
';
- html += '
' + Globalize.translate('MessageIfYouBlockedVoice') + '
';
-
- html += '
';
-
- html += '
';
-
- // voiceHelpContent
- html += '
';
-
- html += '
';
-
- dlg.innerHTML = html;
- document.body.appendChild(dlg);
-
- dialogHelper.open(dlg);
- currentDialog = dlg;
-
- dlg.addEventListener('close', function () {
- currentDialog = null;
- });
-
- $('.btnCancelVoiceInput', dlg).on('click', function () {
- destroyCurrentRecognition();
- dialogHelper.close(dlg);
- });
-
- $('.btnRetry', dlg).on('click', function () {
- $('.unrecognizedCommand').hide();
- $('.defaultVoiceHelp').show();
- startListening(false);
- });
-
- getCommandsPromise.then(function (commands) {
- renderSampleCommands(dlg.querySelector('.voiceHelpContent'), commands);
- });
+ }
}
-
- /// Hides the voice help.
- /// .
- function hideVoiceHelp() {
-
- $('.voiceInputHelp').remove();
+ function processInput(input) {
+ return voiceprocessor.processTranscript(input);
}
/// Shows the unrecognized command help.
/// .
- function showUnrecognizedCommandHelp() {
+ function showUnrecognizedCommandHelp(command) {
//speak("I don't understend this command");
- $('.unrecognizedCommand').show();
- $('.defaultVoiceHelp').hide();
- }
-
- /// Process the transcript described by text.
- /// The text.
- /// .
- function processTranscript(text, isCancelled) {
-
- $('.voiceInputText').html(text);
-
- if (text || AppInfo.isNativeApp) {
- $('.blockedMessage').hide();
- }
- else {
- $('.blockedMessage').show();
- }
-
- if (text) {
- require(['voice/voicecommands.js', 'voice/grammarprocessor.js'], function (voicecommands, grammarprocessor) {
-
- var processor = grammarprocessor(commandgroups, text);
- if (processor && processor.command) {
- voicecommands(processor)
- .then(function (result) {
- if (result.item.actionid === 'show' && result.item.sourceid === 'group') {
- var dlg = currentDialog;
- if (dlg)
- showCommands(false, result)
- else
- showCommands(true, result)
- }
- })
- .catch(showUnrecognizedCommandHelp);
- }
- else
- showUnrecognizedCommandHelp();
-
- var dlg = currentDialog;
- if (dlg) {
- dialogHelper.close(dlg);
- }
- });
-
- }
- else if (!isCancelled) {
- showUnrecognizedCommandHelp();
- }
- }
-
- /// Starts listening internal.
- /// .
- function startListening(createUI) {
-
- destroyCurrentRecognition();
- var recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition)();
- recognition.lang = lang;
- var groupid = '';
- //recognition.continuous = true;
- //recognition.interimResults = true;
-
- recognition.onresult = function (event) {
- if (event.results.length > 0) {
- processTranscript(event.results[0][0].transcript || '');
- }
- };
-
- recognition.onerror = function () {
- processTranscript('', recognition.cancelled);
- };
-
- recognition.onnomatch = function () {
- processTranscript('', recognition.cancelled);
- };
-
- recognition.start();
- currentRecognition = recognition;
- showCommands(createUI);
- }
-
- /// Destroys the current recognition.
- /// .
- function destroyCurrentRecognition() {
-
- var recognition = currentRecognition;
- if (recognition) {
- recognition.abort();
- currentRecognition = null;
- }
- }
-
- /// Cancel listener.
- /// .
- function cancelListener() {
-
- destroyCurrentRecognition();
- hideVoiceHelp();
+ if (command)
+ currentDialog.querySelector('.voiceInputText').innerText = command;
+ currentDialog.querySelector('.unrecognizedCommand').classList.remove('hide');
+ currentDialog.querySelector('.defaultVoiceHelp').classList.add('hide');
}
/// Shows the commands.
/// The create user interface.
/// .
- function showCommands(createUI, result) {
- if (createUI !== false) {
- //speak('Hello, what can I do for you?');
- require(['paper-fab', 'css!voice/voice.css'], function () {
- if (result)
- showVoiceHelp(result.groupid, result.name);
- else
- showVoiceHelp();
- });
+ function showCommands(result) {
+ //speak('Hello, what can I do for you?');
+ if (result)
+ showVoiceHelp(result.groupid, result.name);
+ else
+ showVoiceHelp();
+ }
+
+ function resetDialog() {
+ if (currentDialog) {
+ currentDialog.querySelector('.unrecognizedCommand').classList.add('hide');
+ currentDialog.querySelector('.defaultVoiceHelp').classList.remove('hide');
}
}
+ function showDialog() {
+ resetDialog();
+ showCommands();
+ listen();
+ }
+ function listen() {
+ voicereceiver.listenForCommand(lang || "en-US").then(processInput).then(function (data) {
+
+ closeDialog();
+
+ }, function (result) {
+ if (result.error == 'group') {
+ showVoiceHelp(result.item.groupid, result.groupName);
+ return;
+ }
+ showUnrecognizedCommandHelp(result.text || '');
+ });
+ }
+ function closeDialog() {
+ dialogHelper.close(currentDialog);
+ voicereceiver.cancel();
+ }
/// An enum constant representing the window. voice input manager option.
return {
- startListening: startListening
+ showDialog: showDialog
};
});
\ No newline at end of file
diff --git a/dashboard-ui/voice/voiceprocessor.js b/dashboard-ui/voice/voiceprocessor.js
new file mode 100644
index 0000000000..5570ab2b8c
--- /dev/null
+++ b/dashboard-ui/voice/voiceprocessor.js
@@ -0,0 +1,65 @@
+define(['voice/voicecommands.js', 'voice/grammarprocessor.js'], function (voicecommands, grammarprocessor) {
+
+ var commandgroups;
+
+ function getCommandGroups() {
+
+ if (commandgroups) {
+ return Promise.resolve(commandgroups);
+ }
+
+ return new Promise(function (resolve, reject) {
+
+ var file = "grammar";
+ //if (language && language.length > 0)
+ // file = language;
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', "voice/grammar/" + file + ".json", true);
+
+ xhr.onload = function (e) {
+
+ commandgroups = JSON.parse(this.response);
+ resolve(commandgroups);
+ }
+
+ xhr.onerror = reject;
+
+ xhr.send();
+ });
+ }
+ /// Process the transcript described by text.
+ /// The text.
+ /// .
+ function processTranscript(text) {
+ if (text) {
+ var processor = grammarprocessor(commandgroups, text);
+ if (processor && processor.command) {
+ console.log("Command from Grammar Processor", processor);
+ return voicecommands(processor)
+ .then(function (result) {
+ console.log("Result of executed command", result);
+ if (result.item.actionid === 'show' && result.item.sourceid === 'group') {
+ return Promise.reject({ error: "group", item: result.item, groupName: result.name });
+ } else {
+ return Promise.resolve({ item: result.item });
+ }
+ }, function () {
+ return Promise.reject({ error: "unrecognized-command", text: text });
+ });
+ } else {
+ return Promise.reject({ error: "unrecognized-command", text: text });
+ }
+
+ } else {
+ return Promise.reject({ error: "empty" });
+ }
+ }
+
+ /// An enum constant representing the window. voice input manager option.
+ return {
+ processTranscript: processTranscript,
+ getCommandGroups: getCommandGroups
+ };
+
+});
\ No newline at end of file
diff --git a/dashboard-ui/voice/voicereceiver.js b/dashboard-ui/voice/voicereceiver.js
new file mode 100644
index 0000000000..d25bd115fb
--- /dev/null
+++ b/dashboard-ui/voice/voicereceiver.js
@@ -0,0 +1,57 @@
+define([], function () {
+ var currentRecognition = null;
+
+
+ /// Starts listening for voice commands
+ /// .
+ function listenForCommand(lang) {
+ return new Promise(function (resolve, reject) {
+ cancelListener();
+
+ var recognition = new (window.SpeechRecognition ||
+ window.webkitSpeechRecognition ||
+ window.mozSpeechRecognition ||
+ window.oSpeechRecognition ||
+ window.msSpeechRecognition)();
+ recognition.lang = lang;
+
+ recognition.onresult = function (event) {
+ console.log(event);
+ if (event.results.length > 0) {
+ var resultInput = event.results[0][0].transcript || '';
+ resolve(resultInput);
+ }
+ };
+
+ recognition.onerror = function () {
+ reject({ error: event.error, message: event.message });
+ };
+
+ recognition.onnomatch = function () {
+ reject({ error: "no-match" });
+ };
+ currentRecognition = recognition;
+
+ currentRecognition.start();
+ });
+ }
+
+
+ /// Cancel listener.
+ /// .
+ function cancelListener() {
+
+ if (currentRecognition) {
+ currentRecognition.abort();
+ currentRecognition = null;
+ }
+
+ }
+
+ /// An enum constant representing the window. voice input manager option.
+ return {
+ listenForCommand: listenForCommand,
+ cancel: cancelListener
+ };
+
+});
\ No newline at end of file