mirror of https://github.com/dessant/buster
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
13 KiB
Vue
547 lines
13 KiB
Vue
<template>
|
|
<div id="app" v-if="dataLoaded">
|
|
<div class="section">
|
|
<div class="section-title" v-once>
|
|
{{ getText('optionSectionTitle_services') }}
|
|
</div>
|
|
<div class="option-wrap">
|
|
<div class="option select">
|
|
<v-select
|
|
:label="getText('optionTitle_speechService')"
|
|
v-model="options.speechService"
|
|
:options="selectOptions.speechService"
|
|
>
|
|
</v-select>
|
|
</div>
|
|
|
|
<div
|
|
class="option text-field"
|
|
v-if="options.speechService === 'googleSpeechApi'"
|
|
>
|
|
<v-textfield
|
|
v-model.trim="options.googleSpeechApiKey"
|
|
:label="getText('inputLabel_apiKey')"
|
|
>
|
|
</v-textfield>
|
|
</div>
|
|
|
|
<div
|
|
class="option select"
|
|
v-if="options.speechService === 'ibmSpeechApi'"
|
|
>
|
|
<v-select
|
|
:label="getText('optionTitle_ibmSpeechApiLoc')"
|
|
v-model="options.ibmSpeechApiLoc"
|
|
:options="selectOptions.ibmSpeechApiLoc"
|
|
>
|
|
</v-select>
|
|
</div>
|
|
<div
|
|
class="option text-field"
|
|
v-if="options.speechService === 'ibmSpeechApi'"
|
|
>
|
|
<v-textfield
|
|
v-model.trim="options.ibmSpeechApiKey"
|
|
:label="getText('inputLabel_apiKey')"
|
|
>
|
|
</v-textfield>
|
|
</div>
|
|
|
|
<a
|
|
class="service-guide"
|
|
v-if="options.speechService === 'ibmSpeechApi'"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
href="https://github.com/dessant/buster/wiki/Configuring-IBM-Watson-Speech-to-Text"
|
|
>
|
|
{{ getText('linkText_apiGuide') }}
|
|
</a>
|
|
|
|
<div
|
|
class="option select"
|
|
v-if="options.speechService === 'microsoftSpeechApi'"
|
|
>
|
|
<v-select
|
|
:label="getText('optionTitle_microsoftSpeechApiLoc')"
|
|
v-model="options.microsoftSpeechApiLoc"
|
|
:options="selectOptions.microsoftSpeechApiLoc"
|
|
>
|
|
</v-select>
|
|
</div>
|
|
<div
|
|
class="option text-field"
|
|
v-if="options.speechService === 'microsoftSpeechApi'"
|
|
>
|
|
<v-textfield
|
|
v-model.trim="options.microsoftSpeechApiKey"
|
|
:label="getText('inputLabel_apiKey')"
|
|
>
|
|
</v-textfield>
|
|
</div>
|
|
|
|
<v-textfield
|
|
v-if="options.speechService === 'witSpeechApi'"
|
|
v-for="item in witSpeechApis"
|
|
:key="item.id"
|
|
:value="options.witSpeechApiKeys[item] || ''"
|
|
:label="
|
|
getText('inputLabel_apiKeyType', [
|
|
getText(`optionValue_witSpeechApiLang_${item}`)
|
|
])
|
|
"
|
|
@input="saveWitSpeechApiKey($event.trim(), item)"
|
|
>
|
|
</v-textfield>
|
|
<div
|
|
class="wit-add-api"
|
|
v-if="options.speechService === 'witSpeechApi'"
|
|
>
|
|
<v-select
|
|
v-model="witSpeechApiLang"
|
|
:options="selectOptions.witSpeechApiLang"
|
|
:label="getText('optionTitle_witSpeechApiLang')"
|
|
>
|
|
</v-select>
|
|
<v-button
|
|
:outlined="true"
|
|
:disabled="!witSpeechApiLang"
|
|
:label="getText('buttonText_addApi')"
|
|
@click="addWitSpeechApi"
|
|
>
|
|
</v-button>
|
|
</div>
|
|
|
|
<a
|
|
class="service-guide"
|
|
v-if="options.speechService === 'witSpeechApi'"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
href="https://github.com/dessant/buster/wiki/Configuring-Wit.ai"
|
|
>
|
|
{{ getText('linkText_apiGuide') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title" v-once>
|
|
{{ getText('optionSectionTitle_client') }}
|
|
</div>
|
|
<div class="section-desc" v-once>
|
|
{{ getText('optionSectionDescription_client') }}
|
|
</div>
|
|
<div class="option-wrap">
|
|
<div
|
|
class="option"
|
|
v-if="
|
|
clientAppInstalled ||
|
|
(clientAppVerified && options.simulateUserInput)
|
|
"
|
|
>
|
|
<v-form-field
|
|
input-id="si"
|
|
:label="getText('optionTitle_simulateUserInput')"
|
|
>
|
|
<v-switch id="si" v-model="options.simulateUserInput"></v-switch>
|
|
</v-form-field>
|
|
</div>
|
|
|
|
<div
|
|
class="option"
|
|
v-if="clientAppVerified && options.simulateUserInput"
|
|
>
|
|
<v-form-field
|
|
input-id="nc"
|
|
:label="getText('optionTitle_navigateWithKeyboard')"
|
|
>
|
|
<v-switch id="nc" v-model="options.navigateWithKeyboard"></v-switch>
|
|
</v-form-field>
|
|
</div>
|
|
|
|
<div class="option" v-if="clientAppInstalled">
|
|
<v-form-field
|
|
input-id="auc"
|
|
:label="getText('optionTitle_autoUpdateClientApp')"
|
|
>
|
|
<v-switch id="auc" v-model="options.autoUpdateClientApp"></v-switch>
|
|
</v-form-field>
|
|
</div>
|
|
|
|
<div
|
|
class="client-download"
|
|
v-if="clientAppVerified && !clientAppInstalled"
|
|
>
|
|
<div
|
|
class="download-desc"
|
|
v-html="
|
|
getText('pageContent_optionClientAppDownloadDesc', [
|
|
`<a target='_blank' rel='noreferrer' href='${installGuideUrl}'>${getText(
|
|
'linkText_installGuide'
|
|
)}</a>`
|
|
])
|
|
"
|
|
></div>
|
|
<div class="download-error" v-if="!clientAppDownloadUrl">
|
|
{{ getText('pageContent_optionClientAppOSError') }}
|
|
</div>
|
|
|
|
<v-button
|
|
class="download-button"
|
|
:unelevated="true"
|
|
:disabled="!clientAppDownloadUrl"
|
|
:label="getText('buttonText_downloadApp')"
|
|
@click="$refs.dlLink.click()"
|
|
>
|
|
</v-button>
|
|
<a
|
|
ref="dlLink"
|
|
class="download-link"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
:href="clientAppDownloadUrl"
|
|
></a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<div class="section-title" v-once>
|
|
{{ getText('optionSectionTitle_misc') }}
|
|
</div>
|
|
<div class="option-wrap">
|
|
<div class="option">
|
|
<v-form-field
|
|
input-id="lec"
|
|
:label="getText('optionTitle_loadEnglishChallenge')"
|
|
>
|
|
<v-switch
|
|
id="lec"
|
|
v-model="options.loadEnglishChallenge"
|
|
></v-switch>
|
|
</v-form-field>
|
|
</div>
|
|
|
|
<div class="option" v-if="!options.loadEnglishChallenge">
|
|
<v-form-field
|
|
input-id="esm"
|
|
:label="getText('optionTitle_tryEnglishSpeechModel')"
|
|
>
|
|
<v-switch
|
|
id="esm"
|
|
v-model="options.tryEnglishSpeechModel"
|
|
></v-switch>
|
|
</v-form-field>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import browser from 'webextension-polyfill';
|
|
import {Button, Select, Switch, FormField, TextField} from 'ext-components';
|
|
|
|
import storage from 'storage/storage';
|
|
import {getOptionLabels, pingClientApp} from 'utils/app';
|
|
import {getText, getPlatform} from 'utils/common';
|
|
import {clientAppVersion} from 'utils/config';
|
|
import {
|
|
optionKeys,
|
|
clientAppPlatforms,
|
|
captchaWitSpeechApiLangCodes
|
|
} from 'utils/data';
|
|
|
|
export default {
|
|
components: {
|
|
[Button.name]: Button,
|
|
[Select.name]: Select,
|
|
[Switch.name]: Switch,
|
|
[FormField.name]: FormField,
|
|
[TextField.name]: TextField
|
|
},
|
|
|
|
data: function () {
|
|
return {
|
|
dataLoaded: false,
|
|
|
|
selectOptions: getOptionLabels({
|
|
speechService: [
|
|
'witSpeechApiDemo',
|
|
'googleSpeechApi',
|
|
'witSpeechApi',
|
|
'ibmSpeechApi',
|
|
'microsoftSpeechApi'
|
|
],
|
|
ibmSpeechApiLoc: [
|
|
'seoul',
|
|
'london',
|
|
'frankfurt',
|
|
'dallas',
|
|
'washington',
|
|
'sydney',
|
|
'tokyo'
|
|
],
|
|
microsoftSpeechApiLoc: [
|
|
'eastAu',
|
|
'centralCa',
|
|
'centralUs',
|
|
'centralFr',
|
|
'centralIn',
|
|
'eastJp',
|
|
'centralKr',
|
|
'northCentralUs',
|
|
'southCentralUs',
|
|
'southUk',
|
|
'eastUs',
|
|
'eastUs2',
|
|
'westUs',
|
|
'westUs2',
|
|
'eastAsia',
|
|
'southeastAsia',
|
|
'westEu',
|
|
'northEu'
|
|
],
|
|
witSpeechApiLang: [
|
|
...new Set(
|
|
Object.values(captchaWitSpeechApiLangCodes).filter(Boolean)
|
|
)
|
|
].sort()
|
|
}),
|
|
|
|
witSpeechApiLang: '',
|
|
witSpeechApis: [],
|
|
|
|
clientAppVerified: false,
|
|
clientAppInstalled: false,
|
|
clientAppDownloadUrl: '',
|
|
installGuideUrl: '',
|
|
|
|
options: {
|
|
speechService: '',
|
|
googleSpeechApiKey: '',
|
|
ibmSpeechApiLoc: '',
|
|
ibmSpeechApiKey: '',
|
|
microsoftSpeechApiLoc: '',
|
|
microsoftSpeechApiKey: '',
|
|
witSpeechApiKeys: {},
|
|
loadEnglishChallenge: false,
|
|
tryEnglishSpeechModel: false,
|
|
simulateUserInput: false,
|
|
autoUpdateClientApp: false,
|
|
navigateWithKeyboard: false
|
|
}
|
|
};
|
|
},
|
|
|
|
methods: {
|
|
getText,
|
|
|
|
verifyClientApp: async function () {
|
|
try {
|
|
await pingClientApp();
|
|
this.clientAppInstalled = true;
|
|
} catch (err) {
|
|
if (!this.installGuideUrl) {
|
|
this.installGuideUrl =
|
|
'https://github.com/dessant/buster/wiki/Installing-the-client-app';
|
|
const {os, arch} = await getPlatform();
|
|
if (clientAppPlatforms.includes(`${os}/${arch}`)) {
|
|
this.installGuideUrl += `#${os}`;
|
|
this.clientAppDownloadUrl = `https://github.com/dessant/buster-client/releases/download/v${clientAppVersion}/buster-client-setup-v${clientAppVersion}-${os}-${arch}`;
|
|
if (os === 'windows') {
|
|
this.clientAppDownloadUrl += '.exe';
|
|
}
|
|
}
|
|
}
|
|
|
|
this.clientAppInstalled = false;
|
|
}
|
|
|
|
this.clientAppVerified = true;
|
|
},
|
|
|
|
setWitSpeechApiLangOptions: function () {
|
|
this.selectOptions.witSpeechApiLang = this.selectOptions.witSpeechApiLang.filter(
|
|
item => !this.witSpeechApis.includes(item.id)
|
|
);
|
|
},
|
|
|
|
addWitSpeechApi: function () {
|
|
this.witSpeechApis.push(this.witSpeechApiLang);
|
|
this.witSpeechApiLang = '';
|
|
this.setWitSpeechApiLangOptions();
|
|
},
|
|
|
|
saveWitSpeechApiKey: function (value, lang) {
|
|
const apiKeys = this.options.witSpeechApiKeys;
|
|
if (value) {
|
|
this.options.witSpeechApiKeys = Object.assign({}, apiKeys, {
|
|
[lang]: value
|
|
});
|
|
} else if (apiKeys[lang]) {
|
|
delete apiKeys[lang];
|
|
this.options.witSpeechApiKeys = Object.assign({}, apiKeys);
|
|
}
|
|
}
|
|
},
|
|
|
|
created: async function () {
|
|
const options = await storage.get(optionKeys, 'sync');
|
|
|
|
for (const option of Object.keys(this.options)) {
|
|
this.options[option] = options[option];
|
|
this.$watch(`options.${option}`, async function (value) {
|
|
await storage.set({[option]: value}, 'sync');
|
|
});
|
|
}
|
|
|
|
this.witSpeechApis = Object.keys(options.witSpeechApiKeys);
|
|
this.setWitSpeechApiLangOptions();
|
|
|
|
document.title = getText('pageTitle', [
|
|
getText('pageTitle_options'),
|
|
getText('extensionName')
|
|
]);
|
|
|
|
this.verifyClientApp();
|
|
|
|
this.dataLoaded = true;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
$mdc-theme-primary: #1abc9c;
|
|
|
|
@import '@material/select/mdc-select';
|
|
@import '@material/theme/mixins';
|
|
@import '@material/typography/mixins';
|
|
@import '@material/button/mixins';
|
|
|
|
body {
|
|
margin: 0;
|
|
@include mdc-typography-base;
|
|
font-size: 100%;
|
|
background-color: #ffffff;
|
|
overflow: visible !important;
|
|
}
|
|
|
|
#app {
|
|
display: grid;
|
|
grid-row-gap: 32px;
|
|
padding: 24px;
|
|
}
|
|
|
|
.mdc-switch {
|
|
margin-right: 16px;
|
|
}
|
|
|
|
.section-title,
|
|
.section-desc {
|
|
@include mdc-theme-prop(color, text-primary-on-light);
|
|
}
|
|
|
|
.section-title {
|
|
@include mdc-typography(headline6);
|
|
}
|
|
|
|
.section-desc {
|
|
@include mdc-typography(body2);
|
|
padding-top: 8px;
|
|
max-width: 380px;
|
|
}
|
|
|
|
.option-wrap {
|
|
display: grid;
|
|
grid-row-gap: 24px;
|
|
padding-top: 24px;
|
|
grid-auto-columns: min-content;
|
|
}
|
|
|
|
.option {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 24px;
|
|
|
|
& .mdc-form-field {
|
|
max-width: calc(100vw - 48px);
|
|
|
|
& label {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
}
|
|
|
|
.option {
|
|
&.select,
|
|
&.text-field {
|
|
height: 56px;
|
|
}
|
|
}
|
|
|
|
.option.select {
|
|
align-items: start;
|
|
|
|
& .mdc-select__anchor,
|
|
& .mdc-select__menu {
|
|
max-width: calc(100vw - 48px);
|
|
}
|
|
|
|
& .mdc-select__selected-text {
|
|
overflow: hidden;
|
|
white-space: nowrap;
|
|
text-overflow: ellipsis;
|
|
}
|
|
}
|
|
|
|
.wit-add-api {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
.wit-add-api > button {
|
|
margin-left: 24px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.service-guide {
|
|
@include mdc-typography(body1);
|
|
}
|
|
|
|
.client-download {
|
|
min-width: 300px;
|
|
}
|
|
|
|
.download-desc,
|
|
.download-error {
|
|
@include mdc-theme-prop(color, text-primary-on-light);
|
|
@include mdc-typography(body2);
|
|
}
|
|
|
|
.download-desc a {
|
|
@include mdc-typography(body2);
|
|
}
|
|
|
|
.download-desc {
|
|
max-width: 240px;
|
|
}
|
|
|
|
.download-error {
|
|
margin-top: 12px;
|
|
color: #e74c3c;
|
|
}
|
|
|
|
.download-link {
|
|
visibility: hidden;
|
|
}
|
|
|
|
.download-button {
|
|
@include mdc-button-ink-color(#fff);
|
|
width: 200px;
|
|
height: 48px;
|
|
margin-top: 24px;
|
|
}
|
|
</style>
|