Merging HTML/CSS/JS stuff.

This commit is contained in:
Marat Fayzullin 2024-01-30 19:39:40 -05:00
parent 5c67fdf12e
commit d9e294a378
8 changed files with 406 additions and 48 deletions

View File

@ -4,7 +4,7 @@
an open-source SDR receiver software with a web UI.
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
Copyright (c) 2019-2021 by Jakob Ketterl <dd5jfk@darc.de>
Copyright (c) 2022-2023 by Marat Fayzullin <luarvique@gmail.com>
Copyright (c) 2022-2024 by Marat Fayzullin <luarvique@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@ -1648,43 +1648,6 @@ img.openwebrx-mirror-img
height: 27px;
}
@keyframes openwebrx-record-animation {
0% { background: #ff0000; color: white; }
50% { background: #800000; color: white; }
100% { background: #ff0000; color: white; }
}
.openwebrx-record-button {
color: #ff8080;
float: right;
margin-top: 13px;
animation-duration: 1s;
animation-iteration-count: infinite;
}
@keyframes openwebrx-scan-animation {
0% { background: #00ff00; color: white; }
50% { background: #008000; color: white; }
100% { background: #00ff00; color: white; }
}
.openwebrx-squelch-auto {
animation-duration: 1s;
animation-iteration-count: infinite;
}
.openwebrx-squelch-auto .scanner {
display: none;
}
.openwebrx-squelch-auto.highlighted .scanner {
display: initial;
}
.openwebrx-squelch-auto.highlighted .squelch {
display: none;
}
.openwebrx-slider-button svg {
position:relative;
top: 1px;
@ -1730,6 +1693,123 @@ img.openwebrx-mirror-img
flex: 0 0 auto;
}
#openwebrx-panel-metadata-wfm {
width: 300px;
max-height: 300px;
}
.rds-container {
width: 100%;
text-align: center;
overflow: hidden auto;
}
.rds-container > *, .rds-radiotext-plus > * {
margin: 2px 0;
}
.rds-container .rds-stationname {
font-family: roboto-mono;
font-size: 18pt;
padding: 10px 0;
}
.rds-container .rds-stationname,
.rds-container .rds-identifier,
.rds-container .rds-prog_type {
min-height: 1lh;
}
.rds-container .rds-radiotext-plus .rds-rtplus-item:not(:empty):before {
content: "&#9835; ";
}
.rds-container .rds-radiotext-plus .rds-rtplus-programme:not(:empty):before {
content: "&#128197; ";
}
.rds-container .rds-radiotext-plus ul.rds-rtplus-news {
list-style-type: "&#128240; ";
padding-left: 1.5lh;
}
.rds-container .rds-radiotext-plus .rds-rtplus-weather:not(:empty):before {
content: "&#9925; ";
}
.rds-container .rds-radiotext-plus .rds-rtplus-homepage:not(:empty):before {
content: "&#128279; ";
}
#openwebrx-panel-metadata-dab {
width: 300px;
}
#openwebrx-panel-metadata-dab .dab-container {
width: 100%;
}
.dab-container > * {
margin: 2px 0;
text-align: center;
overflow: hidden auto;
}
.dab-container label {
display: block;
margin: 5px 0;
}
.dab-container select#dab-service-id {
width: 100%;
padding: 3px;
}
.dab-container .dab-ensemble-id:not(:empty):before {
content: "Ensemble ID: ";
}
.dab-container .dab-ensemble-label:not(:empty):before {
content: "Ensemble: ";
}
@keyframes openwebrx-record-animation {
0% { background: #ff0000; color: white; }
50% { background: #800000; color: white; }
100% { background: #ff0000; color: white; }
}
.openwebrx-record-button {
color: #ff8080;
float: right;
margin-top: 13px;
animation-duration: 1s;
animation-iteration-count: infinite;
}
@keyframes openwebrx-scan-animation {
0% { background: #00ff00; color: white; }
50% { background: #008000; color: white; }
100% { background: #00ff00; color: white; }
}
.openwebrx-squelch-auto {
animation-duration: 1s;
animation-iteration-count: infinite;
}
.openwebrx-squelch-auto .scanner {
display: none;
}
.openwebrx-squelch-auto.highlighted .scanner {
display: initial;
}
.openwebrx-squelch-auto.highlighted .squelch {
display: none;
}
.openwebrx-spectrum-container {
transition-property: height, opacity;
transition-duration: 1s;
@ -1773,3 +1853,4 @@ img.openwebrx-mirror-img
.openwebrx-section.closed {
max-height: 0;
}

View File

@ -4,8 +4,8 @@
This file is part of OpenWebRX,
an open-source SDR receiver software with a web UI.
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
Copyright (c) 2019-2021 by Jakob Ketterl <dd5jfk@darc.de>
Copyright (c) 2022-2023 by Marat Fayzullin <luarvique@gmail.com>
Copyright (c) 2019-2024 by Jakob Ketterl <dd5jfk@darc.de>
Copyright (c) 2022-2024 by Marat Fayzullin <luarvique@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
@ -164,6 +164,8 @@
</div>
</div>
</div>
<div class="openwebrx-panel openwebrx-meta-panel disabled" id="openwebrx-panel-metadata-wfm" style="display: none;" data-panel-name="metadata-wfm"></div>
<div class="openwebrx-panel openwebrx-meta-panel" id="openwebrx-panel-metadata-dab" style="display: none;" data-panel-name="metadata-dab"></div>
<div class="openwebrx-panel" id="openwebrx-panel-log" data-panel-name="debug" style="width: 92%; max-width: 619px;">
<div style="position: relative; height: 100%">
<div class="openwebrx-panel-inner nano" id="openwebrx-log-scroll">

View File

@ -6,10 +6,10 @@ AprsMarker.prototype.isFacingEast = function(symbol) {
var candidates = ''
if (symbol.table === '/') {
// primary table
candidates = '(*<=>CFPUXYabefghjkpsuv[';
candidates = '(*<=>CFPUXYZabefgjkpsuv[';
} else {
// alternate table
candidates = 'hkluv';
candidates = '(T`efhjktuvw';
}
return candidates.includes(symbol.symbol);
};

View File

@ -15,6 +15,10 @@ Filter.prototype.getLimits = function() {
max_bw = 50000;
} else if (this.demodulator.get_modulation() === "freedv") {
max_bw = 4000;
} else if (this.demodulator.get_modulation() === "dab") {
max_bw = 1000000;
} else if (this.demodulator.get_secondary_demod() === "ism") {
max_bw = 600000;
} else {
max_bw = (audioEngine.getOutputRate() / 2) - 1;
}
@ -218,6 +222,7 @@ function Demodulator(offset_frequency, modulation) {
this.filter = new Filter(this);
this.squelch_level = -150;
this.dmr_filter = 3;
this.dab_service_id = 0;
this.started = false;
this.state = {};
this.secondary_demod = false;
@ -307,6 +312,7 @@ Demodulator.prototype.set = function () { //this function sends demodulator par
"offset_freq": this.offset_frequency,
"mod": this.modulation,
"dmr_filter": this.dmr_filter,
"dab_service_id": this.dab_service_id,
"squelch_level": this.squelch_level,
"secondary_mod": this.secondary_demod,
"secondary_offset_freq": this.secondary_offset_freq
@ -344,6 +350,11 @@ Demodulator.prototype.setDmrFilter = function(dmr_filter) {
this.set();
};
Demodulator.prototype.setDabServiceId = function(dab_service_id) {
this.dab_service_id = dab_service_id;
this.set();
}
Demodulator.prototype.setBandpass = function(bandpass) {
this.bandpass = bandpass;
this.low_cut = bandpass.low_cut;

View File

@ -181,7 +181,7 @@ DemodulatorPanel.prototype.updatePanels = function() {
var showing = 'openwebrx-panel-metadata-' + modulation;
var metaPanels = $(".openwebrx-meta-panel");
metaPanels.each(function (_, p) {
toggle_panel(p.id, p.id === showing);
toggle_panel(p.id, p.id === showing && !p.classList.contains('disabled'));
});
metaPanels.metaPanel().each(function() {
this.clear();

View File

@ -359,12 +359,280 @@ M17MetaPanel.prototype.clear = function() {
this.setDestination();
};
function WfmMetaPanel(el) {
MetaPanel.call(this, el);
this.modes = ['WFM'];
this.enabled = false;
this.timeout = false;
this.clear();
}
WfmMetaPanel.prototype = new MetaPanel();
WfmMetaPanel.prototype.update = function(data) {
if (!this.isSupported(data)) return;
var me = this;
// automatically clear metadata panel when no RDS data is received for more than ten seconds
if (this.timeout) clearTimeout(this.timeout);
this.timeout = setTimeout(function(){
me.clear();
}, 10000);
if ('pi' in data && data.pi !== this.pi) {
this.clear();
this.pi = data.pi;
}
var $el = $(this.el);
if ('ps' in data) {
this.ps = data.ps;
}
if ('prog_type' in data) {
$el.find('.rds-prog_type').text(data['prog_type']);
}
if ('callsign' in data) {
this.callsign = data.callsign;
}
if ('pi' in data) {
this.pi = data.pi
}
if ('clock_time' in data) {
var date = new Date(Date.parse(data.clock_time));
$el.find('.rds-clock').text(date.toLocaleString([], {dateStyle: 'short', timeStyle: 'short'}));
}
if ('radiotext_plus' in data) {
// prefer displaying radiotext plus over radiotext
this.radiotext_plus = this.radiotext_plus || {
item_toggle: -1,
news: []
};
var tags = {};
if ('tags' in data.radiotext_plus) {
tags = Object.fromEntries(data.radiotext_plus.tags.map(function (tag) {
return [tag['content-type'], tag['data']]
}));
}
if (data.radiotext_plus.item_toggle !== this.radiotext_plus.item_toggle) {
this.radiotext_plus.item_toggle = data.radiotext_plus.item_toggle;
this.radiotext_plus.item = '';
}
this.radiotext_plus.item_running = !!data.radiotext_plus.item_running;
if ('item.artist' in tags && 'item.title' in tags) {
this.radiotext_plus.item = tags['item.artist'] + ' - ' + tags['item.title'];
} else {
var items = Object.entries(tags).filter(function (e) {
return e[0].startsWith("item.")
})
if (items.length) {
this.radiotext_plus.item = items.map(function (e) {
return e[0].substr(5, 1).toUpperCase() + e[0].substr(6) + ': ' + e[1];
}).join('; ');
}
}
if ('programme.now' in tags) {
this.radiotext_plus.programme = tags['programme.now'];
}
if ('programme.homepage' in tags) {
this.radiotext_plus.homepage = tags['programme.homepage'];
}
if ('stationname.long' in tags) {
this.long_stationname = tags['stationname.long'];
}
if ('stationname.short' in tags) {
this.short_stationname = tags['stationname.short'];
}
if ('info.news' in tags) {
var n = tags['info.news'];
var i = this.radiotext_plus.news.indexOf(n);
if (i >= 0) {
this.radiotext_plus.news.splice(i, 1);
}
this.radiotext_plus.news.push(n);
// limit the number of items
this.radiotext_plus.news = this.radiotext_plus.news.slice(-5);
}
if ('info.weather' in tags) {
this.radiotext_plus.weather = tags['info.weather'];
}
}
if ('radiotext' in data && !this.radiotext_plus) {
this.radiotext = data.radiotext;
}
if (this.radiotext_plus) {
$el.find('.rds-radiotext').empty();
if (this.radiotext_plus.item_running) {
$el.find('.rds-rtplus-item').text(this.radiotext_plus.item || '');
} else {
$el.find('.rds-rtplus-item').empty();
}
$el.find('.rds-rtplus-programme').text(this.radiotext_plus.programme || '');
$el.find('.rds-rtplus-news').empty().html(this.radiotext_plus.news.map(function(n){
return $('<li>').text(n);
}));
$el.find('.rds-rtplus-weather').text(this.radiotext_plus.weather || '');
if (this.radiotext_plus.homepage) {
var url = this.radiotext_plus.homepage;
// prefix with a protcol if not present. we'll assume https, should be generally available these days.
if (url.indexOf('://') < 0) url = 'https://' + url;
// avoid updating the link if not necessary since that would prevent the user from clicking it
if ($el.find('.rds-rtplus-homepage a').attr('href') !== url) {
var link = $('<a href="' + url + '" target="_blank"></a>').text(this.radiotext_plus.homepage);
$el.find('.rds-rtplus-homepage').html(link);
}
}
} else {
$el.find('.rds-radiotext-plus .autoclear').empty();
$el.find('.rds-radiotext').text(this.radiotext || '');
}
$el.find('.rds-stationname').text(this.long_stationname || this.ps);
$el.find('.rds-identifier').text(this.short_stationname || this.callsign || this.pi);
};
WfmMetaPanel.prototype.isSupported = function(data) {
return this.modes.includes(data.mode);
};
WfmMetaPanel.prototype.setEnabled = function(enabled) {
if (enabled === this.enabled) return;
this.enabled = enabled;
if (enabled) {
$(this.el).removeClass('disabled').html(
'<div class="rds-container">' +
'<div class="rds-identifier rds-autoclear"></div>' +
'<div class="rds-stationname rds-autoclear"></div>' +
'<div class="rds-radiotext rds-autoclear"></div>' +
'<div class="rds-radiotext-plus">' +
'<div class="rds-rtplus-programme rds-autoclear"></div>' +
'<div class="rds-rtplus-item rds-autoclear"></div>' +
'<ul class="rds-rtplus-news rds-autoclear"></ul>' +
'<div class="rds-rtplus-weather rds-autoclear"></div>' +
'<div class="rds-rtplus-homepage rds-autoclear"></div>' +
'</div>' +
'<div class="rds-prog_type rds-autoclear"></div>' +
'<div class="rds-clock rds-autoclear"></div>' +
'</div>'
);
} else {
$(this.el).addClass('disabled').emtpy()
}
};
WfmMetaPanel.prototype.clear = function() {
$(this.el).find('.rds-autoclear').empty();
this.pi = '';
this.ps = '';
this.callsign = '';
this.long_stationname = '';
this.short_stationname = '';
this.radiotext = '';
this.radiotext_plus = false;
};
function DabMetaPanel(el) {
MetaPanel.call(this, el);
var me = this;
this.modes = ['DAB'];
this.service_id = 0;
this.$select = $('<select id="dab-service-id"></select>');
this.$select.on("change", function() {
me.service_id = parseInt($(this).val());
$('#openwebrx-panel-receiver').demodulatorPanel().getDemodulator().setDabServiceId(me.service_id);
});
var $container = $(
'<div class="dab-container">' +
'<div class="dab-auto-clear dab-ensemble-id"></div>' +
'<div class="dab-auto-clear dab-ensemble-label"></div>' +
'<div class="dab-auto-clear dab-timestamp"></div>' +
'<label for="dab-service-id">DAB Programme:</label>' +
'</div>'
);
$container.append(this.$select);
$(this.el).append($container);
this.clear();
this.programmeTimeout = false;
}
DabMetaPanel.prototype = new MetaPanel();
DabMetaPanel.prototype.isSupported = function(data) {
return this.modes.includes(data.mode);
}
DabMetaPanel.prototype.update = function(data) {
if (!this.isSupported(data)) return;
if ('ensemble_id' in data) {
$(this.el).find('.dab-ensemble-id').text('0x' + data.ensemble_id.toString(16));
}
if ('ensemble_label' in data) {
$(this.el).find('.dab-ensemble-label').text(data.ensemble_label);
}
if ('timestamp' in data) {
var date = new Date(data.timestamp * 1000);
$(this.el).find('.dab-timestamp').text(date.toLocaleString([], {dateStyle: 'short', timeStyle: 'medium'}));
}
if ('programmes' in data) {
var options = Object.entries(data.programmes).map(function(e) {
return '<option value="' + e[0] + '">' + e[1] + '</option>';
});
this.$select.html(
options.join('') +
'<option value="" disabled selected hidden>Loading...</option>'
);
var me = this;
if (this.programmeTimeout) clearTimeout(this.programmeTimeout);
this.programmeTimeout = setTimeout(function() {
// user has selected a programme to play. don't interfere.
me.$select.val(this.service_id);
if (me.$select.val()) return;
me.$select.val(me.$select.find('option:first').val()).change();
}, 1000);
}
}
DabMetaPanel.prototype.clear = function() {
this.service_id = 0;
$(this.el).find('.dab-auto-clear').empty();
this.$select.html(
'<option value="" disabled selected hidden>Loading...</option>'
);
}
MetaPanel.types = {
dmr: DmrMetaPanel,
ysf: YsfMetaPanel,
dstar: DStarMetaPanel,
nxdn: NxdnMetaPanel,
m17: M17MetaPanel,
wfm: WfmMetaPanel,
dab: DabMetaPanel,
};
$.fn.metaPanel = function() {

View File

@ -4,7 +4,7 @@
an open-source SDR receiver software with a web UI.
Copyright (c) 2013-2015 by Andras Retzler <randras@sdr.hu>
Copyright (c) 2019-2021 by Jakob Ketterl <dd5jfk@darc.de>
Copyright (c) 2022-2023 by Marat Fayzullin <luarvique@gmail.com>
Copyright (c) 2022-2024 by Marat Fayzullin <luarvique@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as

View File

@ -57,7 +57,3 @@ ${header}
</div>
</div>
</body>
</div>
</body>