Merging HTML/CSS/JS stuff.
This commit is contained in:
parent
5c67fdf12e
commit
d9e294a378
|
|
@ -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: "♫ ";
|
||||
}
|
||||
|
||||
.rds-container .rds-radiotext-plus .rds-rtplus-programme:not(:empty):before {
|
||||
content: "📅 ";
|
||||
}
|
||||
|
||||
.rds-container .rds-radiotext-plus ul.rds-rtplus-news {
|
||||
list-style-type: "📰 ";
|
||||
padding-left: 1.5lh;
|
||||
}
|
||||
|
||||
.rds-container .rds-radiotext-plus .rds-rtplus-weather:not(:empty):before {
|
||||
content: "⛅ ";
|
||||
}
|
||||
|
||||
.rds-container .rds-radiotext-plus .rds-rtplus-homepage:not(:empty):before {
|
||||
content: "🔗 ";
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -57,7 +57,3 @@ ${header}
|
|||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Reference in New Issue