|
@@ -28,71 +28,95 @@ Object.assign(Date.prototype, {
|
|
|
return this.toLocaleString(undefined, opt);
|
|
|
},
|
|
|
});
|
|
|
-function handleNVSVisible(){
|
|
|
+function get_control_option_value(obj) {
|
|
|
+ let ctrl,id,val,opt;
|
|
|
+ let radio = false;
|
|
|
+ let checked = false;
|
|
|
+ if (typeof (obj) === 'string') {
|
|
|
+ id = obj;
|
|
|
+ ctrl = $(`#${id}`);
|
|
|
+ } else {
|
|
|
+ id = $(obj).attr('id');
|
|
|
+ ctrl = $(obj);
|
|
|
+ }
|
|
|
+ if(ctrl.attr('type') === 'checkbox'){
|
|
|
+ opt = $(obj).checked?id.replace('cmd_opt_', ''):'';
|
|
|
+ val = true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ opt = id.replace('cmd_opt_', '');
|
|
|
+ val = $(obj).val();
|
|
|
+ val = `${val.includes(" ") ? '"' : ''}${val}${val.includes(" ") ? '"' : ''}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ return { opt, val };
|
|
|
+}
|
|
|
+function handleNVSVisible() {
|
|
|
let nvs_previous_checked = isEnabled(Cookies.get("show-nvs"));
|
|
|
- $('input#show-nvs')[0].checked = nvs_previous_checked ;
|
|
|
+ $('input#show-nvs')[0].checked = nvs_previous_checked;
|
|
|
if ($('input#show-nvs')[0].checked || recovery) {
|
|
|
- $('*[href*="-nvs"]').show();
|
|
|
- } else {
|
|
|
- $('*[href*="-nvs"]').hide();
|
|
|
+ $('*[href*="-nvs"]').show();
|
|
|
+ } else {
|
|
|
+ $('*[href*="-nvs"]').hide();
|
|
|
+ }
|
|
|
+}
|
|
|
+function concatenateOptions(options) {
|
|
|
+ let commandLine = ' ';
|
|
|
+ for (const [option, value] of Object.entries(options)) {
|
|
|
+ if (option !== 'n' && option !== 'o') {
|
|
|
+ commandLine += `-${option} `;
|
|
|
+ if (value !== true) {
|
|
|
+ commandLine += `${value} `;
|
|
|
+ }
|
|
|
}
|
|
|
+ }
|
|
|
+ return commandLine;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
function isEnabled(val) {
|
|
|
- return val!=undefined && typeof val === 'string' && val.match("[Yy1]");
|
|
|
+ return val != undefined && typeof val === 'string' && val.match("[Yy1]");
|
|
|
}
|
|
|
|
|
|
const nvsTypes = {
|
|
|
NVS_TYPE_U8: 0x01,
|
|
|
-
|
|
|
/*! < Type uint8_t */
|
|
|
NVS_TYPE_I8: 0x11,
|
|
|
-
|
|
|
/*! < Type int8_t */
|
|
|
NVS_TYPE_U16: 0x02,
|
|
|
-
|
|
|
/*! < Type uint16_t */
|
|
|
NVS_TYPE_I16: 0x12,
|
|
|
-
|
|
|
/*! < Type int16_t */
|
|
|
NVS_TYPE_U32: 0x04,
|
|
|
-
|
|
|
/*! < Type uint32_t */
|
|
|
NVS_TYPE_I32: 0x14,
|
|
|
-
|
|
|
/*! < Type int32_t */
|
|
|
NVS_TYPE_U64: 0x08,
|
|
|
-
|
|
|
/*! < Type uint64_t */
|
|
|
NVS_TYPE_I64: 0x18,
|
|
|
-
|
|
|
/*! < Type int64_t */
|
|
|
NVS_TYPE_STR: 0x21,
|
|
|
-
|
|
|
/*! < Type string */
|
|
|
NVS_TYPE_BLOB: 0x42,
|
|
|
-
|
|
|
/*! < Type blob */
|
|
|
NVS_TYPE_ANY: 0xff /*! < Must be last */,
|
|
|
};
|
|
|
const btIcons = {
|
|
|
- bt_playing: {'label':'','icon': 'media_bluetooth_on'},
|
|
|
- bt_disconnected: {'label':'','icon': 'media_bluetooth_off'},
|
|
|
- bt_neutral: {'label':'','icon': 'bluetooth'},
|
|
|
- bt_connecting: {'label':'','icon': 'bluetooth_searching'},
|
|
|
- bt_connected: {'label':'','icon': 'bluetooth_connected'},
|
|
|
- bt_disabled: {'label':'','icon': 'bluetooth_disabled'},
|
|
|
- play_arrow: {'label':'','icon': 'play_circle_filled'},
|
|
|
- pause: {'label':'','icon': 'pause_circle'},
|
|
|
- stop: {'label':'','icon': 'stop_circle'},
|
|
|
- '': {'label':'','icon':''}
|
|
|
+ bt_playing: { 'label': '', 'icon': 'media_bluetooth_on' },
|
|
|
+ bt_disconnected: { 'label': '', 'icon': 'media_bluetooth_off' },
|
|
|
+ bt_neutral: { 'label': '', 'icon': 'bluetooth' },
|
|
|
+ bt_connecting: { 'label': '', 'icon': 'bluetooth_searching' },
|
|
|
+ bt_connected: { 'label': '', 'icon': 'bluetooth_connected' },
|
|
|
+ bt_disabled: { 'label': '', 'icon': 'bluetooth_disabled' },
|
|
|
+ play_arrow: { 'label': '', 'icon': 'play_circle_filled' },
|
|
|
+ pause: { 'label': '', 'icon': 'pause_circle' },
|
|
|
+ stop: { 'label': '', 'icon': 'stop_circle' },
|
|
|
+ '': { 'label': '', 'icon': '' }
|
|
|
};
|
|
|
const batIcons = [
|
|
|
- { icon: "battery_0_bar", label:'▪', ranges: [{ f: 5.8, t: 6.8 }, { f: 8.8, t: 10.2 }] },
|
|
|
- { icon: "battery_2_bar", label:'▪▪', ranges: [{ f: 6.8, t: 7.4 }, { f: 10.2, t: 11.1 }] },
|
|
|
- { icon: "battery_3_bar", label:'▪▪▪', ranges: [{ f: 7.4, t: 7.5 }, { f: 11.1, t: 11.25 }] },
|
|
|
- { icon: "battery_4_bar", label:'▪▪▪▪', ranges: [{ f: 7.5, t: 7.8 }, { f: 11.25, t: 11.7 }] }
|
|
|
+ { icon: "battery_0_bar", label: '▪', ranges: [{ f: 5.8, t: 6.8 }, { f: 8.8, t: 10.2 }] },
|
|
|
+ { icon: "battery_2_bar", label: '▪▪', ranges: [{ f: 6.8, t: 7.4 }, { f: 10.2, t: 11.1 }] },
|
|
|
+ { icon: "battery_3_bar", label: '▪▪▪', ranges: [{ f: 7.4, t: 7.5 }, { f: 11.1, t: 11.25 }] },
|
|
|
+ { icon: "battery_4_bar", label: '▪▪▪▪', ranges: [{ f: 7.5, t: 7.8 }, { f: 11.25, t: 11.7 }] }
|
|
|
];
|
|
|
const btStateIcons = [
|
|
|
{ desc: 'Idle', sub: ['bt_neutral'] },
|
|
@@ -162,7 +186,7 @@ let flashState = {
|
|
|
$('.flact').prop('disabled', false);
|
|
|
$('#flashfilename').value = null;
|
|
|
$('#fw-url-input').value = null;
|
|
|
- if(!this.isStateError()){
|
|
|
+ if (!this.isStateError()) {
|
|
|
$('span#flash-status').html('');
|
|
|
$('#fwProgressLabel').parent().removeClass('bg-danger');
|
|
|
}
|
|
@@ -357,8 +381,8 @@ let flashState = {
|
|
|
const xhttp = new XMLHttpRequest();
|
|
|
xhttp.context = this;
|
|
|
var boundHandleUploadProgressEvent = this.HandleUploadProgressEvent.bind(this);
|
|
|
- var boundsetOTAError=this.setOTAError.bind(this);
|
|
|
- xhttp.upload.addEventListener("progress",boundHandleUploadProgressEvent, false);
|
|
|
+ var boundsetOTAError = this.setOTAError.bind(this);
|
|
|
+ xhttp.upload.addEventListener("progress", boundHandleUploadProgressEvent, false);
|
|
|
xhttp.onreadystatechange = function () {
|
|
|
if (xhttp.readyState === 4) {
|
|
|
if (xhttp.status === 0 || xhttp.status === 404) {
|
|
@@ -464,11 +488,89 @@ window.handleReboot = function (link) {
|
|
|
$('#reboot_nav').removeClass('active'); delayReboot(500, '', link);
|
|
|
}
|
|
|
}
|
|
|
-function isConnected(){
|
|
|
- return ConnectedTo.hasOwnProperty('ip') && ConnectedTo.ip!='0.0.0.0'&& ConnectedTo.ip!='';
|
|
|
+
|
|
|
+function parseSqueezeliteCommandLine(commandLine) {
|
|
|
+ const options = {};
|
|
|
+ let output, name;
|
|
|
+ let otherValues = '';
|
|
|
+
|
|
|
+ const argRegex = /("[^"]+"|'[^']+'|\S+)/g;
|
|
|
+ const args = commandLine.match(argRegex);
|
|
|
+
|
|
|
+ let i = 0;
|
|
|
+
|
|
|
+ while (i < args.length) {
|
|
|
+ const arg = args[i];
|
|
|
+
|
|
|
+ if (arg.startsWith('-')) {
|
|
|
+ const option = arg.slice(1);
|
|
|
+
|
|
|
+ if (option === '') {
|
|
|
+ otherValues += args.slice(i).join(' ');
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ let value = true;
|
|
|
+
|
|
|
+ if (i + 1 < args.length && !args[i + 1].startsWith('-')) {
|
|
|
+ value = args[i + 1].replace(/"/g, '').replace(/'/g, '');
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ options[option] = value;
|
|
|
+ } else {
|
|
|
+ otherValues += arg + ' ';
|
|
|
+ }
|
|
|
+
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+ otherValues = otherValues.trim();
|
|
|
+ output = getOutput(options);
|
|
|
+ name = getName(options);
|
|
|
+ let otherOptions={btname:null,n:null};
|
|
|
+ // assign o and n options to otheroptions if present
|
|
|
+ if (options.o && output.toUpperCase() === 'BT') {
|
|
|
+ let temp = parseSqueezeliteCommandLine(options.o);
|
|
|
+ if(temp.name) {
|
|
|
+ otherOptions.btname = temp.name;
|
|
|
+ }
|
|
|
+ delete options.o;
|
|
|
+ }
|
|
|
+ if (options.n) {
|
|
|
+ otherOptions['n'] = options.n;
|
|
|
+ delete options.n;
|
|
|
+ }
|
|
|
+ return { name, output, options, otherValues,otherOptions };
|
|
|
+}
|
|
|
+
|
|
|
+function getOutput(options) {
|
|
|
+ let output;
|
|
|
+ if (options.o){
|
|
|
+ output = options.o.replace(/"/g, '').replace(/'/g, '');
|
|
|
+ /* set output as the first alphanumerical word in the command line */
|
|
|
+ if (output.indexOf(' ') > 0) {
|
|
|
+ output = output.substring(0, output.indexOf(' '));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return output;
|
|
|
+}
|
|
|
+
|
|
|
+function getName(options) {
|
|
|
+ let name;
|
|
|
+ /* if n option present, assign to name variable */
|
|
|
+ if (options.n){
|
|
|
+ name = options.n.replace(/"/g, '').replace(/'/g, '');
|
|
|
+ }
|
|
|
+ return name;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function isConnected() {
|
|
|
+ return ConnectedTo.hasOwnProperty('ip') && ConnectedTo.ip != '0.0.0.0' && ConnectedTo.ip != '';
|
|
|
}
|
|
|
-function getIcon(icons){
|
|
|
- return isConnected()?icons.icon:icons.label;
|
|
|
+function getIcon(icons) {
|
|
|
+ return isConnected() ? icons.icon : icons.label;
|
|
|
}
|
|
|
function handlebtstate(data) {
|
|
|
let icon = '';
|
|
@@ -476,7 +578,7 @@ function handlebtstate(data) {
|
|
|
if (data.bt_status !== undefined && data.bt_sub_status !== undefined) {
|
|
|
const iconindex = btStateIcons[data.bt_status].sub[data.bt_sub_status];
|
|
|
if (iconindex) {
|
|
|
- icon = btIcons[iconindex];
|
|
|
+ icon = btIcons[iconindex];
|
|
|
tt = btStateIcons[data.bt_status].desc;
|
|
|
} else {
|
|
|
icon = btIcons.bt_connected;
|
|
@@ -485,19 +587,28 @@ function handlebtstate(data) {
|
|
|
}
|
|
|
|
|
|
$('#o_type').attr('title', tt);
|
|
|
- $('#o_bt').html(isConnected()?icon.label:icon.text);
|
|
|
+ $('#o_bt').html(isConnected() ? icon.label : icon.text);
|
|
|
}
|
|
|
function handleTemplateTypeRadio(outtype) {
|
|
|
$('#o_type').children('span').css({ display: 'none' });
|
|
|
+ let changed = false;
|
|
|
if (outtype === 'bt') {
|
|
|
+ changed = output !== 'bt' && output !== '';
|
|
|
output = 'bt';
|
|
|
} else if (outtype === 'spdif') {
|
|
|
+ changed = output !== 'spdif' && output !== '';
|
|
|
output = 'spdif';
|
|
|
} else {
|
|
|
+ changed = output !== 'i2s' && output !== '';
|
|
|
output = 'i2s';
|
|
|
}
|
|
|
$('#' + output).prop('checked', true);
|
|
|
$('#o_' + output).css({ display: 'inline' });
|
|
|
+ if (changed) {
|
|
|
+ Object.keys(commandDefaults[output]).forEach(function (key) {
|
|
|
+ $(`#cmd_opt_${key}`).val(commandDefaults[output][key]);
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
function handleExceptionResponse(xhr, _ajaxOptions, thrownError) {
|
|
@@ -545,7 +656,17 @@ let releaseURL =
|
|
|
|
|
|
let recovery = false;
|
|
|
let messagesHeld = false;
|
|
|
-const commandHeader = 'squeezelite -b 500:2000 -d all=info -C 30 -W';
|
|
|
+let commandBTSinkName = '';
|
|
|
+const commandHeader = 'squeezelite ';
|
|
|
+const commandDefaults = {
|
|
|
+ i2s: { b: "500:2000", C: "30", W: "", Z: "96000", o: "I2S" },
|
|
|
+ spdif: { b: "500:2000", C: "30", W: "", Z: "48000", o: "SPDIF" },
|
|
|
+ bt: { b: "500:2000", C: "30", W: "", Z: "44100", o: "BT" },
|
|
|
+};
|
|
|
+let validOptions = {
|
|
|
+ codecs: ['flac', 'pcm', 'mp3', 'ogg', 'aac', 'wma', 'alac', 'dsd', 'mad', 'mpg']
|
|
|
+};
|
|
|
+
|
|
|
//let blockFlashButton = false;
|
|
|
let apList = null;
|
|
|
//let selectedSSID = '';
|
|
@@ -559,6 +680,7 @@ let hostName = '';
|
|
|
let versionName = 'Squeezelite-ESP32';
|
|
|
let prevmessage = '';
|
|
|
let project_name = versionName;
|
|
|
+let depth = 16;
|
|
|
let board_model = '';
|
|
|
let platform_name = versionName;
|
|
|
let preset_name = '';
|
|
@@ -690,11 +812,6 @@ function handleHWPreset(allfields, reboot) {
|
|
|
}
|
|
|
},
|
|
|
});
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
}
|
|
|
|
|
|
|
|
@@ -773,23 +890,34 @@ function delayReboot(duration, cmdname, ota = 'reboot') {
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
window.saveAutoexec1 = function (apply) {
|
|
|
showCmdMessage('cfg-audio-tmpl', 'MESSAGING_INFO', 'Saving.\n', false);
|
|
|
- let commandLine = commandHeader + ' -n "' + $('#player').val() + '"';
|
|
|
+ let commandLine = `${commandHeader} -o ${output} `;
|
|
|
+ $('.sqcmd').each(function () {
|
|
|
+ let { opt, val } = get_control_option_value($(this));
|
|
|
+ if ((opt && opt.length>0 ) && typeof(val) == 'boolean' || val.length > 0) {
|
|
|
+ const optStr=opt===':'?opt:(` -${opt} `);
|
|
|
+ val = typeof(val) == 'boolean'?'':val;
|
|
|
+ commandLine += `${optStr} ${val}`;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const resample=$('#cmd_opt_R input[name=resample]:checked');
|
|
|
+ if (resample.length>0 && resample.attr('suffix')!=='') {
|
|
|
+ commandLine += resample.attr('suffix');
|
|
|
+ // now check resample_i option and if checked, add suffix to command line
|
|
|
+ if ($('#resample_i').is(":checked") && resample.attr('aint') =='true') {
|
|
|
+ commandLine += $('#resample_i').attr('suffix');
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
if (output === 'bt') {
|
|
|
- commandLine += ' -o "BT" -R -Z 192000';
|
|
|
showCmdMessage(
|
|
|
'cfg-audio-tmpl',
|
|
|
'MESSAGING_INFO',
|
|
|
'Remember to configure the Bluetooth audio device name.\n',
|
|
|
true
|
|
|
);
|
|
|
- } else if (output === 'spdif') {
|
|
|
- commandLine += ' -o SPDIF -Z 192000';
|
|
|
- } else {
|
|
|
- commandLine += ' -o I2S';
|
|
|
- }
|
|
|
- if ($('#optional').val() !== '') {
|
|
|
- commandLine += ' ' + $('#optional').val();
|
|
|
}
|
|
|
+ commandLine += concatenateOptions(options);
|
|
|
const data = {
|
|
|
timestamp: Date.now(),
|
|
|
};
|
|
@@ -880,9 +1008,33 @@ window.handleConnect = function () {
|
|
|
// now we can re-set the intervals regardless of result
|
|
|
|
|
|
}
|
|
|
+function renderError(opt,error){
|
|
|
+ const fieldname = `cmd_opt_${opt}`;
|
|
|
+ let errorFieldName=`${fieldname}-error`;
|
|
|
+ let errorField=$(`#${errorFieldName}`);
|
|
|
+ let field=$(`#${fieldname}`);
|
|
|
+
|
|
|
+ if (!errorField || errorField.length ==0) {
|
|
|
+ field.after(`<div id="${errorFieldName}" class="invalid-feedback"></div>`);
|
|
|
+ errorField=$(`#${errorFieldName}`);
|
|
|
+ }
|
|
|
+ if(error.length ==0){
|
|
|
+ errorField.hide();
|
|
|
+ field.removeClass('is-invalid');
|
|
|
+ field.addClass('is-valid');
|
|
|
+ errorField.text('');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ errorField.show();
|
|
|
+ errorField.text(error);
|
|
|
+ field.removeClass('is-valid');
|
|
|
+ field.addClass('is-invalid');
|
|
|
+ }
|
|
|
+ return errorField;
|
|
|
+}
|
|
|
$(document).ready(function () {
|
|
|
$('.material-icons').each(function (_index, entry) {
|
|
|
- entry.attributes['icon']=entry.textContent;
|
|
|
+ entry.attributes['icon'] = entry.textContent;
|
|
|
});
|
|
|
setIcons(true);
|
|
|
handleNVSVisible();
|
|
@@ -908,6 +1060,43 @@ $(document).ready(function () {
|
|
|
|
|
|
});
|
|
|
setTimeout(refreshAP, 1500);
|
|
|
+ /* add validation for cmd_opt_c, which accepts a comma separated list.
|
|
|
+ getting known codecs from validOptions.codecs array
|
|
|
+ use bootstrap classes to highlight the error with an overlay message */
|
|
|
+ $('#options input').on('input', function () {
|
|
|
+ const { opt, val } = get_control_option_value(this);
|
|
|
+ if (opt === 'c' || opt === 'e') {
|
|
|
+ const fieldname = `cmd_opt_${opt}_codec-error`;
|
|
|
+
|
|
|
+ const values = val.split(',').map(function (item) {
|
|
|
+ return item.trim();
|
|
|
+ });
|
|
|
+ /* get a list of invalid codecs */
|
|
|
+ const invalid = values.filter(function (item) {
|
|
|
+ return !validOptions.codecs.includes(item);
|
|
|
+ });
|
|
|
+ renderError(opt,invalid.length > 0 ? `Invalid codec(s) ${invalid.join(', ')}` : '');
|
|
|
+ }
|
|
|
+ /* add validation for cmd_opt_m, which accepts a mac_address */
|
|
|
+ if (opt === 'm') {
|
|
|
+ const mac_regex = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/;
|
|
|
+ renderError(opt,mac_regex.test(val) ? '' : 'Invalid MAC address');
|
|
|
+ }
|
|
|
+ if (opt === 'r') {
|
|
|
+ const rateRegex = /^(\d+\.?\d*|\.\d+)-(\d+\.?\d*|\.\d+)$|^(\d+\.?\d*)$|^(\d+\.?\d*,)+\d+\.?\d*$/;
|
|
|
+ renderError(opt,rateRegex.test(val)?'':`Invalid rate(s) ${val}. Acceptable format: <maxrate>|<minrate>-<maxrate>|<rate1>,<rate2>,<rate3>`);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ );
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
$('#WifiConnectDialog')[0].addEventListener('shown.bs.modal', function (event) {
|
|
|
$("*[class*='connecting']").hide();
|
|
@@ -1029,7 +1218,7 @@ $(document).ready(function () {
|
|
|
|
|
|
$('input#show-nvs').on('click', function () {
|
|
|
this.checked = this.checked ? 1 : 0;
|
|
|
- Cookies.set("show-nvs", this.checked?'Y':'N');
|
|
|
+ Cookies.set("show-nvs", this.checked ? 'Y' : 'N');
|
|
|
handleNVSVisible();
|
|
|
});
|
|
|
$('#btn_reboot_recovery').on('click', function () {
|
|
@@ -1048,7 +1237,7 @@ $(document).ready(function () {
|
|
|
saveAutoexec1(true);
|
|
|
});
|
|
|
$('#btn_disconnect').on('click', function () {
|
|
|
- ConnectedTo={};
|
|
|
+ ConnectedTo = {};
|
|
|
refreshAPHTML2();
|
|
|
$.ajax({
|
|
|
url: '/connect.json',
|
|
@@ -1303,15 +1492,15 @@ window.setURL = function (button) {
|
|
|
|
|
|
function rssiToIcon(rssi) {
|
|
|
if (rssi >= -55) {
|
|
|
- return {'label':'****','icon':`signal_wifi_statusbar_4_bar`};
|
|
|
+ return { 'label': '****', 'icon': `signal_wifi_statusbar_4_bar` };
|
|
|
} else if (rssi >= -60) {
|
|
|
- return {'label':'***','icon':`network_wifi_3_bar`};
|
|
|
+ return { 'label': '***', 'icon': `network_wifi_3_bar` };
|
|
|
} else if (rssi >= -65) {
|
|
|
- return {'label':'**','icon':`network_wifi_2_bar`};
|
|
|
+ return { 'label': '**', 'icon': `network_wifi_2_bar` };
|
|
|
} else if (rssi >= -70) {
|
|
|
- return {'label':'*','icon':`network_wifi_1_bar`};
|
|
|
+ return { 'label': '*', 'icon': `network_wifi_1_bar` };
|
|
|
} else {
|
|
|
- return {'label':'.','icon':`signal_wifi_statusbar_null`};
|
|
|
+ return { 'label': '.', 'icon': `signal_wifi_statusbar_null` };
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1339,9 +1528,9 @@ function refreshAP() {
|
|
|
});
|
|
|
}
|
|
|
function formatAP(ssid, rssi, auth) {
|
|
|
- const rssi_icon=rssiToIcon(rssi);
|
|
|
- const auth_icon={label:auth == 0 ? '🔓' : '🔒',icon:auth == 0 ? 'no_encryption' : 'lock'};
|
|
|
-
|
|
|
+ const rssi_icon = rssiToIcon(rssi);
|
|
|
+ const auth_icon = { label: auth == 0 ? '🔓' : '🔒', icon: auth == 0 ? 'no_encryption' : 'lock' };
|
|
|
+
|
|
|
return `<tr data-bs-toggle="modal" data-bs-target="#WifiConnectDialog"><td></td><td>${ssid}</td><td>
|
|
|
<span class="material-icons" style="fill:white; display: inline" aria-label="${rssi_icon.label}" icon="${rssi_icon.icon}" >${getIcon(rssi_icon)}</span>
|
|
|
</td><td>
|
|
@@ -1512,9 +1701,9 @@ function getMessages() {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- setTimeout(getMessages,messageInterval);
|
|
|
+ setTimeout(getMessages, messageInterval);
|
|
|
}).fail(function (xhr, ajaxOptions, thrownError) {
|
|
|
-
|
|
|
+
|
|
|
if (xhr.status == 404) {
|
|
|
$('.orec').hide(); // system commands won't be available either
|
|
|
messagesHeld = true;
|
|
@@ -1522,15 +1711,15 @@ function getMessages() {
|
|
|
else {
|
|
|
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
|
|
}
|
|
|
- if(xhr.status == 0 && xhr.readyState ==0){
|
|
|
+ if (xhr.status == 0 && xhr.readyState == 0) {
|
|
|
// probably a timeout. Target is rebooting?
|
|
|
- setTimeout(getMessages,messageInterval*2); // increase duration if a failure happens
|
|
|
+ setTimeout(getMessages, messageInterval * 2); // increase duration if a failure happens
|
|
|
}
|
|
|
- else if(!messagesHeld){
|
|
|
+ else if (!messagesHeld) {
|
|
|
// 404 here means we rebooted to an old recovery
|
|
|
- setTimeout(getMessages,messageInterval); // increase duration if a failure happens
|
|
|
+ setTimeout(getMessages, messageInterval); // increase duration if a failure happens
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
);
|
|
|
|
|
@@ -1552,18 +1741,18 @@ function handleRecoveryMode(data) {
|
|
|
$('#boot-button').html('Reboot');
|
|
|
$('#boot-form').attr('action', '/reboot_ota.json');
|
|
|
} else {
|
|
|
- if(!recovery && messagesHeld){
|
|
|
- messagesHeld=false;
|
|
|
- setTimeout(getMessages,messageInterval); // increase duration if a failure happens
|
|
|
+ if (!recovery && messagesHeld) {
|
|
|
+ messagesHeld = false;
|
|
|
+ setTimeout(getMessages, messageInterval); // increase duration if a failure happens
|
|
|
}
|
|
|
recovery = false;
|
|
|
-
|
|
|
+
|
|
|
$('.recovery_element').hide();
|
|
|
$('.ota_element').show();
|
|
|
$('#boot-button').html('Recovery');
|
|
|
$('#boot-form').attr('action', '/recovery.json');
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
|
|
|
function hasConnectionChanged(data) {
|
|
@@ -1645,9 +1834,9 @@ function handleWifiDialog(data) {
|
|
|
|
|
|
}
|
|
|
}
|
|
|
-function setIcons(offline){
|
|
|
+function setIcons(offline) {
|
|
|
$('.material-icons').each(function (_index, entry) {
|
|
|
- entry.textContent = entry.attributes[offline?'aria-label':'icon'].value;
|
|
|
+ entry.textContent = entry.attributes[offline ? 'aria-label' : 'icon'].value;
|
|
|
});
|
|
|
}
|
|
|
function handleNetworkStatus(data) {
|
|
@@ -1682,13 +1871,13 @@ function batteryToIcon(voltage) {
|
|
|
for (const iconEntry of batIcons) {
|
|
|
for (const entryRanges of iconEntry.ranges) {
|
|
|
if (inRange(voltage, entryRanges.f, entryRanges.t)) {
|
|
|
- return { label: iconEntry.label, icon:iconEntry.icon};
|
|
|
+ return { label: iconEntry.label, icon: iconEntry.icon };
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
- return {label:'▪▪▪▪',icon:"battery_full"};
|
|
|
+ return { label: '▪▪▪▪', icon: "battery_full" };
|
|
|
}
|
|
|
function checkStatus() {
|
|
|
$.ajaxSetup({
|
|
@@ -1700,6 +1889,16 @@ function checkStatus() {
|
|
|
handleNetworkStatus(data);
|
|
|
handlebtstate(data);
|
|
|
flashState.EventTargetStatus(data);
|
|
|
+ if(data.depth) {
|
|
|
+ depth = data.depth;
|
|
|
+ if(depth==16){
|
|
|
+ $('#cmd_opt_R').show();
|
|
|
+ }
|
|
|
+ else{
|
|
|
+ $('#cmd_opt_R').hide();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
if (data.project_name && data.project_name !== '') {
|
|
|
project_name = data.project_name;
|
|
@@ -1717,10 +1916,10 @@ function checkStatus() {
|
|
|
$('span#flash-status').html('');
|
|
|
}
|
|
|
if (data.Voltage) {
|
|
|
- const bat_icon=batteryToIcon(data.Voltage);
|
|
|
+ const bat_icon = batteryToIcon(data.Voltage);
|
|
|
$('#battery').html(`${getIcon(bat_icon)}`);
|
|
|
- $('#battery').attr("aria-label",bat_icon.label);
|
|
|
- $('#battery').attr("icon",bat_icon.icon);
|
|
|
+ $('#battery').attr("aria-label", bat_icon.label);
|
|
|
+ $('#battery').attr("icon", bat_icon.icon);
|
|
|
$('#battery').show();
|
|
|
} else {
|
|
|
$('#battery').hide();
|
|
@@ -1757,15 +1956,15 @@ function checkStatus() {
|
|
|
});
|
|
|
}
|
|
|
$('#o_jack').css({ display: Number(data.Jack) ? 'inline' : 'none' });
|
|
|
- setTimeout(checkStatus,statusInterval);
|
|
|
+ setTimeout(checkStatus, statusInterval);
|
|
|
}).fail(function (xhr, ajaxOptions, thrownError) {
|
|
|
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
|
|
- if(xhr.status == 0 && xhr.readyState ==0){
|
|
|
+ if (xhr.status == 0 && xhr.readyState == 0) {
|
|
|
// probably a timeout. Target is rebooting?
|
|
|
- setTimeout(checkStatus,messageInterval*2); // increase duration if a failure happens
|
|
|
+ setTimeout(checkStatus, messageInterval * 2); // increase duration if a failure happens
|
|
|
}
|
|
|
else {
|
|
|
- setTimeout(checkStatus,messageInterval); // increase duration if a failure happens
|
|
|
+ setTimeout(checkStatus, messageInterval); // increase duration if a failure happens
|
|
|
}
|
|
|
});
|
|
|
}
|
|
@@ -1995,6 +2194,7 @@ function getConfig() {
|
|
|
$('#nvsTable tr').remove();
|
|
|
const data = (entries.config ? entries.config : entries);
|
|
|
SystemConfig = data;
|
|
|
+ commandBTSinkName = '';
|
|
|
Object.keys(data)
|
|
|
.sort()
|
|
|
.forEach(function (key) {
|
|
@@ -2006,20 +2206,15 @@ function getConfig() {
|
|
|
$('#disable-squeezelite')[0].checked = false;
|
|
|
}
|
|
|
} else if (key === 'autoexec1') {
|
|
|
- const re = /-o\s?(["][^"]*["]|[^-]+)/g;
|
|
|
- const m = re.exec(val);
|
|
|
- if (m[1].toUpperCase().startsWith('I2S')) {
|
|
|
- handleTemplateTypeRadio('i2s');
|
|
|
- } else if (m[1].toUpperCase().startsWith('SPDIF')) {
|
|
|
- handleTemplateTypeRadio('spdif');
|
|
|
- } else if (m[1].toUpperCase().startsWith('"BT')) {
|
|
|
- handleTemplateTypeRadio('bt');
|
|
|
- }
|
|
|
+ /* call new function to parse the squeezelite options */
|
|
|
+ processSqueezeliteCommandLine(val);
|
|
|
} else if (key === 'host_name') {
|
|
|
val = val.replaceAll('"', '');
|
|
|
$('input#dhcp-name1').val(val);
|
|
|
$('input#dhcp-name2').val(val);
|
|
|
- $('#player').val(val);
|
|
|
+ if ($('#cmd_opt_n').length == 0) {
|
|
|
+ $('#cmd_opt_n').val(val);
|
|
|
+ }
|
|
|
document.title = val;
|
|
|
hostName = val;
|
|
|
} else if (key === 'rel_api') {
|
|
@@ -2054,6 +2249,10 @@ function getConfig() {
|
|
|
);
|
|
|
$('input#' + key).val(data[key].value);
|
|
|
});
|
|
|
+ if(commandBTSinkName.length > 0) {
|
|
|
+ // persist the sink name found in the autoexec1 command line
|
|
|
+ $('#cfg-audio-bt_source-sink_name').val(commandBTSinkName);
|
|
|
+ }
|
|
|
$('tbody#nvsTable').append(
|
|
|
"<tr><td><input type='text' class='form-control' id='nvs-new-key' placeholder='new key'></td><td><input type='text' class='form-control' id='nvs-new-value' placeholder='new value' nvs_type=33 ></td></tr>"
|
|
|
);
|
|
@@ -2083,6 +2282,40 @@ function getConfig() {
|
|
|
handleExceptionResponse(xhr, ajaxOptions, thrownError);
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+function processSqueezeliteCommandLine(val) {
|
|
|
+ const parsed = parseSqueezeliteCommandLine(val);
|
|
|
+ if (parsed.output.toUpperCase().startsWith('I2S')) {
|
|
|
+ handleTemplateTypeRadio('i2s');
|
|
|
+ } else if (parsed.output.toUpperCase().startsWith('SPDIF')) {
|
|
|
+ handleTemplateTypeRadio('spdif');
|
|
|
+ } else if (parsed.output.toUpperCase().startsWith('BT')) {
|
|
|
+ if(parsed.otherOptions.btname){
|
|
|
+ commandBTSinkName= parsed.otherOptions.btname;
|
|
|
+ }
|
|
|
+ handleTemplateTypeRadio('bt');
|
|
|
+ }
|
|
|
+ Object.keys(parsed.options).forEach(function (key) {
|
|
|
+ const option = parsed.options[key];
|
|
|
+ if (!$(`#cmd_opt_${key}`).hasOwnProperty('checked')) {
|
|
|
+ $(`#cmd_opt_${key}`).val(option);
|
|
|
+ } else {
|
|
|
+ $(`#cmd_opt_${key}`)[0].checked = option;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (parsed.options.hasOwnProperty('u')) {
|
|
|
+ // parse -u v[:i] and check the appropriate radio button with id #resample_v
|
|
|
+ const [resampleValue, resampleInterpolation] = parsed.options.u.split(':');
|
|
|
+ $(`#resample_${resampleValue}`).prop('checked', true);
|
|
|
+ // if resampleinterpolation is set, check resample_i checkbox
|
|
|
+ if (resampleInterpolation) {
|
|
|
+ $('#resample_i').prop('checked', true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
function showLocalMessage(message, severity) {
|
|
|
const msg = {
|
|
|
message: message,
|