mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-18 03:18:19 -07:00
381 lines
10 KiB
JavaScript
381 lines
10 KiB
JavaScript
(function () {
|
|
|
|
var currentRecognition;
|
|
|
|
function shuffleArray(array) {
|
|
var currentIndex = array.length, temporaryValue, randomIndex;
|
|
|
|
// While there remain elements to shuffle...
|
|
while (0 !== currentIndex) {
|
|
|
|
// Pick a remaining element...
|
|
randomIndex = Math.floor(Math.random() * currentIndex);
|
|
currentIndex -= 1;
|
|
|
|
// And swap it with the current element.
|
|
temporaryValue = array[currentIndex];
|
|
array[currentIndex] = array[randomIndex];
|
|
array[randomIndex] = temporaryValue;
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
function getSampleCommands() {
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
var commands = [];
|
|
|
|
//commands.push('show my movies');
|
|
//commands.push('pull up my tv shows');
|
|
|
|
commands.push('play my latest episodes');
|
|
commands.push('play next up');
|
|
commands.push('shuffle my favorite songs');
|
|
|
|
commands.push('show my tv guide');
|
|
commands.push('pull up my recordings');
|
|
commands.push('control chromecast');
|
|
commands.push('control [device name]');
|
|
commands.push('turn on display mirroring');
|
|
commands.push('turn off display mirroring');
|
|
commands.push('toggle display mirroring');
|
|
|
|
resolve(shuffleArray(commands));
|
|
});
|
|
}
|
|
|
|
function processText(text) {
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
require(['voice/textprocessor-en-us.js'], function (parseText) {
|
|
|
|
var result = parseText(text);
|
|
|
|
switch (result.action) {
|
|
|
|
case 'show':
|
|
showCommand(result);
|
|
break;
|
|
case 'play':
|
|
playCommand(result);
|
|
break;
|
|
case 'shuffle':
|
|
playCommand(result, true);
|
|
break;
|
|
case 'search':
|
|
playCommand(result);
|
|
break;
|
|
case 'control':
|
|
controlCommand(result);
|
|
break;
|
|
case 'enable':
|
|
enableCommand(result);
|
|
break;
|
|
case 'disable':
|
|
disableCommand(result);
|
|
break;
|
|
case 'toggle':
|
|
toggleCommand(result);
|
|
break;
|
|
default:
|
|
reject();
|
|
return;
|
|
}
|
|
|
|
var dlg = currentDialog;
|
|
if (dlg) {
|
|
PaperDialogHelper.close(dlg);
|
|
}
|
|
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
function showCommand(result) {
|
|
|
|
if (result.category == 'tvguide') {
|
|
Dashboard.navigate('livetv.html?tab=1');
|
|
return;
|
|
}
|
|
|
|
if (result.category == 'recordings') {
|
|
Dashboard.navigate('livetv.html?tab=3');
|
|
return;
|
|
}
|
|
}
|
|
|
|
function enableCommand(result) {
|
|
|
|
var what = result.what.toLowerCase();
|
|
|
|
if (what.indexOf('mirror') != -1) {
|
|
MediaController.enableDisplayMirroring(true);
|
|
}
|
|
}
|
|
|
|
function disableCommand(result) {
|
|
|
|
var what = result.what.toLowerCase();
|
|
|
|
if (what.indexOf('mirror') != -1) {
|
|
MediaController.enableDisplayMirroring(false);
|
|
}
|
|
}
|
|
|
|
function toggleCommand(result) {
|
|
|
|
var what = result.what.toLowerCase();
|
|
|
|
if (what.indexOf('mirror') != -1) {
|
|
MediaController.toggleDisplayMirroring();
|
|
}
|
|
}
|
|
|
|
function controlCommand(result) {
|
|
|
|
MediaController.trySetActiveDeviceName(result.what);
|
|
}
|
|
|
|
function playCommand(result, shuffle) {
|
|
|
|
var query = {
|
|
|
|
Limit: result.limit || 100,
|
|
UserId: result.userId,
|
|
ExcludeLocationTypes: "Virtual"
|
|
};
|
|
|
|
if (result.category == 'nextup') {
|
|
|
|
ApiClient.getNextUpEpisodes(query).then(function (queryResult) {
|
|
|
|
playItems(queryResult.Items, shuffle);
|
|
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (shuffle) {
|
|
result.sortby = result.sortby ? 'Random,' + result.sortby : 'Random';
|
|
}
|
|
|
|
query.SortBy = result.sortby;
|
|
query.SortOrder = result.sortorder;
|
|
query.Recursive = true;
|
|
|
|
if (result.filters.indexOf('unplayed') != -1) {
|
|
query.IsPlayed = false;
|
|
}
|
|
if (result.filters.indexOf('played') != -1) {
|
|
query.IsPlayed = true;
|
|
}
|
|
if (result.filters.indexOf('favorite') != -1) {
|
|
query.Filters = 'IsFavorite';
|
|
}
|
|
|
|
if (result.itemType) {
|
|
query.IncludeItemTypes = result.itemType;
|
|
}
|
|
|
|
ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (queryResult) {
|
|
|
|
playItems(queryResult.Items, shuffle);
|
|
});
|
|
}
|
|
|
|
function playItems(items, shuffle) {
|
|
|
|
if (shuffle) {
|
|
items = shuffleArray(items);
|
|
}
|
|
|
|
items = items.map(function (i) {
|
|
return i.Id;
|
|
});
|
|
|
|
if (items.length) {
|
|
MediaController.play({
|
|
ids: items
|
|
});
|
|
} else {
|
|
Dashboard.alert({
|
|
message: Globalize.translate('MessageNoItemsFound')
|
|
});
|
|
}
|
|
}
|
|
|
|
function searchCommand(result) {
|
|
|
|
|
|
}
|
|
|
|
function renderSampleCommands(elem, commands) {
|
|
|
|
commands.length = Math.min(commands.length, 4);
|
|
|
|
commands = commands.map(function (c) {
|
|
|
|
return '<div class="exampleCommand"><span class="exampleCommandText">"' + c + '"</span></div>';
|
|
|
|
}).join('');
|
|
|
|
$('.exampleCommands', elem).html(commands);
|
|
}
|
|
|
|
var currentDialog;
|
|
function showVoiceHelp(paperDialogHelper) {
|
|
|
|
var dlg = paperDialogHelper.createDialog({
|
|
size: 'medium',
|
|
removeOnClose: true
|
|
});
|
|
|
|
var html = '';
|
|
html += '<h2 class="dialogHeader">';
|
|
html += '<paper-fab icon="arrow-back" mini class="btnCancelVoiceInput"></paper-fab>';
|
|
html += '</h2>';
|
|
|
|
html += '<div>';
|
|
|
|
var getCommandsPromise = getSampleCommands();
|
|
|
|
html += '<div class="voiceHelpContent">';
|
|
|
|
html += '<div class="defaultVoiceHelp">';
|
|
|
|
html += '<h1>' + Globalize.translate('HeaderSaySomethingLike') + '</h1>';
|
|
|
|
html += '<div class="exampleCommands">';
|
|
html += '</div>';
|
|
|
|
// defaultVoiceHelp
|
|
html += '</div>';
|
|
|
|
html += '<div class="unrecognizedCommand" style="display:none;">';
|
|
html += '<h1>' + Globalize.translate('HeaderYouSaid') + '</h1>';
|
|
html += '<p class="exampleCommand voiceInputContainer"><i class="fa fa-quote-left"></i><span class="voiceInputText exampleCommandText"></span><i class="fa fa-quote-right"></i></p>';
|
|
html += '<p>' + Globalize.translate('MessageWeDidntRecognizeCommand') + '</p>';
|
|
|
|
html += '<br/>';
|
|
html += '<paper-button raised class="submit block btnRetry"><iron-icon icon="mic"></iron-icon><span>' + Globalize.translate('ButtonTryAgain') + '</span></paper-button>';
|
|
html += '<p class="blockedMessage" style="display:none;">' + Globalize.translate('MessageIfYouBlockedVoice') + '<br/><br/></p>';
|
|
|
|
html += '</div>';
|
|
|
|
html += '<paper-button raised class="block btnCancelVoiceInput" style="background-color:#444;"><iron-icon icon="close"></iron-icon><span>' + Globalize.translate('ButtonCancel') + '</span></paper-button>';
|
|
|
|
// voiceHelpContent
|
|
html += '</div>';
|
|
|
|
html += '</div>';
|
|
|
|
dlg.innerHTML = html;
|
|
document.body.appendChild(dlg);
|
|
|
|
paperDialogHelper.open(dlg);
|
|
currentDialog = dlg;
|
|
|
|
dlg.addEventListener('iron-overlay-closed', function () {
|
|
currentDialog = null;
|
|
});
|
|
|
|
$('.btnCancelVoiceInput', dlg).on('click', function () {
|
|
destroyCurrentRecognition();
|
|
paperDialogHelper.close(dlg);
|
|
});
|
|
|
|
$('.btnRetry', dlg).on('click', function () {
|
|
$('.unrecognizedCommand').hide();
|
|
$('.defaultVoiceHelp').show();
|
|
startListening(false);
|
|
});
|
|
|
|
getCommandsPromise.then(function (commands) {
|
|
renderSampleCommands(dlg.querySelector('.voiceHelpContent'), commands);
|
|
});
|
|
}
|
|
|
|
function showUnrecognizedCommandHelp() {
|
|
|
|
$('.unrecognizedCommand').show();
|
|
$('.defaultVoiceHelp').hide();
|
|
}
|
|
|
|
function destroyCurrentRecognition() {
|
|
|
|
var recognition = currentRecognition;
|
|
if (recognition) {
|
|
recognition.cancelled = true;
|
|
recognition.abort();
|
|
currentRecognition = null;
|
|
}
|
|
}
|
|
|
|
function processTranscript(text, isCancelled) {
|
|
|
|
$('.voiceInputText').html(text);
|
|
|
|
if (text || AppInfo.isNativeApp) {
|
|
$('.blockedMessage').hide();
|
|
} else {
|
|
$('.blockedMessage').show();
|
|
}
|
|
|
|
if (text) {
|
|
processText(text).catch(showUnrecognizedCommandHelp);
|
|
} else if (!isCancelled) {
|
|
showUnrecognizedCommandHelp();
|
|
}
|
|
}
|
|
|
|
function startListening(createUI) {
|
|
|
|
destroyCurrentRecognition();
|
|
|
|
var recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
|
|
|
|
//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;
|
|
|
|
if (createUI !== false) {
|
|
require(['components/paperdialoghelper', 'paper-fab', 'css!voice/voice.css'], showVoiceHelp);
|
|
}
|
|
}
|
|
|
|
window.VoiceInputManager = {
|
|
|
|
isSupported: function () {
|
|
|
|
if (AppInfo.isNativeApp) {
|
|
// TODO: Only return false for crosswalk
|
|
return false;
|
|
}
|
|
|
|
return window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
},
|
|
|
|
startListening: startListening
|
|
};
|
|
|
|
})(); |